From a1ae3a2b8b569f4ae4a4f8625662367eee050606 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 14 Apr 2018 12:49:45 +0100 Subject: [PATCH 01/68] Update version number --- src/main/java/electroblob/wizardry/Wizardry.java | 2 +- src/main/resources/mcmod.info | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index 576450c9..305bcff8 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -48,7 +48,7 @@ public class Wizardry { * 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft * 1.11.x versions, and so on. */ - public static final String VERSION = "4.1.0"; + public static final String VERSION = "4.2.0"; // IDEA: Improve the algorithm that finds a place to summon creatures to take walls into account. // IDEA: Replace all uses of Math.cos and Math.sin with MathHelper versions diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index c64df350..0d2decc3 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -2,7 +2,7 @@ { "modid" : "ebwizardry", "name" : "Electroblob's Wizardry", - "version" : "4.1.0", + "version" : "4.2.0", "url" : "https://minecraft.curseforge.com/projects/electroblobs-wizardry", "credits" : "Designed, coded and textured by Electroblob. Code contributed to 1.11 and 1.12 updates by Corail31 and 12foo. Translators: MadWrist (Spanish, Mexican Spanish), VilagVil (Russian).", "authors" : [ From f5730bf9455b4fd8c0b692c409d923ec95bfdb33 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 14 Apr 2018 12:51:18 +0100 Subject: [PATCH 02/68] Replace crossed quads arc renderer with new 3D box-based rendering --- .../wizardry/client/renderer/RenderArc.java | 210 +++++++++++------- .../wizardry/entity/EntityArc.java | 13 +- 2 files changed, 141 insertions(+), 82 deletions(-) diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderArc.java b/src/main/java/electroblob/wizardry/client/renderer/RenderArc.java index 1e59d927..d390acc0 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderArc.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderArc.java @@ -1,8 +1,9 @@ package electroblob.wizardry.client.renderer; +import java.util.Random; + import org.lwjgl.opengl.GL11; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.EntityArc; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; @@ -15,119 +16,172 @@ import net.minecraft.util.ResourceLocation; public class RenderArc extends Render { - private static final ResourceLocation[] textures = new ResourceLocation[16]; - public RenderArc(RenderManager renderManager){ super(renderManager); - for(int i = 0; i < 16; i++){ - textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/arc_" + i + ".png"); - } } @Override - public void doRender(EntityArc arc, double d0, double d1, double d2, float fa, float fb){ + public void doRender(EntityArc arc, double x, double y, double z, float viewPitch, float viewYaw) { + GlStateManager.pushMatrix(); - GlStateManager.translate((float)d0, (float)d1, (float)d2); + GlStateManager.translate(x, y, z); GlStateManager.disableLighting(); GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); // This line fixes the weird - // brightness bug. + GlStateManager.disableTexture2D(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); - // System.out.println("Entity coords: " + entity.posX + ", " + entity.posY + ", " + entity.posZ); - // System.out.println("doRender parameters: " + d0 + ", " + d1 + ", " + d2 + ", " + fa + ", " + fb); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - bindTexture(textures[arc.textureIndex]); // This MUST be after the tessellator declaration and the gl stuff - - /** - * Note: A lot of the maths here works on similar triangles and the ratios between them, avoiding too much + /* 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. - */ + * Ratios are usually used swapping x and z because the triangles are rotated through 90 degrees. */ - double dx = -d0; - double dy = -d1; - double dz = -d2; + double dx = -x; + double dy = -y; + double dz = -z; if(arc.x1 != 0){ - dx = arc.x1 - arc.posX;// - d2/lengthOffsetRatio; - dy = arc.y1 - arc.posY + 0.3; - dz = arc.z1 - arc.posZ;// + d0/lengthOffsetRatio; - // The distance from caster to target - double arcLength = Math.sqrt(dz * dz + dx * dx); + dx = arc.x1 - arc.posX; + dy = arc.y1 - arc.posY; + dz = arc.z1 - arc.posZ; - // The ratio between the length of the arc and the offset of the start point from the player's centre (which - // is always 0.3). - // double lengthOffsetRatio = arcLength/0.3; + // The distance from origin to endpoint + double arcLength = Math.sqrt(dx*dx+dy*dy+dz*dz); - // EntityClientPlayerMP player = Minecraft.getMinecraft().player; + GL11.glTranslated(dx, dy, dz); - // double xViewDist = player.posX - d0; - // double yViewDist = player.posY + player.eyeHeight - d1; - // double zViewDist = player.posZ - d2; + // 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))); - // double xzViewDist = Math.sqrt(xViewDist * xViewDist + zViewDist * zViewDist); + GL11.glRotatef(yaw, 0, 1, 0); + GL11.glRotatef(pitch, 1, 0, 0); - // The angle above the horizontal that this particular player is viewing the arc from - // double viewAngle = Math.atan(yViewDist/xzViewDist); + // 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. - // Half the width of the arc - double arcWidth = 0.3d; + boolean freeEnd = arc.freeEnd; - // Right hand side of vertical plane - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - // Target end - buffer.pos(0, -0.5, 0).tex(1, 1).endVertex(); - buffer.pos(0, 0.5, 0).tex(1, 0).endVertex(); - // Caster end - buffer.pos(dx, dy, dz).tex(0, 0).endVertex(); - buffer.pos(dx, dy - 1, dz).tex(0, 1).endVertex(); - tessellator.draw(); + // == 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 - // Left - buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); - // Target end - buffer.pos(0, -0.5, 0).tex(1, 1).endVertex(); - // Caster end - buffer.pos(dx, dy - 1, dz).tex(0, 1).endVertex(); - buffer.pos(dx, dy, dz).tex(0, 0).endVertex(); - // Target end - buffer.pos(0, 0.5, 0).tex(1, 0).endVertex(); - tessellator.draw(); + int numberOfSegments = (int)Math.round(arcLength/maxSegmentLength); // Number of segments - // Bottom of horizontal plane - buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); - buffer.pos((arcWidth / arcLength) * dz, 0, (-arcWidth / arcLength) * dx).tex(1, 1).endVertex(); - buffer.pos(dx + (arcWidth / arcLength) * dz, dy - 0.5, dz - (arcWidth / arcLength) * dx).tex(0, 1) - .endVertex(); - buffer.pos(dx - (arcWidth / arcLength) * dz, dy - 0.5, dz + (arcWidth / arcLength) * dx).tex(0, 0) - .endVertex(); - buffer.pos((-arcWidth / arcLength) * dz, 0, (arcWidth / arcLength) * dx).tex(1, 0).endVertex(); - tessellator.draw(); + for(int layer=0; layer<3; layer++){ - // Top - buffer.begin(GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); - buffer.pos((arcWidth / arcLength) * dz, 0, (-arcWidth / arcLength) * dx).tex(1, 1).endVertex(); - buffer.pos((-arcWidth / arcLength) * dz, 0, (arcWidth / arcLength) * dx).tex(1, 0).endVertex(); - buffer.pos(dx - (arcWidth / arcLength) * dz, dy - 0.5, dz + (arcWidth / arcLength) * dx).tex(0, 0) - .endVertex(); - buffer.pos(dx + (arcWidth / arcLength) * dz, dy - 0.5, dz - (arcWidth / arcLength) * dx).tex(0, 1) - .endVertex(); - tessellator.draw(); + 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 Date: Wed, 2 May 2018 13:03:14 +0100 Subject: [PATCH 03/68] Fix incorrect event handler annotation --- src/main/java/electroblob/wizardry/Wizardry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index 305bcff8..99f2766f 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -188,7 +188,7 @@ public class Wizardry { // 2.1 changed some item ids, so this fixes them for existing worlds // Nobody updates minecraft versions when using mods, but I may as well leave this here just in case. - @EventHandler + @SubscribeEvent public static void onMissingMappingEvent(RegistryEvent.MissingMappings event){ // Just get, not getAll, since the mod id didn't change! for(RegistryEvent.MissingMappings.Mapping mapping : event.getAllMappings()){ From df14912693c31e316cf06dbae4693c60cb2c3c62 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 2 May 2018 13:17:04 +0100 Subject: [PATCH 04/68] Add new files for the particle refactoring --- .../client/particle/ParticleBuff.java | 136 +++++++ .../client/particle/ParticleEntityLinked.java | 61 +++ .../client/particle/ParticleFlash.java | 44 ++ .../client/particle/ParticleMagicBubble.java | 39 ++ .../client/particle/ParticleWizardry.java | 94 +++++ .../wizardry/util/ParticleBuilder.java | 378 ++++++++++++++++++ .../ebwizardry/textures/particle/buff.png | Bin 0 -> 4714 bytes 7 files changed, 752 insertions(+) create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleMagicBubble.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java create mode 100644 src/main/java/electroblob/wizardry/util/ParticleBuilder.java create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/buff.png diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java new file mode 100644 index 00000000..b7ea5432 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java @@ -0,0 +1,136 @@ +package electroblob.wizardry.client.particle; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +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.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ParticleBuff extends ParticleEntityLinked { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/buff.png"); + private final boolean mirror; + + public ParticleBuff(World world, Entity entity, float r, float g, float b, boolean mirror){ + super(world, entity); + this.setRBGColorF(r, g, b); + this.mirror = mirror; + } + + public ParticleBuff(World world, Entity entity, int maxAge, float r, float g, float b, boolean mirror){ + super(world, entity, maxAge); + this.setRBGColorF(r, g, b); + this.mirror = mirror; + } + + @Override + public void init(){ + this.particleGravity = 0; + this.posY += 1; + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.setPosition(this.entity.posX, this.entity.posY + 1 + 4f * this.particleAge/this.particleMaxAge, this.entity.posZ); + if(this.particleAge > this.particleMaxAge/2) this.particleAlpha = 2f - 2f*(float)this.particleAge/(float)this.particleMaxAge; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, + float rotationYZ, float rotationXY, float rotationXZ){ + + GlStateManager.pushMatrix(); + GlStateManager.pushAttrib(); + + float scale = 0.6f; + GlStateManager.scale(scale, scale, scale); + if(mirror) GlStateManager.scale(-1, 1, 1); + + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.disableCull(); + GlStateManager.disableLighting(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + // Makes the particle colour add to the colour of the texture pixels, rather than the default multiplying + GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_ADD); + + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); + + // Does the texture translation wrapping thing (the cool stuff) + GlStateManager.matrixMode(GL11.GL_TEXTURE); + GlStateManager.loadIdentity(); + + GlStateManager.translate((this.particleAge + partialTicks)/(float)this.particleMaxAge * -2, 0, 0); + + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + + RenderHelper.disableStandardItemLighting(); + + Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE); + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); + + // 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); + + // Increases from 0 to 1 in steps of 0.125 evenly throughout the particle's lifetime + float f = 0.875f - 0.125f * MathHelper.floor((float)this.particleAge/(float)this.particleMaxAge * 8 - 0.000001f); + float g = f + 0.125f; + float hrepeat = 1; + float yScale = 0.7f; + + buffer.pos(x-1, y-yScale, z-1).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y+yScale, z-1).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+1, y-yScale, z-1).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+1, y+yScale, z-1).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+1, y-yScale, z+1).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+1, y+yScale, z+1).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y-yScale, z+1).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y+yScale, z+1).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y-yScale, z-1).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y+yScale, z-1).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + + Tessellator.getInstance().draw(); + + // Undoes the texture transformations + GlStateManager.matrixMode(GL11.GL_TEXTURE); + GlStateManager.loadIdentity(); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.enableCull(); + GlStateManager.enableLighting(); + // Reverses the colour addition change from before + GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE); + + GlStateManager.popAttrib(); + GlStateManager.popMatrix(); + + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java b/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java new file mode 100644 index 00000000..76dfaefb --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java @@ -0,0 +1,61 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.client.particle.Particle; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** + * Abstract superclass for particles that are linked to entities, i.e. move with a given entity. This is generally used + * for visual effects in spell casting. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +@SideOnly(Side.CLIENT) +public abstract class ParticleEntityLinked extends Particle { + + /** True if the particle always renders at full brightness. Defaults to false. */ + protected boolean fullBrightness = false; + + /** The entity this particle is linked to. The particle will move with this entity. */ + protected Entity entity; + + public ParticleEntityLinked(World world, Entity entity){ + super(world, entity.posX, entity.posY, entity.posZ, entity.motionX, entity.motionY, entity.motionZ); + this.entity = entity; + this.init(); + } + + public ParticleEntityLinked(World world, Entity entity, int maxAge){ + this(world, entity); + this.particleMaxAge = maxAge; + } + + /** + * Called from both constructors to set constants, avoiding duplicate code. Common fields to set here include: + * particleScale, particleGravity, canCollide, fullBrightness and setting the texture index. + */ + public abstract void init(); + + /* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png + * to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the + * render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine + * for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was + * presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning + * you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten + * anyway since they bind their own textures. It is of course important to bind the texture every time you render a + * custom particle, but I don't see how you could do it any other way, since you don't have access to + * EffectRenderer. */ + @Override + public int getFXLayer(){ + // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. + return 3; + } + + @Override + public int getBrightnessForRender(float partialTick){ + return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick); + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java new file mode 100644 index 00000000..82927b46 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java @@ -0,0 +1,44 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +/** + * Copied from ParticleFirework.Overlay; for some reason that class has no public constructors, plus I want to change the + * scale and a few other things + * @author Electroblob + * @since Wizardry 4.2.0 + */ +public class ParticleFlash extends ParticleWizardry { + + public ParticleFlash(World world, double x, double y, double z){ + super(world, x, y, z); + this.setRBGColorF(1, 1, 1); + this.particleScale = 7.1f; // 7.1f is the value used in fireworks + this.particleMaxAge = 4; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ + float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F) * 0.25F * (float)Math.PI); + this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F) * 0.25F * 0.5F); + float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); + float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); + float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); + int i = this.getBrightnessForRender(partialTicks); + int j = i >> 16 & 65535; + int k = i & 65535; + buffer.pos((double)(f5 - rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 - rotationYZ * f4 - rotationXZ * f4)).tex(0.5D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); + buffer.pos((double)(f5 - rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 - rotationYZ * f4 + rotationXZ * f4)).tex(0.5D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); + buffer.pos((double)(f5 + rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 + rotationYZ * f4 + rotationXZ * f4)).tex(0.25D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); + buffer.pos((double)(f5 + rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 + rotationYZ * f4 - rotationXZ * f4)).tex(0.25D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); + } + + @Override + public int getBrightnessForRender(float partialTicks){ + return 15728880; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleMagicBubble.java b/src/main/java/electroblob/wizardry/client/particle/ParticleMagicBubble.java new file mode 100644 index 00000000..59951ea5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleMagicBubble.java @@ -0,0 +1,39 @@ +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 ParticleMagicBubble extends ParticleWizardry { + + public ParticleMagicBubble(World world, double x, double y, double z){ + super(world, x, y, z); + this.particleRed = 1.0F; + this.particleGreen = 1.0F; + this.particleBlue = 1.0F; + this.setParticleTextureIndex(32); + this.setSize(0.02F, 0.02F); + this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F; +// this.motionX = par8 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); +// this.motionY = par10 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); +// this.motionZ = par12 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); + this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D)); + } + + @Override + public void onUpdate(){ + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + this.motionY += 0.002D; + this.move(this.motionX, this.motionY, this.motionZ); + this.motionX *= 0.8500000238418579D; + this.motionY *= 0.8500000238418579D; + this.motionZ *= 0.8500000238418579D; + + if(this.particleMaxAge-- <= 0){ + this.setExpired(); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java b/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java new file mode 100644 index 00000000..607c4da5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java @@ -0,0 +1,94 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.client.particle.Particle; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** + * Abstract superclass for all of wizardry's particles. This replaces {@code ParticleCustomTexture} (the functionality of + * which is no longer necessary since wizardry now uses {@code TextureAtlasSprite}s to do the rendering), and fits into + * {@code ParticleBuilder} by exposing all the necessary variables through getters, allowing them to be set on the fly + * rather than needing to be passed into the constructor. + *

+ * The new system is as follows: + *

+ * - All particle classes have a single constructor which takes a world and a position only.
+ * - Each particle class defines any relevant default values in its constructor, including velocity.
+ * - The particle builder then overwrites any other values that were set during building. + *

+ * This beauty of this system is that there are never any redundant parameters when spawning particles. For example, + * snow particles nearly always fall at the same speed, which can now be defined in the particle class and no longer + * needs to be defined when spawning the particle - but importantly, it can still be overridden if desired. + * + * @author Electroblob + * @since Wizardry 4.2.0 + * @see electroblob.wizardry.util.ParticleBuilder ParticleBuilder + */ +@SideOnly(Side.CLIENT) +public abstract class ParticleWizardry extends Particle { + + /** True if the particle is shaded, false if the particle always renders at full brightness. Defaults to false. */ + protected boolean shaded = false; + + protected float fadeRed = 1; + protected float fadeGreen = 1; + protected float fadeBlue = 0; + + public ParticleWizardry(World world, double x, double y, double z){ + super(world, x, y, z); + } + + /** Sets whether the particle should render at full brightness or not. True if the particle is shaded, false if + * the particle always renders at full brightness. Defaults to false.*/ + public void setShaded(boolean shaded){ + this.shaded = shaded; + } + + /** Sets this particle's gravity. True to enable gravity, false to disable. Defaults to false.*/ + public void setGravity(boolean gravity){ + this.particleGravity = gravity ? 1 : 0; + } + + /** Sets this particle's lifetime in ticks.*/ + public void setLifetime(int lifetime){ + this.particleMaxAge = lifetime; + } + + /** + * Sets the velocity of the particle. + * @param vx The x velocity + * @param vy The y velocity + * @param vz The z velocity + */ + public void setVelocity(double vx, double vy, double vz){ + this.motionX = vx; + this.motionY = vy; + this.motionZ = vz; + } + + /** + * Sets the fade colour of the particle. + * @param r The red colour component + * @param g The green colour component + * @param g The blue colour component + */ + public void setFadeColour(float r, float g, float b){ + this.fadeRed = r; + this.fadeGreen = g; + this.fadeBlue = b; + } + + @Override + public int getBrightnessForRender(float partialTick){ + return shaded ? super.getBrightnessForRender(partialTick) : 15728880; + } + + /** Simple particle factory interface which takes a world and a position and returns a particle. Used (via lambda + * expressions) in the client proxy to link particle enum types to actual particle classes. */ + @SideOnly(Side.CLIENT) + @FunctionalInterface + public interface IWizardryParticleFactory { + ParticleWizardry createParticle(World world, double x, double y, double z); + } +} diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java new file mode 100644 index 00000000..c09fe325 --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -0,0 +1,378 @@ +package electroblob.wizardry.util; + +import java.util.Random; + +import electroblob.wizardry.Wizardry; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +/** + * "Don't waste time spawning particles manually - let {@code ParticleBuilder} do the work for you!" + *

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

+ * It also goes without saying that this class should only ever be used client-side. + *

+ * {@link ParticleBuilder#instance} retrieves the static instance of the particle builder. Use + * {@link ParticleBuilder#particle(Type)} to start building a particle, or alternatively use the static + * convenience version {@link ParticleBuilder#create(Type)}. Use {@link ParticleBuilder#spawn()} + * to finish building and spawn the particle. Between these two, a variety of parameters can be set using the various + * setter methods (see individual method descriptions for more details). These, along with {@code ParticleBuilder.particle(...)}, + * return the particle builder instance, allowing them to be chained together to spawn particles using a single line of code. + * If any parameters are unspecified these will default to certain values, which may or may not depend on the particle type. + * Not all parameters affect all particles. Again, see individual method descriptions for more details. + *

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

+ * ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).colour(r, g, b).spawn(world); + * @author Electroblob + * @since Wizardry 4.2.0 + */ +public final class ParticleBuilder { + + /** The static instance of the particle builder. */ + public static final ParticleBuilder instance = new ParticleBuilder(); + + /** Whether the particle builder is currently building or not. */ + private boolean building = false; + + // Builder variables + // We can't just store a particle and set its parameters in the builder methods, because the server won't like having + // a field of a client-only type + private Type type; + private double x, y, z; + private double vx, vy, vz; + private float r, g, b; + private float fr, fg, fb; + private double radius; + private int lifetime; + private boolean gravity; + private boolean shaded; + private float scale; + private Entity entity; + + /** Enum constants representing the different types of particle added by wizardry. As of 4.2.0, this has been moved + * from its own file {@code Type} to inside {@link ParticleBuilder}. This allowed its name to be + * shortened to simply {@code Type}, making most references more concise. References in classes where another + * {@code Type} is also used can simply refer to the full name, {@code ParticleBuilder.Type}, which is no more verbose + * than before. + *

+ * Individual constants have comments detailing their corresponding default parameters. A range of values indicates + * randomness. */ + public static enum Type { + @Deprecated BLIZZARD, + /** Spiral particle, like potions.

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

Lifetime: 10-15 ticks
Velocity: (0, -0.03, 0) */ LEAF, + /** Bubble that doesn't burst in air.

Defaults:

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

Defaults:

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

Defaults:

Lifetime: 8-40 ticks
Colour: white */ PATH, + /** Snowflake particle.

Defaults:

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

Defaults:

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

Defaults:

Lifetime: 48-60 ticks
Colour: white */ SPARKLE, + @Deprecated SPARKLE_ROTATING + } + + private ParticleBuilder(){ + reset(); + } + + // Convenience methods + + /** + * Starts building a particle of the given type. Static convenience version of + * {@link ParticleBuilder#particle(Type)}; makes code more concise. + * @param type The type of particle to build + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is already building. + */ + public static ParticleBuilder create(Type type){ + return ParticleBuilder.instance.particle(type); + } + + /** + * Starts building a particle of the given type and positions it randomly within the given entity's bounding box. + * Equivalent to calling {@code ParticleBuilder.create(type).pos(...)}; users should chain any additional builder + * methods onto this one and finish with {@code .spawn(world)} as normal. + * Used extensively with summoned creatures; makes code much neater and more concise. + * @param type The type of particle to build + * @param entity The entity to position the particle at + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is already building. + */ + public static ParticleBuilder create(Type type, Entity entity){ + + double x = entity.posX + (entity.world.rand.nextDouble() - 0.5D) * (double)entity.width; + double y = entity.posY + entity.world.rand.nextDouble() * (double)entity.height; + double z = entity.posZ + (entity.world.rand.nextDouble() - 0.5D) * (double)entity.width; + + return ParticleBuilder.instance.particle(type).pos(x, y, z); + } + + /** + * Starts building a particle of the given type and positions it randomly within the given radius of the given position, + * with velocity proportional to distance from the given position if move is true. Good for making explosion-type effects. + * Equivalent to calling {@code ParticleBuilder.create(type).pos(...).vel(...)}; users should chain any additional builder + * methods onto this one and finish with {@code .spawn(world)} as normal. + * @param type The type of particle to build + * @param random An RNG instance + * @param x The x coordinate of the centre of the region in which to position the particle + * @param y The y coordinate of the centre of the region in which to position the particle + * @param z The z coordinate of the centre of the region in which to position the particle + * @param radius The radius of the region in which to position the particle + * @param move Whether the particle should move outwards from the centre (note that if this is false, the particle's + * default velocity will apply) + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is already building. + */ + public static ParticleBuilder create(Type type, Random random, double x, double y, double z, double radius, boolean move){ + + double px = x + (random.nextDouble() - 0.5D) * radius; + double py = y + (random.nextDouble() - 0.5D) * radius; + double pz = z + (random.nextDouble() - 0.5D) * radius; + + if(move) return ParticleBuilder.instance.particle(type).pos(x, y, z).vel(px-x, py-y, pz-z); + + return ParticleBuilder.instance.particle(type).pos(x, y, z); + } + + // Core builder methods + + /** + * Starts building a particle of the given type. + * @param type The type of particle to build + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is already building. + */ + public ParticleBuilder particle(Type type){ + if(building) throw new IllegalStateException("Already building!"); + this.type = type; + this.building = true; + return this; + } + + /** + * Sets the position of the particle being built. If unspecified, this defaults to the origin (0, 0, 0). + *

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

+ * Affects: All particle types except {@link Type#DUST DUST} + * @param x The x coordinate to set + * @param y The y coordinate to set + * @param z The z coordinate to set + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder vel(double vx, double vy, double vz){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.vx = vx; + this.vy = vy; + this.vz = vz; + return this; + } + + /** + * Sets the colour of the particle being built. If unspecified, this defaults to the particle's default colour, + * specified within its constructor. + *

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

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

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

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

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

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

+ * Affects: All particle types + * @param shaded True to enable shading for the particle, false for full brightness + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder shaded(boolean shaded){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.shaded = shaded; + return this; + } + + /** + * Sets the entity of the particle being built. This must be specified for entity-linked particles. + * @param entity The entity to set + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder entity(Entity entity){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.entity = entity; + return this; + } + + /** + * Spawns the particle that has been built and resets the particle builder. + * @param world The world in which to spawn the particle + * @throws IllegalStateException if the particle builder is not yet building. + */ + public void spawn(World world){ + + if(!building) throw new IllegalStateException("Not building yet!"); + + if(y < 0 && entity == null) Wizardry.logger.warn("Spawning particle below y = 0 - are you sure the position/entity" + + "has been set correctly?"); + + electroblob.wizardry.client.particle.ParticleWizardry particle = Wizardry.proxy.createParticle(type, world, x, y, z); + + if(particle == null){ + reset(); + return; + } + + particle.multipleParticleScaleBy(scale); + if(!Double.isNaN(vx) && !Double.isNaN(vy) && !Double.isNaN(vz)) particle.setVelocity(vx, vy, vz); + if(r >= 0 && g >= 0 && b >= 0) particle.setRBGColorF(r, g, b); + if(fr >= 0 && fg >= 0 && fb >= 0) particle.setFadeColour(fr, fg, fb); + if(lifetime >= 0) particle.setLifetime(lifetime); + particle.setGravity(gravity); + particle.setShaded(shaded); + + net.minecraft.client.Minecraft.getMinecraft().effectRenderer.addEffect(particle); + + reset(); + } + + /** Resets the state of the particle builder and resets all the builder variables to their default values. */ + private void reset(){ + building = false; + type = null; + x = 0; + y = 0; + z = 0; + // NaN indicates the velocity was not set (can't use -1 since it could very reasonably be -1) + // For all other values -1 indicates the value was not set + vx = Double.NaN; + vy = Double.NaN; + vz = Double.NaN; + r = -1; + g = -1; + b = -1; + fr = -1; + fg = -1; + fb = -1; + radius = 0; + lifetime = -1; + gravity = false; + shaded = false; + scale = 1; + entity = null; + } + +} diff --git a/src/main/resources/assets/ebwizardry/textures/particle/buff.png b/src/main/resources/assets/ebwizardry/textures/particle/buff.png new file mode 100644 index 0000000000000000000000000000000000000000..bdc069b07504b182424b1bf58ccf362c5576b5ce GIT binary patch literal 4714 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU})fAV_;y|-I$-nz`($kFdh=h($!uKvd{XZXE-I;CD|K$B>F!Z|7D| z3B6i-+@6`aX+cN(3dvJD&qR~z?(%Ha=#?Dw4FY^ zy|M6sTS9iA$ZfVB1}!x!uNm|B_6WINJbmEWI<-5TYZo`TH%1o9ycco3IQxM2foJbt zn0#5P&n(>V^?+!hj6cgi-U`dEMY;~FeJZ@C`s7cUuI$>N?;2<#b|Xl{^{U?G3#WPd z*}pMOV=8`RaZkL0>jZH~1@T`yTI6GBa@x6k+NQS3VHO-8ApH zufS$DjiZHsDjx_|zK<0=^67EEecj~em4|m32MQ`35V`oJ^+12aefPi;i4Tn&A4(P0 zPW>sjnPKLOgA9c-=UMz1<(T|f_VK-ubq!RL($3zqce94x$3$%dy}rlIjlKuAXmm~U zHmT>Ah!r_%{q@}5h3qrz`7-(+|FC^9`@rP`?;Gzf(x~FE2vf7!w3?Iqv9fE&;)Z&* zf7}sbt{1a61?A{=C9Qp4schG`t@;Y9&3S7lrt9+xW#Tz)IDDo!OzB+aF6w$wtNzkG z-jhKx$7K)vJMdD;Mf;4osO!g?pUt*MYxWu@q{%K;YYny&3*Z2 zzyHm#$~58UvN`bmZ(tL9&J?RfJ-j!fGM-f4d-waFi|3kuE`ve|^(6l?Sqglg*OPxFk%zR;BeJTH*ZXJz5S+H%^yyOIT@mAT9Y!-~sLfRu8U6 zy-sfwQ+SdsiE#sek+^$q@D0y-{`U%&Pej4KBB1mwvc;Rl-=*f^!C2 zjIMn4#i;!{jd>~ap6A|WIXdajU!&wRrU%|PSZ}!|dqC$wc+$J|&nn}JCtkVH++)so z_SlT~OqLsb{`?7cSe;Q_vr}uz$-I{>FEyFw`WhUo3Et2)HR^S@>+5{3-ub8I*S=kN2K@cbZj`qxAtrBf!G7xmGkVwnqO~WeBO0{?^;woOPz+irJzLk z$v+JTn2)^KuQ9paqv^{2XO;J&n0qHTRvwTGlKO96pjD7M@3}6s5dVr3Cyzg^+_!=6 zd!)kY$3Y3xZO*@!4XJR@o%JqdkGA8-iwleLGkALS+yz+9ItrXwJ^9!X$3}J*#|tWv z57IoF7|N!v*_0)9?Ut$1mXn{p%|4LJ9K_%#AjADe^XH#!DxP-hr`%#lSZll6Eh?Qs z*k!`+jt5~3{okuC_Z)V4-jT-7de3jtlad92nqPSecsE>&%FY&eV0S>h!FjUEO=r!m z9v>RL*KEyZW04bJIauT7^X3w*IX*{LHfb+YqzdxW%RQ5v7ckSrtWFP zzQJqdb5-8|(b>77(#w1Iu6g=(NA14c1MHrYazq&4a7iq^;&hTT@2y|3=&XM#8?-zp z`7% z+I8Gj&zbcfZ+qzHIq3=W1CGM!?;kr{UV1>kVfosv>#tfpZ=089<2mW`5+fPSFV+py zrv!B`%{$Q;mYwUZzD133KAX*h6Dpp4f{N?HylhpL?HAdxH!Syi7wd^4V_nZltV|U- zf<6nJHMjDxXZ{zuk+62}cIoMy4a`TDe-~8D3-tOcU=gG9Y=r_xQ&w}zdQJy5o`Ql& zD&i+n0=;aNBpy6IF!|c8tmwOLDxO74kF>MNgzVcqka^H|$7m&S=ao6dCjNRimLunl=D4!^N)VGr5d5_(~V zR`%Dt1C^83?&ZF7c{b1WR7TOX{;l8Ebj9ngnRsqz1HTUAx6RkiNkNlN4r`c4z#DUe zlnkC;M+2{=LB%UWW`*nbIySPOaGA<-;^rjNb*owVHKux93=3u0bdxx+W)lF3}jwueG1UG~pSz4?i;k$sBSQp*F^mo(ir_Py*s zrCz-4A=d(iyi=QU5=FPHo0_ze<;|RBFB_fGmx{y(PD@?=YmL;Kro@Kz9L1L}o7k>d zo?czOGzGhp-JbcW)JTvMT zv(zDjnz(86jyEPoPKymxJ=uK8#CE?^L-f(uJVC4b8uc5N&sZcpA(?F z;L?TDJk8n7wcIl%EqfU^b!UT5h3tpT?%9Za+l=Qe zdnwMkR5I?PtZbshK23$ELJxY+ndogfckHdS+>B+J#jUH?h}k4CUzn77^G{;~dyH1k ze3mycnpX^XuAdB=#^AlnsCc0wKF9ZyvWV&9n-C z^<$HMp3eHak<(m5C)ud@UJlk`xuN()PQ=C``~jowHQ%^?);+VAz4Tr5mG9uE=!W#w zolmS&GXD2j=U!6KKBTsB&hgHdNk@S*98C{E zvCd`VpcW+#D%E+ibGtcmA3SDs6!^m^H$mm(Kd+TV)@#>IyjFYQhXMzinViDh`{`b< zcI$dh$~;i8G^Fje?!Gm*_<}EfDYH@VoTRq&N}0`q-F1)l+30UzuyE{}V>?Mj)ALu1 z#?o6YA8)VSdOg(fHUEbO70((5u+m$3SKH!Je(-39?(fa6wpH|;wD;-t*#)%+-gC=+ z5YB$vze?ai_^FBpgT1o+0bY>_3%73j|Di#FgXw|CorB9wJSP|t4)=(W=RSZuYS%yqfyK=m!NRI1Li@_9{K(!-t;==E2uydsJDLeko|^)?C|O_~Q* zdQQ@~li3&c@$Eyel~Z?EGhSzYy=Lpvwx#KIP3H;^NFI>BRJT8Rr%IUDUbPqJg|FSZ z329t>JSpm+w%nzR$xL(UyQvRKv@hJ5+WFpq&woZ>9pe~Iu< z;INP1&~WwBd)4gRYF?9BDt><$%CDrctXuf%_qAKQUo5^Dp!_)fp_JstYkI3L*Q!0f zmC?8L8sDsc4eSNa%Wu8ELs)pO(szmX+CFiZP*S=@`CtRU({&Q&PgBcFY5ZS!NDk?$Ix!w?h=uJjJ5Y!#hzB) ztFLG*Ui!1Ayw7!@l$evU2cyh|Mr`eJ7@fncyK!EwaAZE2`tr5EBEc;R`e4* zJtL*(r!u4Ct*zJmnJzcZf4uI&ug!IuZDlh)*xZ>~wfte;kP@CZT7GCnv~pQnE%-7xV`rKt=Vh$v-+I-{O8su_Uf*mRm};r4WC)b zJhOAl{%f`F_wDnaYwD&t$*3N(;`-s8u=Cn4-jAor1188 z!^Te{yVkW>2u6q=|EL<2vX?=pYtf6OgOY9Ht{+!CuXNNsFZy<>#DmIvF?U|}FMb-i zXm;cAMH*J@<%|CKJ-Dz)t3TswHTndYnn!Q+K7f;1bqgmfYK7VC9c(qXG zephz&&sY)Hr{~tL?p~y!Y=1r^(NgAZs6wcs v$UsC*_{qgxUoTl+{Jh7XcWM=L!XN(o^OsIJ#q=38c*Nl8>gTe~DWM4fSs&o~ literal 0 HcmV?d00001 From 466b3bbc2720fc3fcb4c5266ebcff6517b5fcfa1 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 2 May 2018 13:17:15 +0100 Subject: [PATCH 05/68] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c3bb6202..939f55fc 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ build eclipse run misc +libs Thumbs.db \ No newline at end of file From d91a3e056a4b88f41b212c2c162ff68c7d5b8b4b Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 5 Jun 2018 21:13:41 +0100 Subject: [PATCH 06/68] The great particle refactoring part 1: Introducing ParticleBuilder! Adds ParticleBuilder to replace the particle spawning methods in the proxies, and changes all particle spawning to use the builder except for in the spell classes, which are to be reorganised first. --- .../electroblob/wizardry/CommonProxy.java | 74 ++----------- .../java/electroblob/wizardry/Wizardry.java | 1 + .../wizardry/WizardryEventHandler.java | 10 +- .../wizardry/block/BlockCrystalFlower.java | 12 +- .../wizardry/block/BlockSpectral.java | 24 ++-- .../wizardry/client/ClientProxy.java | 103 ++++++++---------- .../client/particle/ParticleBlizzard.java | 19 +--- .../particle/ParticleCustomTexture.java | 95 +--------------- .../client/particle/ParticleDarkMagic.java | 19 +--- .../client/particle/ParticleDust.java | 31 ++---- .../wizardry/client/particle/ParticleIce.java | 26 ++--- .../client/particle/ParticleLeaf.java | 14 +-- .../client/particle/ParticleMagicFlame.java | 31 +++--- .../client/particle/ParticlePath.java | 24 +--- .../particle/ParticleRotatingSparkle.java | 15 ++- .../client/particle/ParticleSnow.java | 16 +-- .../client/particle/ParticleSpark.java | 12 +- .../client/particle/ParticleSparkle.java | 80 +++++--------- .../entity/construct/EntityBlizzard.java | 29 +++-- .../entity/construct/EntityDecay.java | 13 ++- .../entity/construct/EntityForcefield.java | 17 +-- .../entity/construct/EntityFrostSigil.java | 10 +- .../entity/construct/EntityHammer.java | 22 ++-- .../entity/construct/EntityHealAura.java | 15 ++- .../construct/EntityLightningSigil.java | 22 ++-- .../entity/construct/EntityTornado.java | 33 +++--- .../wizardry/entity/living/EntityDecoy.java | 15 ++- .../entity/living/EntityEvilWizard.java | 18 +-- .../entity/living/EntityIceGiant.java | 19 ++-- .../entity/living/EntityIceWraith.java | 14 ++- .../entity/living/EntityLightningWraith.java | 18 +-- .../entity/living/EntityShadowWraith.java | 35 +++--- .../entity/living/EntitySilverfishMinion.java | 10 +- .../entity/living/EntitySpiderMinion.java | 10 +- .../entity/living/EntitySpiritHorse.java | 51 +++++---- .../entity/living/EntitySpiritWolf.java | 40 ++++--- .../entity/living/EntityStormElemental.java | 21 ++-- .../wizardry/entity/living/EntityWizard.java | 18 +-- .../entity/living/ISummonedCreature.java | 10 +- .../entity/projectile/EntityDarknessOrb.java | 21 ++-- .../entity/projectile/EntityDart.java | 8 +- .../entity/projectile/EntityFirebomb.java | 30 ++--- .../entity/projectile/EntityForceOrb.java | 11 +- .../entity/projectile/EntityIceCharge.java | 19 ++-- .../entity/projectile/EntityIceLance.java | 11 +- .../entity/projectile/EntityIceShard.java | 11 +- .../projectile/EntityLightningArrow.java | 16 +-- .../projectile/EntityLightningDisc.java | 19 ++-- .../entity/projectile/EntityMagicMissile.java | 16 +-- .../entity/projectile/EntityPoisonBomb.java | 20 ++-- .../entity/projectile/EntitySmokeBomb.java | 13 +-- .../entity/projectile/EntitySpark.java | 11 +- .../entity/projectile/EntitySparkBomb.java | 19 ++-- .../entity/projectile/EntityThunderbolt.java | 8 +- .../wizardry/potion/PotionFrost.java | 6 +- .../wizardry/registry/WizardryPotions.java | 14 +-- .../electroblob/wizardry/spell/Agility.java | 17 +-- .../java/electroblob/wizardry/spell/Arc.java | 6 +- .../wizardry/spell/ArcaneJammer.java | 6 +- .../electroblob/wizardry/spell/Banish.java | 6 +- .../electroblob/wizardry/spell/Bubble.java | 6 +- .../wizardry/spell/ChainLightning.java | 8 +- .../wizardry/spell/Clairvoyance.java | 6 +- .../wizardry/spell/ConjureArmour.java | 4 +- .../wizardry/spell/ConjureBow.java | 4 +- .../wizardry/spell/ConjurePickaxe.java | 4 +- .../wizardry/spell/ConjureSword.java | 4 +- .../wizardry/spell/CureEffects.java | 6 +- .../wizardry/spell/CurseOfSoulbinding.java | 8 +- .../wizardry/spell/Darkvision.java | 4 +- .../wizardry/spell/Diamondflesh.java | 6 +- .../wizardry/spell/Entrapment.java | 6 +- .../wizardry/spell/FireResistance.java | 6 +- .../electroblob/wizardry/spell/Firestorm.java | 6 +- .../electroblob/wizardry/spell/FlameRay.java | 10 +- .../wizardry/spell/FlamingWeapon.java | 4 +- .../electroblob/wizardry/spell/Flight.java | 6 +- .../wizardry/spell/FontOfMana.java | 4 +- .../wizardry/spell/FontOfVitality.java | 6 +- .../wizardry/spell/ForestsCurse.java | 8 +- .../electroblob/wizardry/spell/Freeze.java | 14 +-- .../wizardry/spell/FreezingWeapon.java | 4 +- .../electroblob/wizardry/spell/FrostAxe.java | 4 +- .../electroblob/wizardry/spell/FrostRay.java | 10 +- .../electroblob/wizardry/spell/Glide.java | 6 +- .../wizardry/spell/GreaterHeal.java | 6 +- .../electroblob/wizardry/spell/GroupHeal.java | 6 +- .../java/electroblob/wizardry/spell/Heal.java | 9 +- .../electroblob/wizardry/spell/HealAlly.java | 4 +- .../electroblob/wizardry/spell/IceStatue.java | 6 +- .../wizardry/spell/ImbueWeapon.java | 4 +- .../wizardry/spell/Intimidate.java | 4 +- .../wizardry/spell/InvigoratingPresence.java | 4 +- .../wizardry/spell/Invisibility.java | 6 +- .../wizardry/spell/InvokeWeather.java | 4 +- .../electroblob/wizardry/spell/Ironflesh.java | 6 +- .../wizardry/spell/Levitation.java | 4 +- .../electroblob/wizardry/spell/LifeDrain.java | 10 +- .../wizardry/spell/LightningRay.java | 6 +- .../wizardry/spell/LightningWeb.java | 8 +- .../wizardry/spell/Metamorphosis.java | 6 +- .../wizardry/spell/MindControl.java | 10 +- .../electroblob/wizardry/spell/MindTrick.java | 6 +- .../electroblob/wizardry/spell/Oakflesh.java | 6 +- .../electroblob/wizardry/spell/Petrify.java | 6 +- .../wizardry/spell/PlagueOfDarkness.java | 6 +- .../electroblob/wizardry/spell/Poison.java | 10 +- .../wizardry/spell/ReplenishHunger.java | 4 +- .../electroblob/wizardry/spell/Shockwave.java | 6 +- .../electroblob/wizardry/spell/Slime.java | 6 +- .../electroblob/wizardry/spell/Snare.java | 6 +- .../wizardry/spell/SummonIceGiant.java | 4 +- .../wizardry/spell/SummonIronGolem.java | 4 +- .../wizardry/spell/SummonSnowGolem.java | 4 +- .../wizardry/spell/Thunderstorm.java | 6 +- .../wizardry/spell/WallOfFrost.java | 6 +- .../wizardry/spell/WaterBreathing.java | 4 +- .../electroblob/wizardry/spell/Wither.java | 10 +- .../wizardry/util/WizardryParticleType.java | 9 -- 119 files changed, 722 insertions(+), 972 deletions(-) delete mode 100644 src/main/java/electroblob/wizardry/util/WizardryParticleType.java diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index acaf16ed..b8ef9d67 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -1,5 +1,6 @@ package electroblob.wizardry; +import electroblob.wizardry.client.particle.ParticleWizardry; import electroblob.wizardry.item.ItemSpectralBow; import electroblob.wizardry.packet.PacketCastContinuousSpell; import electroblob.wizardry.packet.PacketCastSpell; @@ -11,7 +12,7 @@ import electroblob.wizardry.packet.PacketTransportation; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.item.ItemStack; @@ -56,75 +57,20 @@ public class CommonProxy { // SECTION Particles // =============================================================================================================== - /** - * Spawns a custom particle of the specified type. - * - * @param type EnumParticleType of the particle - * @param world Reference to the World object - * @param x Particle x position - * @param y Particle y position - * @param z Particle z position - * @param velX Particle x velocity - * @param velY Particle y velocity - * @param velZ Particle z velocity - * @param maxAge Lifetime of the particle in ticks - * @param r Red component of particle colour; will be clamped to between 0 and 1 - * @param g Red component of particle colour; will be clamped to between 0 and 1 - * @param b Red component of particle colour; will be clamped to between 0 and 1 - * @param doGravity Whether the particle is affected by gravity (only affects SPARKLE at the moment) - * @param radius The radius of the particle's motion, for cirular motion particles - */ - public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, - double velY, double velZ, int maxAge, float r, float g, float b, boolean doGravity, double radius){ - // Does nothing since particles are client-side only - } + /** Called from init() in the main mod class to initialise the particle factories. */ + public void initParticleFactories(){} // Does nothing since particles are client-side only - /** - * Spawns a custom particle of the specified type. doGravity defaults to false and radius defaults to 0. Note that - * some of these settings may not affect the particle; some particles are always affected by gravity, for instance. - * - * @param type EnumParticleType of the particle - * @param world Reference to the World object - * @param x Particle x position - * @param y Particle y position - * @param z Particle z position - * @param velX Particle x velocity - * @param velY Particle y velocity - * @param velZ Particle z velocity - * @param maxAge Lifetime of the particle in ticks - * @param r Red component of particle colour; will be clamped to between 0 and 1 (unless this is a MAGIC_FIRE - * particle, in which case this is the scale) - * @param g Red component of particle colour; will be clamped to between 0 and 1 - * @param b Red component of particle colour; will be clamped to between 0 and 1 - */ - public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, - double velY, double velZ, int maxAge, float r, float g, float b){ - this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, r, g, b, false, 0); - } - - /** - * Spawns a custom particle of the specified type. Colour defaults to white, doGravity defaults to false and radius - * defaults to 0. Note that some of these settings may not affect the particle; some particles are always affected - * by gravity, for instance. - * - * @param type EnumParticleType of the particle - * @param world Reference to the World object - * @param x Particle x position - * @param y Particle y position - * @param z Particle z position - * @param velX Particle x velocity - * @param velY Particle y velocity - * @param velZ Particle z velocity - * @param maxAge Lifetime of the particle in ticks - */ - public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, - double velY, double velZ, int maxAge){ - this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, 1, 1, 1, false, 0); + /** Creates a new particle of the specified type from the appropriate particle factory. Does not actually spawn the + * particle; use {@link electroblob.wizardry.util.ParticleBuilder ParticleBuilder} to spawn particles. */ + public ParticleWizardry createParticle(Type type, World world, double x, double y, double z){ + return null; } public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){ } + + public void spawnEntityParticle(World world, Entity entity, int maxAge, float r, float g, float b){} // SECTION Items // =============================================================================================================== diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index 99f2766f..996258b9 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -156,6 +156,7 @@ public class Wizardry { WizardryPacketHandler.initPackets(); proxy.initGuiBits(); + proxy.initParticleFactories(); } @EventHandler diff --git a/src/main/java/electroblob/wizardry/WizardryEventHandler.java b/src/main/java/electroblob/wizardry/WizardryEventHandler.java index b3799275..a46d2730 100644 --- a/src/main/java/electroblob/wizardry/WizardryEventHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryEventHandler.java @@ -20,9 +20,10 @@ import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.IElementalDamage; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.EntityLiving; @@ -213,10 +214,9 @@ public final class WizardryEventHandler { world.spawnEntity(arc); }else{ for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, - 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, 3); + 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, diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java index 1ca537ea..27bc7046 100644 --- a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java +++ b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java @@ -2,9 +2,9 @@ package electroblob.wizardry.block; import java.util.Random; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryBlocks; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.block.BlockBush; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; @@ -41,10 +41,10 @@ public class BlockCrystalFlower extends BlockBush { @Override public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){ if(world.isRemote && random.nextBoolean()){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, pos.getX() + random.nextDouble(), - pos.getY() + random.nextDouble() / 2 + 0.5, pos.getZ() + random.nextDouble(), 0d, 0.01, 0d, - 20 + random.nextInt(10), 0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2), - 0.5f + (random.nextFloat() / 2)); + ParticleBuilder.create(Type.SPARKLE) + .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble() / 2 + 0.5, pos.getZ() + random.nextDouble()).vel(0, 0.01, 0) + .lifetime(20 + random.nextInt(10)).colour(0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2), + 0.5f + (random.nextFloat() / 2)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/block/BlockSpectral.java b/src/main/java/electroblob/wizardry/block/BlockSpectral.java index d4c91f1a..99d1ee17 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSpectral.java +++ b/src/main/java/electroblob/wizardry/block/BlockSpectral.java @@ -61,18 +61,22 @@ public class BlockSpectral extends BlockContainer { @Override public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){ + // Middle of block - Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX() + random.nextDouble(), - pos.getY() + random.nextDouble(), pos.getZ() + random.nextDouble(), 0, 0, 0, - (int)(16.0D / (Math.random() * 0.8D + 0.2D)), 0.4f + random.nextFloat() * 0.2f, - 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f); + ParticleBuilder.create(Type.DUST) + .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble(), pos.getZ() + random.nextDouble()) + .lifetime((int)(16.0D / (Math.random() * 0.8D + 0.2D))) + .colour(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f) + .shaded(true).spawn(world); + // Top surface - Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX() + random.nextDouble(), pos.getY() + 1, - pos.getZ() + random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)), - 0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f); - Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, pos.getX() + random.nextDouble(), pos.getY() + 1, - pos.getZ() + random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)), - 0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f); + for(int i=0; i<2; i++){ + ParticleBuilder.create(Type.DUST) + .pos(pos.getX() + random.nextDouble(), pos.getY() + 1, pos.getZ() + random.nextDouble()) + .lifetime((int)(16.0D / (Math.random() * 0.8D + 0.2D))) + .colour(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f) + .shaded(true).spawn(world); + } } // Overriden to make the block always look full brightness despite not emitting diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 4adcb7ac..411fdc59 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -2,6 +2,7 @@ package electroblob.wizardry.client; import java.lang.ref.WeakReference; import java.util.HashMap; +import java.util.Map; import org.lwjgl.input.Keyboard; @@ -11,11 +12,13 @@ import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.model.ModelWizardArmour; import electroblob.wizardry.client.particle.ParticleBlizzard; +import electroblob.wizardry.client.particle.ParticleBuff; import electroblob.wizardry.client.particle.ParticleDarkMagic; import electroblob.wizardry.client.particle.ParticleDust; -import electroblob.wizardry.client.particle.ParticleGiantBubble; +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; @@ -23,6 +26,8 @@ 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.renderer.LayerStone; import electroblob.wizardry.client.renderer.RenderArc; import electroblob.wizardry.client.renderer.RenderArcaneWorkbench; @@ -114,8 +119,9 @@ import electroblob.wizardry.spell.Spell; import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; import electroblob.wizardry.tileentity.TileEntityMagicLight; import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WizardryParticleType; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; @@ -135,7 +141,6 @@ import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Property; @@ -154,6 +159,9 @@ public class ClientProxy extends CommonProxy { /** Static instance of the mixed font renderer */ public static MixedFontRenderer mixedFontRenderer; + /** Static particle factory map */ + private static Map factories; + // Key Bindings public static final KeyBinding NEXT_SPELL = new KeyBinding("key." + Wizardry.MODID + ".next_spell", Keyboard.KEY_N, "key.categories." + Wizardry.MODID); public static final KeyBinding PREVIOUS_SPELL = new KeyBinding("key." + Wizardry.MODID + ".previous_spell", Keyboard.KEY_B, "key.categories." + Wizardry.MODID); @@ -265,67 +273,44 @@ public class ClientProxy extends CommonProxy { // =============================================================================================================== @Override - public void spawnParticle(WizardryParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, - float r, float g, float b, boolean doGravity, double radius){ + public void initParticleFactories(){ - // Colour values are now automatically clamped to between 0 and 1, as values outside this range seem to - // cause strange effects in 1.10 (or more specifically, particles that are bright pink!) - // TODO: This is a terrible dirty fix, but it'll do for now. Find a nicer way in future. - if(type != WizardryParticleType.MAGIC_FIRE) r = MathHelper.clamp(r, 0, 1); - g = MathHelper.clamp(g, 0, 1); - b = MathHelper.clamp(b, 0, 1); - - switch(type){ - - case BLIZZARD: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleBlizzard(world, maxAge, x, z, radius, y)); - break; - case BRIGHT_DUST: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDust(world, x, y, z, velX, velY, velZ, r, g, b, false)); - break; - case DARK_MAGIC: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDarkMagic(world, x, y, z, velX, velY, velZ, r, g, b)); - break; - case DUST: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleDust(world, x, y, z, velX, velY, velZ, r, g, b, true)); - break; - case ICE: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleIce(world, x, y, z, velX, velY, velZ, maxAge)); - break; - case LEAF: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleLeaf(world, x, y, z, velX, velY, velZ, maxAge)); - break; - case MAGIC_BUBBLE: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleGiantBubble(world, x, y, z, velX, velY, velZ)); - break; - case MAGIC_FIRE: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleMagicFlame(world, x, y, z, velX, velY, velZ, maxAge, r == 0 ? 1 + world.rand.nextFloat() : r)); - break; - case PATH: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticlePath(world, x, y, z, velX, velY, velZ, r, g, b, maxAge)); - break; - case SNOW: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSnow(world, x, y, z, velX, velY, velZ)); - break; - case SPARK: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSpark(world, x, y, z, velX, velY, velZ)); - break; - case SPARKLE: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleSparkle(world, x, y, z, velX, velY, velZ, r, g, b, maxAge, doGravity)); - break; - case SPARKLE_ROTATING: - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleRotatingSparkle(world, maxAge, x, z, radius, y, r, g, b)); - break; - default: - break; + factories = new HashMap<>(); + + factories.put(Type.BLIZZARD, (world, x, y, z) -> new ParticleBlizzard(world, x, y, z)); + factories.put(Type.DARK_MAGIC, (world, x, y, z) -> new ParticleDarkMagic(world, x, y, z)); + factories.put(Type.DUST, (world, x, y, z) -> new ParticleDust(world, x, y, z)); + factories.put(Type.FLASH, (world, x, y, z) -> new ParticleFlash(world, x, y, z)); + factories.put(Type.ICE, (world, x, y, z) -> new ParticleIce(world, x, y, z)); + factories.put(Type.LEAF, (world, x, y, z) -> new ParticleLeaf(world, x, y, z)); + factories.put(Type.MAGIC_BUBBLE, (world, x, y, z) -> new ParticleMagicBubble(world, x, y, z)); + factories.put(Type.MAGIC_FIRE, (world, x, y, z) -> new ParticleMagicFlame(world, x, y, z)); + factories.put(Type.PATH, (world, x, y, z) -> new ParticlePath(world, x, y, z)); + factories.put(Type.SNOW, (world, x, y, z) -> new ParticleSnow(world, x, y, z)); + factories.put(Type.SPARK, (world, x, y, z) -> new ParticleSpark(world, x, y, z)); + factories.put(Type.SPARKLE, (world, x, y, z) -> new ParticleSparkle(world, x, y, z)); + factories.put(Type.SPARKLE_ROTATING, (world, x, y, z) -> new ParticleRotatingSparkle(world, x, y, z)); + } + + @Override + public ParticleWizardry createParticle(Type type, World world, double x, double y, double z){ + IWizardryParticleFactory factory = factories.get(type); + if(factory == null){ + Wizardry.logger.warn("Unrecognised particle type %s! Ensure the particle is properly registered.", type); + return null; } + return factory.createParticle(world, x, y, z); } @Override public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){ - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTornado(world, maxAge, x, z, radius, y, velX, velZ, block).setBlockPos(pos));// , - // world.rand.nextInt(6))); + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTornado(world, maxAge, x, z, radius, y, velX, velZ, block).setBlockPos(pos));// , world.rand.nextInt(6))); + } + + @Override + public void spawnEntityParticle(World world, Entity entity, int maxAge, float r, float g, float b){ + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleBuff(world, entity, maxAge, r, g, b, world.rand.nextBoolean())); } // SECTION Packet Handlers @@ -431,8 +416,8 @@ public class ClientProxy extends CommonProxy { double x = caster.posX + radius * Math.cos(angle); double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2; double z = caster.posZ + radius * Math.sin(angle); - Minecraft.getMinecraft().effectRenderer - .addEffect(new ParticleSparkle(world, x, y, z, 0, 0.02, 0, 0.6f, 1.0f, 0.6f, 80 + world.rand.nextInt(10))); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.02, 0).colour(0.6f, 1, 0.6f) + .lifetime(80 + world.rand.nextInt(10)).spawn(world); } for(int i = 0; i < 20; i++){ double radius = 1; diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java index 58e84e48..9f7c2828 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java @@ -11,15 +11,14 @@ public class ParticleBlizzard extends ParticleSnow { private double radius; private double speed; - public ParticleBlizzard(World world, int maxAge, double originX, double originZ, double radius, double yPos){ - super(world, 0, 0, 0, 0, 0, 0, maxAge); + 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 = originX - Math.cos(angle) * radius; - double z = originZ + radius * Math.sin(angle); - this.radius = radius; - this.setPosition(x, yPos, z); + double x = ox - Math.cos(angle) * radius; + double z = oz + radius * Math.sin(angle); + this.setPosition(x, y, z); this.prevPosX = x; - this.prevPosY = yPos; + this.prevPosY = y; this.prevPosZ = z; if(rand.nextBoolean()){ speed = rand.nextDouble() * 2 + 1; @@ -29,12 +28,6 @@ public class ParticleBlizzard extends ParticleSnow { this.multipleParticleScaleBy(1.5f); } - @Override - public void init(){ - super.init(); - this.fullBrightness = true; - } - // @Override // public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float // rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java b/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java index 090ea7c9..46f33ad4 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java @@ -13,43 +13,14 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -/** - * Abstract superclass for all particles that use custom textures. This is intended to centralise as much code as - * possible; all subclasses need to do is to define the texture to use, how the frames are arranged (and which to - * choose), and any properties like gravity and collisions. - * - * @author Electroblob - * @since Wizardry 1.2 - */ -@SideOnly(Side.CLIENT) -public abstract class ParticleCustomTexture extends Particle { +@Deprecated +public abstract class ParticleCustomTexture extends ParticleWizardry { - /** True if the particle always renders at full brightness. Defaults to false. */ - protected boolean fullBrightness = false; - - public ParticleCustomTexture(World world, double x, double y, double z, double vx, double vy, double vz){ - super(world, x, y, z, vx, vy, vz); - this.motionX = vx; - this.motionY = vy; - this.motionZ = vz; - this.init(); + public ParticleCustomTexture(World world, double x, double y, double z){ + super(world, x, y, z); } - public ParticleCustomTexture(World world, double x, double y, double z, double vx, double vy, double vz, - int maxAge){ - this(world, x, y, z, vx, vy, vz); - 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(); - /** * Returns a ResourceLocation for the particle's texture sheet. Do not create a new ResourceLocation in this method, * only return a constant. @@ -83,59 +54,6 @@ public abstract class ParticleCustomTexture extends Particle { this.particleTextureIndexY = index / getYFrames(); } - // Overridden to fix the bug with vanilla that makes particles frictionless. (y != y... seriously, Mojang?) - // TESTME: Probably no longer necessary. - // @Override - // public void move(double x, double y, double z){ - // - // double d0 = y; - // - // if (this.canCollide) - // { - // List list = this.world.getCollisionBoxes((Entity)null, this.getBoundingBox().addCoord(x, y, z)); - // - // for (AxisAlignedBB axisalignedbb : list) - // { - // y = axisalignedbb.calculateYOffset(this.getBoundingBox(), y); - // } - // - // this.setBoundingBox(this.getBoundingBox().offset(0.0D, y, 0.0D)); - // - // for (AxisAlignedBB axisalignedbb1 : list) - // { - // x = axisalignedbb1.calculateXOffset(this.getBoundingBox(), x); - // } - // - // this.setBoundingBox(this.getBoundingBox().offset(x, 0.0D, 0.0D)); - // - // for (AxisAlignedBB axisalignedbb2 : list) - // { - // z = axisalignedbb2.calculateZOffset(this.getBoundingBox(), z); - // } - // - // this.setBoundingBox(this.getBoundingBox().offset(0.0D, 0.0D, z)); - // } - // else - // { - // this.setBoundingBox(this.getBoundingBox().offset(x, y, z)); - // } - // - // this.resetPositionToBB(); - // this.onGround = d0 != y && d0 < 0.0D; - // - // /* Can never be true! - But this doesn't seem to make any difference anyway. - // if (x != x) - // { - // this.motionX = 0.0D; - // } - // - // if (z != z) - // { - // this.motionZ = 0.0D; - // } - // */ - // } - // 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 @@ -211,9 +129,4 @@ public abstract class ParticleCustomTexture extends Particle { */ public void undoGLStateChanges(){ } - - @Override - public int getBrightnessForRender(float partialTick){ - return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick); - } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java b/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java index 9c962a00..b4bc8710 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java @@ -1,6 +1,5 @@ package electroblob.wizardry.client.particle; -import net.minecraft.client.particle.Particle; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.entity.Entity; import net.minecraft.world.World; @@ -8,20 +7,16 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleDarkMagic extends Particle { +public class ParticleDarkMagic extends ParticleWizardry { /** Base spell texture index */ private int baseSpellTextureIndex = 128; - public ParticleDarkMagic(World par1World, double par2, double par4, double par6, double par8, double par10, - double par12, float r, float g, float b){ - super(par1World, par2, par4, par6, par8, par10, par12); + public ParticleDarkMagic(World world, double x, double y, double z){ + super(world, x, y, z); + this.motionY *= 0.20000000298023224D; - - this.particleRed = r; - this.particleGreen = g; - this.particleBlue = b; - + this.setRBGColorF(1, 1, 1); this.particleScale *= 0.75F; this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D)); this.canCollide = true; @@ -43,9 +38,7 @@ public class ParticleDarkMagic extends Particle { super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); } - /** - * Called to update the entity's position/logic. - */ + @Override public void onUpdate(){ this.prevPosX = this.posX; this.prevPosY = this.posY; diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java b/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java index c37dbb51..3a7f70fd 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java @@ -1,34 +1,25 @@ package electroblob.wizardry.client.particle; -import net.minecraft.client.particle.Particle; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleDust extends Particle { +public class ParticleDust extends ParticleWizardry { - private final boolean shaded; - - public ParticleDust(World par1World, double x, double y, double z, double par8, double par10, double par12, float r, - float g, float b, boolean shaded){ - super(par1World, x, y, z, par8, par10, par12); - this.particleRed = r; - this.particleGreen = g; - this.particleBlue = b; + public ParticleDust(World world, double x, double y, double z){ + super(world, x, y, z); + this.setParticleTextureIndex(0); this.setSize(0.01F, 0.01F); + + // Defaults this.particleScale *= this.rand.nextFloat() + 0.2F; - this.motionX = par8; - this.motionY = par10; - this.motionZ = par12; this.particleMaxAge = (int)(16.0D / (Math.random() * 0.8D + 0.2D)); - this.shaded = shaded; + this.setRBGColorF(1, 1, 1); } - /** - * Called to update the entity's position/logic. - */ + @Override public void onUpdate(){ this.prevPosX = this.posX; this.prevPosY = this.posY; @@ -39,10 +30,4 @@ public class ParticleDust extends Particle { this.setExpired(); } } - - @Override - public int getBrightnessForRender(float par1){ - return shaded ? super.getBrightnessForRender(par1) : 15728880; - } - /* @Override public float getBrightness(float par1) { return shaded ? super.getBrightness(par1) : 1.0F; } */ } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java index dd548900..7c703f7c 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java @@ -9,26 +9,20 @@ import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class ParticleIce extends ParticleCustomTexture { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/ice_particles.png"); + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/ice_particles.png"); - public ParticleIce(World world, double x, double y, double z, double vx, double vy, double vz){ - super(world, x, y, z, vx, vy, vz); - } - - public ParticleIce(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){ - super(world, x, y, z, vx, vy, vz, maxAge); - } - - @Override - public void init(){ + public ParticleIce(World world, double x, double y, double z){ + super(world, x, y, z); + this.setParticleTextureIndex(rand.nextInt(8)); - this.particleScale *= 0.75f; - this.particleGravity = 1; this.canCollide = true; - this.fullBrightness = true; + + // Defaults + this.particleScale *= 0.75f; + this.setGravity(true); + this.shaded = false; } - + @Override public ResourceLocation getTexture(){ return TEXTURE; diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java index e2610a3d..11efd7bb 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java @@ -12,16 +12,10 @@ public class ParticleLeaf extends ParticleCustomTexture { private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/leaf_particles.png"); - public ParticleLeaf(World world, double x, double y, double z, double vx, double vy, double vz){ - super(world, x, y, z, vx, vy, vz); - } - - public ParticleLeaf(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){ - super(world, x, y, z, vx, vy, vz, maxAge); - } - - @Override - public void init(){ + public ParticleLeaf(World world, double x, double y, double z){ + super(world, x, y, z); + this.setVelocity(0, -0.03, 0); + this.setLifetime(10 + rand.nextInt(5)); this.setParticleTextureIndex(rand.nextInt(16)); this.particleScale *= 1.4f; this.particleGravity = 0; diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleMagicFlame.java b/src/main/java/electroblob/wizardry/client/particle/ParticleMagicFlame.java index d16a53b3..8a1051e0 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleMagicFlame.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleMagicFlame.java @@ -8,24 +8,21 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleMagicFlame extends Particle { +public class ParticleMagicFlame extends ParticleWizardry { /** The scale of the flame particle */ private float flameScale; - public ParticleMagicFlame(World par1World, double par2, double par4, double par6, double par8, double par10, - double par12, int maxAge, float scale){ - super(par1World, par2, par4, par6, par8, par10, par12); - this.motionX = this.motionX * 0.009999999776482582D + par8; - this.motionY = this.motionY * 0.009999999776482582D + par10; - this.motionZ = this.motionZ * 0.009999999776482582D + par12; - this.flameScale = scale; - this.particleRed = this.particleGreen = this.particleBlue = 1.0F; - if(maxAge == 0){ - this.particleMaxAge = (int)(2.0D / (Math.random() * 0.8D + 0.2D)); - }else{ - this.particleMaxAge = maxAge; - } + public ParticleMagicFlame(World world, double x, double y, double 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.setRBGColorF(1, 1, 1); + this.particleMaxAge = (int)(2.0D / (Math.random() * 0.8D + 0.2D)); // IDEA: Make the particles for ray spells collide properly and not spawn on the other side of stuff. this.canCollide = false; this.setParticleTextureIndex(48); @@ -43,4 +40,10 @@ public class ParticleMagicFlame extends Particle { public int getBrightnessForRender(float par1){ return 256; } + + @Override + public Particle multipleParticleScaleBy(float scale){ + this.flameScale *= scale; + return super.multipleParticleScaleBy(scale); + } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticlePath.java b/src/main/java/electroblob/wizardry/client/particle/ParticlePath.java index 4db78d66..189cb962 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticlePath.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticlePath.java @@ -19,32 +19,20 @@ public class ParticlePath extends ParticleCustomTexture { private final double originX, originY, originZ; - public ParticlePath(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, - float b){ - super(world, x, y, z, vx, vy, vz); - this.setRBGColorF(r, g, b); + public ParticlePath(World world, double x, double y, double z){ + super(world, x, y, z); + this.originX = x; this.originY = y; this.originZ = z; - } - - public ParticlePath(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, - float b, int maxAge){ - super(world, x, y, z, vx, vy, vz, maxAge); - this.setRBGColorF(r, g, b); - this.originX = x; - this.originY = y; - this.originZ = z; - } - - @Override - public void init(){ + this.setParticleTextureIndex(0); // Set to a constant to remove the randomness from Particle. this.particleScale = 1.25f; this.particleGravity = 0; - this.fullBrightness = true; + this.shaded = false; this.canCollide = false; + this.setRBGColorF(1, 1, 1); } @Override diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java b/src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java index 498bb038..ba804d58 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java @@ -11,16 +11,15 @@ public class ParticleRotatingSparkle extends ParticleSparkle { private double radius; private double speed; - public ParticleRotatingSparkle(World world, int maxAge, double originX, double originZ, double radius, double yPos, - float r, float g, float b){ - super(world, 0, 0, 0, 0, 0, 0, r, g, b, maxAge); + 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 = originX - Math.cos(angle) * radius; - double z = originZ + radius * Math.sin(angle); - this.radius = radius; - this.setPosition(x, yPos, z); + 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 = yPos; + this.prevPosY = y; this.prevPosZ = z; if(rand.nextBoolean()){ speed = rand.nextDouble() * 2 + 1; diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java index e0d5250d..a18ff4d9 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java @@ -12,22 +12,16 @@ public class ParticleSnow extends ParticleCustomTexture { private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/snow_particles.png"); - public ParticleSnow(World world, double x, double y, double z, double vx, double vy, double vz){ - super(world, x, y, z, vx, vy, vz); - } - - public ParticleSnow(World world, double x, double y, double z, double vx, double vy, double vz, int maxAge){ - super(world, x, y, z, vx, vy, vz, maxAge); - } - - @Override - public void init(){ + public ParticleSnow(World world, double x, double y, double z){ + super(world, x, y, z); this.setParticleTextureIndex(rand.nextInt(8)); + this.setVelocity(0, -0.02, 0); this.particleScale *= 0.6f; this.particleGravity = 0; this.canCollide = true; + this.setLifetime(40 + rand.nextInt(10)); } - + @Override public ResourceLocation getTexture(){ return TEXTURE; diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java index 201d2373..a94103f1 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java @@ -16,18 +16,14 @@ public class ParticleSpark extends ParticleCustomTexture { private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/lightning_particles.png"); - public ParticleSpark(World world, double x, double y, double z, double vx, double vy, double vz){ - // Max age is always 3. - super(world, x, y, z, vx, vy, vz, 3); - } - - @Override - public void init(){ + public ParticleSpark(World world, double x, double y, double z){ + super(world, x, y, z); // Multiplied by 4 because the index works slightly differently for spark particles. this.setParticleTextureIndex(rand.nextInt(8) * 4); this.particleScale *= 1.4f; - this.fullBrightness = true; + this.shaded = false; this.canCollide = false; + this.setLifetime(3); // Lifetime defaults to 3 (and is very unlikely to be changed) } @Override diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java index fdbd553c..f63bfcfb 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java @@ -9,66 +9,33 @@ import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class ParticleSparkle extends ParticleCustomTexture { - /* I have now figured out what particle factories are for: they separate out the individual uses of the varargs - * parameter in spawnParticle so they are kept with the particle class. For my purposes, it would be easier to do - * that in the particle spawning method itself. */ - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/sparkle_particles.png"); - // NOTE: Uncomment once 2.1.0 is released - // private final float initialRed; - // private final float initialGreen; - // private final float initialBlue; + // Implementation of colour fading (perhaps these belong in ParticleWizardry?) + private float initialRed; + private float initialGreen; + private float initialBlue; - // TODO: Assign these via the constructors, as part of the refactoring for particle parameters. - // NOTE: Uncomment once 2.1.0 is released - // private final float fadeRed = 1; - // private final float fadeGreen = 1; - // private final float fadeBlue = 0; - - public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, - float b){ - super(world, x, y, z, vx, vy, vz); - this.setRBGColorF(r, g, b); - // NOTE: Uncomment once 2.1.0 is released - // initialRed = r; - // initialGreen = g; - // initialBlue = b; + public ParticleSparkle(World world, double x, double y, double z){ + super(world, x, y, z); + this.setRBGColorF(1, 1, 1); this.particleMaxAge = 48 + this.rand.nextInt(12); - } - - public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, - float b, int maxAge){ - super(world, x, y, z, vx, vy, vz, maxAge); - this.setRBGColorF(r, g, b); - // NOTE: Uncomment once 2.1.0 is released - // initialRed = r; - // initialGreen = g; - // initialBlue = b; - } - - public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, - float b, boolean doGravity){ - this(world, x, y, z, vx, vy, vz, r, g, b); - this.particleGravity = doGravity ? 1 : 0; - } - - public ParticleSparkle(World world, double x, double y, double z, double vx, double vy, double vz, float r, float g, - float b, int maxAge, boolean doGravity){ - this(world, x, y, z, vx, vy, vz, r, g, b, maxAge); - this.particleGravity = doGravity ? 1 : 0; - } - - @Override - public void init(){ - this.setParticleTextureIndex(rand.nextInt(16)); this.particleScale *= 0.75f; this.particleGravity = 0; this.canCollide = false; - this.fullBrightness = true; + 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; @@ -88,17 +55,20 @@ public class ParticleSparkle extends ParticleCustomTexture { public void onUpdate(){ super.onUpdate(); + // Fading if(this.particleAge > this.particleMaxAge / 2){ this.setAlphaF( 1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); } - // Colour fading TODO Uncomment once 2.1.0 is released - // float ageFraction = (float)this.particleAge / (float)this.particleMaxAge; - // this.setRBGColorF(this.initialRed + (this.fadeRed - this.initialRed)*ageFraction, - // this.initialGreen + (this.fadeGreen - this.initialGreen)*ageFraction, - // this.initialBlue + (this.fadeBlue - this.initialBlue)*ageFraction); + // 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); } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java index 50ecabd4..358eb4a6 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java @@ -2,12 +2,12 @@ package electroblob.wizardry.entity.construct; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.potion.PotionEffect; @@ -61,16 +61,23 @@ public class EntityBlizzard extends EntityMagicConstruct { target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 20, 0)); } }else{ - // For some reason this number of particles now causes the game to lag significantly, despite it being fine - // in 1.7.10. I thought particles were supposed to be LESS laggy now... - for(int i = 1; i < 6; i++){ + for(int i=1; i<6; i++){ + float brightness = 0.5f + (rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.BLIZZARD, world, this.posX, - this.posY + rand.nextDouble() * 3, this.posZ, 0, 0, 0, 100, brightness, brightness + 0.1f, 1.0f, - false, rand.nextDouble() * 2.5d + 0.5d); - Wizardry.proxy.spawnParticle(WizardryParticleType.BLIZZARD, world, this.posX, - this.posY + rand.nextDouble() * 3, this.posZ, 0, 0, 0, 100, 1.0f, 1.0f, 1.0f, false, - rand.nextDouble() * 2.5d + 0.5d); + + ParticleBuilder.create(Type.BLIZZARD) + .pos(this.posX, this.posY + rand.nextDouble() * 3, this.posZ) + .lifetime(100) + .colour(brightness, brightness + 0.1f, 1.0f) + .radius(rand.nextDouble() * 2.5d + 0.5d) + .spawn(world); + + ParticleBuilder.create(Type.BLIZZARD) + .pos(this.posX, this.posY + rand.nextDouble() * 3, this.posZ) + .lifetime(100) + .colour(1, 1, 1) + .radius(rand.nextDouble() * 2.5d + 0.5d) + .spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java index a2835764..19b150d6 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java @@ -2,9 +2,9 @@ package electroblob.wizardry.entity.construct; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; @@ -53,12 +53,17 @@ public class EntityDecay extends EntityMagicConstruct { target.addPotionEffect(new PotionEffect(WizardryPotions.decay, LIFETIME, 0)); } } + }else if(this.rand.nextInt(15) == 0){ + double radius = rand.nextDouble() * 0.8; double angle = rand.nextDouble() * Math.PI * 2; float brightness = rand.nextFloat() * 0.4f; - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, this.posX + radius * Math.cos(angle), - this.posY, this.posZ + radius * Math.sin(angle), 0, 0, 0, 0, brightness, 0, brightness + 0.1f); + + ParticleBuilder.create(Type.DARK_MAGIC) + .pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle)) + .colour(brightness, 0, brightness + 0.1f) + .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java index f26c8a95..8717ccaa 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java @@ -2,9 +2,9 @@ package electroblob.wizardry.entity.construct; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -62,15 +62,18 @@ public class EntityForcefield extends EntityMagicConstruct { } }else{ for(int i = 1; i < 40; i++){ + + // Generates a spherical pattern of particles float brightness = 0.5f + (rand.nextFloat() * 0.5f); double radius = 3; double yaw = rand.nextDouble() * Math.PI * 2; double pitch = (rand.nextDouble() - 0.5) * Math.PI; - // Generates a spherical pattern of particles - Wizardry.proxy.spawnParticle(WizardryParticleType.BRIGHT_DUST, world, - 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), 0, 0, 0, 48 + this.rand.nextInt(12), - brightness, brightness, 1.0f); + + ParticleBuilder.create(Type.DUST) + .pos(this.posX + radius * Math.cos(yaw) * Math.cos(pitch), this.posY + 3 + radius * Math.sin(pitch), + this.posZ + radius * Math.sin(yaw) * Math.cos(pitch)) + .lifetime(48 + this.rand.nextInt(12)) + .colour(brightness, brightness, 1.0f); } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java index 7812ca96..cb29f67e 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java @@ -2,12 +2,12 @@ package electroblob.wizardry.entity.construct; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.potion.PotionEffect; @@ -74,8 +74,10 @@ public class EntityFrostSigil extends EntityMagicConstruct { }else if(this.rand.nextInt(15) == 0){ double radius = 0.5 + rand.nextDouble() * 0.3; double angle = rand.nextDouble() * Math.PI * 2; - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, this.posX + radius * Math.cos(angle), - this.posY + 0.1, this.posZ + radius * Math.sin(angle), 0, 0, 0, 40 + rand.nextInt(10)); + ParticleBuilder.create(Type.SNOW) + .pos(this.posX + radius * Math.cos(angle), this.posY + 0.1, this.posZ + radius * Math.sin(angle)) + .vel(0, 0, 0) // Required since default for snow is not stationary + .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java index 13225ca7..a66fb43c 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java @@ -7,7 +7,8 @@ import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -69,8 +70,9 @@ public class EntityHammer extends EntityMagicConstruct { } if(this.world.isRemote && this.ticksExisted % 3 == 0){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, this.posX - 0.5d + rand.nextDouble(), - this.posY + 2 * rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble(), 0, 0, 0, 3); + ParticleBuilder.create(Type.SPARK) + .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + 2 * rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble()) + .spawn(world); } if(!this.world.isRemote){ @@ -109,12 +111,14 @@ public class EntityHammer extends EntityMagicConstruct { target.posY + target.height / 2, target.posZ); world.spawnEntity(arc); }else{ - for(int j = 0; j < 8; j++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, - 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, 0, 0, 0, 3); + // 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); diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java index 25f93849..8ca40faa 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java @@ -2,11 +2,11 @@ package electroblob.wizardry.entity.construct; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.DamageSource; @@ -69,13 +69,16 @@ public class EntityHealAura extends EntityMagicConstruct { } } }else{ - for(int i = 1; i < 3; i++){ + for(int i=1; i<3; i++){ float brightness = 0.5f + (rand.nextFloat() * 0.5f); double radius = rand.nextDouble() * 2.0; double angle = rand.nextDouble() * Math.PI * 2; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, this.posX + radius * Math.cos(angle), - this.posY, this.posZ + radius * Math.sin(angle), 0, 0.05f, 0, 48 + this.rand.nextInt(12), 1.0f, - 1.0f, brightness); + ParticleBuilder.create(Type.SPARKLE) + .pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle)) + .vel(0, 0.05, 0) + .lifetime(48 + this.rand.nextInt(12)) + .colour(1.0f, 1.0f, brightness) + .spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java index 7e427637..0c2bb112 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java @@ -2,12 +2,12 @@ package electroblob.wizardry.entity.construct; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.DamageSource; @@ -44,8 +44,6 @@ public class EntityLightningSigil extends EntityMagicConstruct { this.setDead(); } - // if(!this.world.isRemote){ - List targets = WizardryUtilities.getEntitiesWithinRadius(1.0d, this.posX, this.posY, this.posZ, this.world); @@ -90,11 +88,11 @@ public class EntityLightningSigil extends EntityMagicConstruct { world.spawnEntity(arc); }else{ for(int k = 0; k < 8; k++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, - 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, 3); + 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 @@ -116,13 +114,13 @@ public class EntityLightningSigil extends EntityMagicConstruct { } } } - // } if(this.world.isRemote && this.rand.nextInt(15) == 0){ double radius = 0.5 + rand.nextDouble() * 0.3; double angle = rand.nextDouble() * Math.PI * 2; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, this.posX + radius * Math.cos(angle), - this.posY + 0.1, this.posZ + radius * Math.sin(angle), 0, 0, 0, 3); + ParticleBuilder.create(Type.SPARK) + .pos(this.posX + radius * Math.cos(angle), this.posY + 0.1, this.posZ + radius * Math.sin(angle)) + .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java index 5f8abcb0..908ac574 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java @@ -7,7 +7,8 @@ import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.block.material.Material; @@ -133,24 +134,22 @@ public class EntityTornado extends EntityMagicConstruct { yPos / 3 + 0.5d, 100, block, pos1); Wizardry.proxy.spawnTornadoParticle(world, this.posX, this.posY + yPos, this.posZ, this.velX, this.velZ, yPos / 3 + 0.5d, 100, block, pos1); + + // Sometimes spawns leaf particles if the block is leaves, or snow particles if the block is snow + if(this.rand.nextInt(3) == 0){ - // Sometimes spawns leaf particles if the block is leaves - if(block.getMaterial() == Material.LEAVES && this.rand.nextInt(3) == 0){ + Type type = null; + + if(block.getMaterial() == Material.LEAVES) type = Type.LEAF; + if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW) + type = Type.SNOW; + double yPos1 = rand.nextDouble() * 8; - Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, world, - this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1, - this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), 0, -0.05, 0, - 40 + rand.nextInt(10)); - } - - // Sometimes spawns snow particles if the block is snow - if(block.getMaterial() == Material.SNOW - || block.getMaterial() == Material.CRAFTED_SNOW && this.rand.nextInt(3) == 0){ - double yPos1 = rand.nextDouble() * 8; - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, - this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1, - this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), 0, -0.02, 0, - 40 + rand.nextInt(10)); + ParticleBuilder.create(type) + .pos(this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1, + this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d)) + .lifetime(40 + rand.nextInt(10)) + .spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java index dfe9c44f..5ec8aa58 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java @@ -2,8 +2,8 @@ package electroblob.wizardry.entity.living; import java.lang.ref.WeakReference; -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import io.netty.buffer.ByteBuf; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; @@ -40,10 +40,13 @@ public class EntityDecoy extends EntitySummonedCreature { public void onDespawn(){ super.onDespawn(); for(int i = 0; i < 20; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, - this.posX + (this.rand.nextDouble() - 0.5) * this.width, - this.getEntityBoundingBox().minY + this.rand.nextDouble() * this.height, - this.posZ + (this.rand.nextDouble() - 0.5) * this.width, 0, 0, 0, 40, 0.2f, 1.0f, 0.8f); + ParticleBuilder.create(Type.DUST) + .pos(this.posX + (this.rand.nextDouble() - 0.5) * this.width, this.getEntityBoundingBox().minY + + this.rand.nextDouble() * this.height, this.posZ + (this.rand.nextDouble() - 0.5) * this.width) + .lifetime(40) + .colour(0.2f, 1.0f, 0.8f) + .shaded(true) + .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java index 30cb09d8..eab20b1c 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java @@ -16,8 +16,9 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; @@ -200,20 +201,19 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // deathTime == 0 checks the wizard isn't currently dying }else if(healCooldown == -1 && this.deathTime == 0){ - // Heal particles + // Heal particles TODO: Change this so it uses the heal spell directly if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double d0 = (double)((float)this.posX + rand.nextFloat() * 2 - 1.0F); + for(int i=0; i<10; i++){ + double x = (double)((float)this.posX + rand.nextFloat() * 2 - 1.0F); // Apparently the client side spawns the particles 1 block higher than it should... hence the - // 0.5F. - double d1 = (double)((float)this.posY - 0.5F + rand.nextFloat()); - double d2 = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, - 48 + rand.nextInt(12), 1.0f, 1.0f, 0.3f); + double y = (double)((float)this.posY - 0.5F + rand.nextFloat()); + double z = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1F, 0).colour(1, 1, 0.3f).spawn(world); } }else{ if(this.getHealth() < 10){ - // Wizard heals himself more often if he has low health + // Wizards heal themseselves more often if they have low health this.setHealCooldown(150); }else{ this.setHealCooldown(400); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java index 423b42e0..ebc34fdb 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java @@ -6,7 +6,8 @@ import java.util.UUID; import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.EntityAIAttackMelee; @@ -144,10 +145,12 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature if(this.world.isRemote){ for(int i = 0; i < 30; i++){ float brightness = 0.5f + (rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, this.world, - this.posX - 1 + rand.nextDouble() * 2, this.posY + rand.nextDouble() * 3, - this.posZ - 1 + rand.nextDouble() * 2, 0, -0.02, 0, 12 + rand.nextInt(8), brightness, - brightness + 0.1f, 1.0f); + ParticleBuilder.create(Type.SPARKLE) + .pos(this.posX - 1 + rand.nextDouble() * 2, this.posY + rand.nextDouble() * 3, this.posZ - 1 + rand.nextDouble() * 2) + .vel(0, -0.02, 0) + .lifetime(12 + rand.nextInt(8)) + .colour(brightness, brightness + 0.1f, 1.0f) + .spawn(world); } } } @@ -158,9 +161,9 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature super.onLivingUpdate(); if(this.world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, this.world, this.posX - 1 + rand.nextDouble() * 2, - this.posY + rand.nextDouble() * 3, this.posZ - 1 + rand.nextDouble() * 2, 0, -0.02, 0, - 40 + rand.nextInt(10)); + ParticleBuilder.create(Type.SNOW) + .pos(this.posX - 1 + rand.nextDouble() * 2, this.posY + rand.nextDouble() * 3, this.posZ - 1 + rand.nextDouble() * 2) + .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java index e1d9caa1..e9ad7d34 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java @@ -1,10 +1,10 @@ package electroblob.wizardry.entity.living; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.EntityAILookIdle; @@ -50,9 +50,13 @@ public class EntityIceWraith extends EntityBlazeMinion { if(this.world.isRemote){ for(int i = 0; i < 15; i++){ float brightness = 0.5f + (rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, this.posX - 0.5d + rand.nextDouble(), - this.posY + this.height / 2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble(), 0, - 0.05f, 0, 20 + rand.nextInt(10), brightness, brightness + 0.1f, 1.0f); + ParticleBuilder.create(Type.SPARKLE) + .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + this.height / 2 - 0.5d + rand.nextDouble(), + this.posZ - 0.5d + rand.nextDouble()) + .vel(0, 0.05f, 0) + .lifetime(20 + rand.nextInt(10)) + .colour(brightness, brightness + 0.1f, 1.0f) + .spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java index ba613e14..3c90a171 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java @@ -1,9 +1,9 @@ package electroblob.wizardry.entity.living; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.EntityAILookIdle; @@ -44,9 +44,12 @@ public class EntityLightningWraith extends EntityBlazeMinion { if(this.world.isRemote){ for(int i = 0; i < 15; i++){ float brightness = 0.3f + (rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, this.posX - 0.5d + rand.nextDouble(), - this.posY + this.height / 2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble(), 0, - 0.05f, 0, 20 + rand.nextInt(10), brightness, brightness + 0.2f, 1.0f); + ParticleBuilder.create(Type.SPARKLE) + .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + this.height / 2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble()) + .vel(0, 0.05, 0) + .lifetime(20 + rand.nextInt(10)) + .colour(brightness, brightness + 0.2f, 1.0f) + .spawn(world); } } } @@ -56,10 +59,7 @@ public class EntityLightningWraith extends EntityBlazeMinion { // Fortunately, lightning wraiths don't replace any of blazes' particle effects or the fire sound, they only // add the sparks, so it's fine to call super here. if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, - this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, - this.posY + this.rand.nextDouble() * (double)this.height, - this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0, 3); + ParticleBuilder.create(Type.SPARK, this).spawn(world); } super.onLivingUpdate(); } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java index 48f78093..9b03593b 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java @@ -3,11 +3,11 @@ package electroblob.wizardry.entity.living; import java.util.Collections; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIAttackMelee; @@ -128,9 +128,13 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell if(this.world.isRemote){ for(int i = 0; i < 15; i++){ float brightness = rand.nextFloat() * 0.4f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, this.posX - 0.5d + rand.nextDouble(), - this.posY + this.height / 2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble(), 0, - 0.05f, 0, 20 + rand.nextInt(10), brightness, 0.0f, brightness); + ParticleBuilder.create(Type.SPARKLE) + .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + this.height / 2 - 0.5d + rand.nextDouble(), + this.posZ - 0.5d + rand.nextDouble()) + .vel(0, 0.05, 0) + .lifetime(20 + rand.nextInt(10)) + .colour(brightness, 0.0f, brightness) + .spawn(world); } } } @@ -149,26 +153,25 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell } if(world.isRemote){ - for(int i = 0; i < 2; i++){ + + for(int i=0; i<2; i++){ + world.spawnParticle(EnumParticleTypes.PORTAL, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0); + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0); + float brightness = rand.nextFloat() * 0.2f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, - this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, - this.posY + this.rand.nextDouble() * (double)this.height, - this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0.05f, 0, - 20 + rand.nextInt(10), brightness, 0.0f, brightness); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, - this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, - this.posY + this.rand.nextDouble() * (double)this.height, - this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0.0d, 0.0d, 0.0d, 0, 0.1f, - 0.0f, 0.0f); + + ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) + .colour(brightness, 0.0f, brightness).spawn(world); + + ParticleBuilder.create(Type.DARK_MAGIC, this).colour(0.1f, 0.0f, 0.0f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java index 4cff78eb..a1a79b4d 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java @@ -4,7 +4,8 @@ import java.lang.ref.WeakReference; import java.util.UUID; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.EntityAIAttackMelee; @@ -119,9 +120,10 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone private void spawnParticleEffect(){ if(this.world.isRemote){ for(int i = 0; i < 15; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, this.posX + this.rand.nextFloat(), - this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat(), 0.0d, 0.0d, 0.0d, 0, 0.3f, - 0.3f, 0.3f); + ParticleBuilder.create(Type.DARK_MAGIC) + .pos(this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat()) + .colour(0.3f, 0.3f, 0.3f) + .spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java index ea9d3cb3..4a979455 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java @@ -4,7 +4,8 @@ import java.lang.ref.WeakReference; import java.util.UUID; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; @@ -147,9 +148,10 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre private void spawnParticleEffect(){ if(this.world.isRemote){ for(int i = 0; i < 15; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, this.posX + this.rand.nextFloat(), - this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat(), 0.0d, 0.0d, 0.0d, 0, 0.1f, - 0.2f, 0.0f); + ParticleBuilder.create(Type.DARK_MAGIC) + .pos(this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat()) + .colour(0.1f, 0.2f, 0.0f) + .spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java index 227b713a..82fa9ce4 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java @@ -4,7 +4,8 @@ import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -85,17 +86,15 @@ public class EntitySpiritHorse extends EntityHorse { if(itemstack.getItem() instanceof ItemWand && this.getOwner() == player && player.isSneaking()){ // Prevents accidental double clicking. if(this.ticksExisted > 20){ - for(int i = 0; i < 15; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, - this.posX - this.width / 2 + this.rand.nextFloat() * width, - this.posY + this.height * this.rand.nextFloat() + 0.2f, - this.posZ - this.width / 2 + this.rand.nextFloat() * width, 0, 0, 0, - 48 + this.rand.nextInt(12), 0.8f, 0.8f, 1.0f); - } + + this.spawnAppearParticles(); + this.setDead(); + if(WizardData.get(player) != null){ WizardData.get(player).hasSpiritHorse = false; } + this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); // This is necessary to prevent the wand's spell being cast when performing this action. return true; @@ -105,6 +104,15 @@ public class EntitySpiritHorse extends EntityHorse { return super.processInteract(player, hand); } + + private void spawnAppearParticles(){ + for(int i=0; i<15; i++){ + double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; + double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; + double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).spawn(world); + } + } @Override public void onDeath(DamageSource par1DamageSource){ @@ -137,10 +145,10 @@ public class EntitySpiritHorse extends EntityHorse { // Adds a dust particle effect if(this.world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, - this.posX - this.width / 2 + this.rand.nextFloat() * width, - this.posY + this.height * this.rand.nextFloat() + 0.2f, - this.posZ - this.width / 2 + this.rand.nextFloat() * width, 0, 0, 0, 0, 0.8f, 0.8f, 1.0f); + double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; + double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; + double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; + ParticleBuilder.create(Type.DUST).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); } // Spirit horse disappears a short time after being dismounted. @@ -151,20 +159,17 @@ public class EntitySpiritHorse extends EntityHorse { } if(this.idleTimer > 200){ + if(this.world.isRemote){ - for(int i = 0; i < 15; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, - this.posX - this.width / 2 + this.rand.nextFloat() * width, - this.posY + this.height * this.rand.nextFloat() + 0.2f, - this.posZ - this.width / 2 + this.rand.nextFloat() * width, 0, 0, 0, - 48 + this.rand.nextInt(12), 0.8f, 0.8f, 1.0f); - } + this.spawnAppearParticles(); } + this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); // Allows player to summon another spirit horse once this one has disappeared. if(this.getOwner() instanceof EntityPlayer && WizardData.get((EntityPlayer)this.getOwner()) != null){ WizardData.get((EntityPlayer)this.getOwner()).hasSpiritHorse = false; } + this.setDead(); } } @@ -179,13 +184,7 @@ public class EntitySpiritHorse extends EntityHorse { // Adds Particles on spawn. Due to client/server differences this cannot be done in the item. if(this.world.isRemote){ - for(int i = 0; i < 15; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, - this.posX - this.width / 2 + this.rand.nextFloat() * width, - this.posY + this.height * this.rand.nextFloat() + 0.2f, - this.posZ - this.width / 2 + this.rand.nextFloat() * width, 0, 0, 0, 48 + this.rand.nextInt(12), - 0.8f, 0.8f, 1.0f); - } + this.spawnAppearParticles(); } return super.onInitialSpawn(difficulty, data); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java index 9fd953d3..abc4dc07 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java @@ -4,7 +4,8 @@ import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.IEntityLivingData; import net.minecraft.entity.ai.EntityAIAttackMelee; @@ -81,18 +82,21 @@ public class EntitySpiritWolf extends EntityWolf { // Adds Particles on spawn. Due to client/server differences this cannot be done // in the item. if(this.world.isRemote){ - for(int i = 0; i < 15; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, - this.posX - this.width / 2 + this.rand.nextFloat() * width, - this.posY + this.height * this.rand.nextFloat() + 0.2f, - this.posZ - this.width / 2 + this.rand.nextFloat() * width, 0, 0, 0, 48 + this.rand.nextInt(12), - 0.8f, 0.8f, 1.0f); - } + this.spawnAppearParticles(); } return livingdata; } + private void spawnAppearParticles(){ + for(int i=0; i<15; i++){ + double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; + double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; + double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).spawn(world); + } + } + @Override public void onUpdate(){ @@ -100,10 +104,10 @@ public class EntitySpiritWolf extends EntityWolf { // Adds a dust particle effect if(this.world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, - this.posX - this.width / 2 + this.rand.nextFloat() * width, - this.posY + this.height * this.rand.nextFloat() + 0.2f, - this.posZ - this.width / 2 + this.rand.nextFloat() * width, 0, 0, 0, 0, 0.8f, 0.8f, 1.0f); + double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; + double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; + double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; + ParticleBuilder.create(Type.DUST).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); } } @@ -119,17 +123,17 @@ public class EntitySpiritWolf extends EntityWolf { if(stack.getItem() instanceof ItemWand && this.getOwner() == player && player.isSneaking()){ // Prevents accidental double clicking. if(this.ticksExisted > 20){ - for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, - this.posX - this.width / 2 + this.rand.nextFloat() * width, - this.posY + this.height * this.rand.nextFloat() + 0.2f, - this.posZ - this.width / 2 + this.rand.nextFloat() * width, 0, 0, 0, - 48 + this.rand.nextInt(12), 0.8f, 0.8f, 1.0f); + + if(this.world.isRemote){ + this.spawnAppearParticles(); } + this.setDead(); + if(WizardData.get(player) != null){ WizardData.get(player).hasSpiritWolf = false; } + this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); // This is necessary to prevent the wand's spell being cast when performing this // action. diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java index 29e2c061..6991713a 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java @@ -3,12 +3,12 @@ package electroblob.wizardry.entity.living; import java.util.Collections; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIAttackMelee; @@ -135,22 +135,23 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe if(world.isRemote){ - for(int i = 0; i < 2; ++i){ + for(int i=0; i<2; ++i){ + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, - this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, - this.posY + this.rand.nextDouble() * (double)this.height, - this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0.0d, 0.0d, 0.0d, 0, 0, 0, 0); + + ParticleBuilder.create(Type.SPARK, this).spawn(world); } - for(int i = 0; i < 10; i++){ + for(int i=0; i<10; i++){ + float brightness = rand.nextFloat() * 0.2f; double dy = this.rand.nextDouble() * (double)this.height; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE_ROTATING, world, this.posX, this.posY + dy, - this.posZ, 0, 0, 0, 20 + rand.nextInt(10), 0, brightness, brightness, false, 0.2f + 0.5f * dy); + + ParticleBuilder.create(Type.SPARKLE_ROTATING).pos(this.posX, this.posY + dy, this.posZ) + .lifetime(20 + rand.nextInt(10)).colour(0, brightness, brightness).radius(0.2f + 0.5f * dy).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index b34c5a5f..b686924c 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -21,10 +21,11 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WandHelper; import electroblob.wizardry.util.WildcardTradeList; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; @@ -245,20 +246,19 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit // deathTime == 0 checks the wizard isn't currently dying }else if(healCooldown == -1 && this.deathTime == 0){ - // Heal particles + // Heal particles TODO: Change this so it uses the heal spell directly if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double d0 = (double)((float)this.posX + rand.nextFloat() * 2 - 1.0F); + for(int i=0; i<10; i++){ + double x = (double)((float)this.posX + rand.nextFloat() * 2 - 1.0F); // Apparently the client side spawns the particles 1 block higher than it should... hence the - // 0.5F. - double d1 = (double)((float)this.posY - 0.5F + rand.nextFloat()); - double d2 = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, - 48 + rand.nextInt(12), 1.0f, 1.0f, 0.3f); + double y = (double)((float)this.posY - 0.5F + rand.nextFloat()); + double z = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1F, 0).colour(1, 1, 0.3f).spawn(world); } }else{ if(this.getHealth() < 10){ - // Wizard heals himself more often if he has low health + // Wizards heal themseselves more often if they have low health this.setHealCooldown(150); }else{ this.setHealCooldown(400); diff --git a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java index e441ae67..85b4bdaf 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java @@ -16,7 +16,8 @@ import electroblob.wizardry.util.IElementalDamage; import electroblob.wizardry.util.IndirectMinionDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.MinionDamage; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; @@ -288,9 +289,10 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { } if(this.hasParticleEffect() && thisEntity.world.isRemote && thisEntity.world.rand.nextInt(8) == 0) - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, thisEntity.world, thisEntity.posX, - thisEntity.posY + thisEntity.world.rand.nextDouble() * 1.5, thisEntity.posZ, 0.0d, 0.0d, 0.0d, 0, - 0.1f, 0.0f, 0.0f); + ParticleBuilder.create(Type.DARK_MAGIC) + .pos(thisEntity.posX, thisEntity.posY + thisEntity.world.rand.nextDouble() * 1.5, thisEntity.posZ) + .colour(0.1f, 0.0f, 0.0f) + .spawn(thisEntity.world); } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java index 90292a5f..6fb6f290 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java @@ -1,9 +1,9 @@ package electroblob.wizardry.entity.projectile; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; @@ -13,6 +13,7 @@ import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; public class EntityDarknessOrb extends EntityMagicProjectile { + public EntityDarknessOrb(World par1World){ super(par1World); } @@ -59,17 +60,13 @@ public class EntityDarknessOrb extends EntityMagicProjectile { super.onUpdate(); if(world.isRemote){ + float brightness = rand.nextFloat() * 0.2f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, - this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, - this.posY + this.rand.nextDouble() * (double)this.height, - this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0, 0, 0, 20 + rand.nextInt(10), - brightness, 0.0f, brightness); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, - this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, - this.posY + this.rand.nextDouble() * (double)this.height, - this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, - 0.0f); + + ParticleBuilder.create(Type.SPARKLE, this).lifetime(20 + rand.nextInt(10)) + .colour(brightness, 0.0f, brightness).spawn(world); + + ParticleBuilder.create(Type.DARK_MAGIC, this).colour(0.1f, 0.0f, 0.0f).spawn(world); } if(this.ticksExisted > 150){ diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java index 0d51c5df..7208a8f0 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java @@ -1,8 +1,8 @@ package electroblob.wizardry.entity.projectile; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; @@ -56,10 +56,8 @@ public class EntityDart extends EntityMagicArrow { @Override public void tickInAir(){ - if(this.world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, world, this.posX, this.posY, this.posZ, 0, -0.03, 0, - 10 + rand.nextInt(5)); + ParticleBuilder.create(Type.LEAF).pos(this.posX, this.posY, this.posZ).lifetime(10 + rand.nextInt(5)); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java index 296af6ff..b181ab2b 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java @@ -2,10 +2,10 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -33,10 +33,9 @@ public class EntityFirebomb extends EntityBomb { super(par1World, par2, par4, par6); } - /** - * Called when this EntityThrowable hits a block or entity. - */ + @Override protected void onImpact(RayTraceResult par1RayTraceResult){ + Entity entityHit = par1RayTraceResult.entityHit; if(entityHit != null){ @@ -52,21 +51,16 @@ public class EntityFirebomb extends EntityBomb { // Particle effect if(world.isRemote){ + this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); + for(int i = 0; i < 60 * blastMultiplier; i++){ - // this.world.spawnParticle(EnumParticleTypes.FLAME, this.posX + (this.rand.nextDouble()*4 - - // 2)*blastMultiplier, this.posY + (this.rand.nextDouble()*4 - 2)*blastMultiplier, this.posZ + - // (this.rand.nextDouble()*4 - 2)*blastMultiplier, 0, 0, 0); - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_FIRE, world, - this.posX + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posY + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posZ + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, 0, 0, 0, 15 + rand.nextInt(5), - 2 + rand.nextFloat(), 0, 0); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, - this.posX + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posY + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posZ + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, 0.0d, 0.0d, 0.0d, 0, 1.0f, - 0.2f + rand.nextFloat() * 0.4f, 0.0f); + + ParticleBuilder.create(Type.MAGIC_FIRE, rand, posX, posY, posZ, 2*blastMultiplier, false) + .lifetime(15 + rand.nextInt(5)).scale(2 + rand.nextFloat()).spawn(world); + + ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) + .colour(1.0f, 0.2f + rand.nextFloat() * 0.4f, 0.0f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java index 825db7fc..d7edcb12 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java @@ -2,10 +2,10 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; @@ -54,11 +54,8 @@ public class EntityForceOrb extends EntityMagicProjectile { if(this.world.isRemote){ for(int j = 0; j < 20; j++){ float brightness = 0.5f + (rand.nextFloat() / 2); - double x = this.posX - 0.25d + (rand.nextDouble() / 2); - double y = this.posY - 0.25d + (rand.nextDouble() / 2); - double z = this.posZ - 0.25d + (rand.nextDouble() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x, y, z, (x - this.posX) * 2, - (y - this.posY) * 2, (z - this.posZ) * 2, 6, brightness, 1.0f, brightness + 0.2f); + ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.25, true).lifetime(6) + .colour(brightness, 1.0f, brightness + 0.2f).spawn(world); } this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java index 3288e4fa..a6768266 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java @@ -2,12 +2,12 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -60,16 +60,13 @@ public class EntityIceCharge extends EntityBomb { if(world.isRemote){ this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); for(int i = 0; i < 30 * blastMultiplier; i++){ + + ParticleBuilder.create(Type.ICE, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) + .lifetime(35).spawn(world); + float brightness = 0.4f + rand.nextFloat() * 0.5f; - Wizardry.proxy.spawnParticle(WizardryParticleType.ICE, world, - this.posX + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posY + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posZ + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, 0.0d, 0.0d, 0.0d, 35); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, - this.posX + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posY + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posZ + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, 0.0d, 0.0d, 0.0d, 0, brightness, - brightness + 0.1f, 1.0f); + ParticleBuilder.create(Type.DARK_MAGIC, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) + .colour(brightness, brightness + 0.1f, 1.0f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java index afbfa94c..f8cb6ee3 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java @@ -1,10 +1,10 @@ package electroblob.wizardry.entity.projectile; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; @@ -68,11 +68,8 @@ public class EntityIceLance extends EntityMagicArrow { // Adds a particle effect when the ice lance hits a block. if(this.world.isRemote){ for(int j = 0; j < 10; j++){ - double x = this.posX - 0.25d + (rand.nextDouble() / 2); - double y = this.posY - 0.25d + (rand.nextDouble() / 2); - double z = this.posZ - 0.25d + (rand.nextDouble() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.ICE, world, x, y, z, x - this.posX, y - this.posY, - z - this.posZ, 20 + rand.nextInt(10)); + ParticleBuilder.create(Type.ICE, this.rand, this.posX, this.posY, this.posZ, 0.5, true) + .lifetime(20 + rand.nextInt(10)).spawn(world); } } // Parameters for sound: sound event name, volume, pitch. diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java index 2d5e2f39..19e72bb6 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java @@ -1,10 +1,10 @@ package electroblob.wizardry.entity.projectile; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; @@ -64,11 +64,8 @@ public class EntityIceShard extends EntityMagicArrow { // Adds a particle effect when the ice shard hits a block. if(this.world.isRemote){ for(int j = 0; j < 10; j++){ - double x = this.posX - 0.25d + (rand.nextDouble() / 2); - double y = this.posY - 0.25d + (rand.nextDouble() / 2); - double z = this.posZ - 0.25d + (rand.nextDouble() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.ICE, world, x, y, z, x - this.posX, y - this.posY, - z - this.posZ, 20 + rand.nextInt(10)); + ParticleBuilder.create(Type.ICE, this.rand, this.posX, this.posY, this.posZ, 0.5, true) + .lifetime(20 + rand.nextInt(10)).spawn(world); } } // Parameters for sound: sound event name, volume, pitch. diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java index f19c4dc2..4da5d2d0 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java @@ -1,9 +1,9 @@ package electroblob.wizardry.entity.projectile; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; @@ -46,15 +46,10 @@ public class EntityLightningArrow extends EntityMagicArrow { if(world.isRemote){ for(int j = 0; j < 8; j++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, this.posX + rand.nextFloat() - 0.5, - this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, - 0, 3); + ParticleBuilder.create(Type.SPARK, rand, posX, posY + height / 2, posZ, 1, false).spawn(world); } } - /* Pretty sure this needn't be here, probably missed it when I implemented the damage type system. if(entityHit - * instanceof EntityCreeper && !((EntityCreeper)entityHit).getPowered()){ - * entityHit.getDataWatcher().updateObject(17, Byte.valueOf((byte)1)); if(this.getShootingEntity() instanceof - * EntityPlayer) ((EntityPlayer)this.getShootingEntity()).addStat(Wizardry.chargeCreeper); } */ + this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.0F); } @@ -66,8 +61,7 @@ public class EntityLightningArrow extends EntityMagicArrow { } if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, this.posX, this.posY, this.posZ, 0, 0, 0, - 3); + ParticleBuilder.create(Type.SPARK).pos(posX, posY, posZ).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java index 6340f99f..988fd2ba 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java @@ -2,11 +2,11 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -14,6 +14,7 @@ import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; public class EntityLightningDisc extends EntityMagicProjectile { + public EntityLightningDisc(World par1World){ super(par1World); } @@ -38,8 +39,9 @@ public class EntityLightningDisc extends EntityMagicProjectile { } @Override - protected void onImpact(RayTraceResult mop){ - Entity entityHit = mop.entityHit; + protected void onImpact(RayTraceResult result){ + + Entity entityHit = result.entityHit; if(entityHit != null){ float damage = 12 * damageMultiplier; @@ -50,7 +52,7 @@ public class EntityLightningDisc extends EntityMagicProjectile { this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); - if(mop.typeOfHit == RayTraceResult.Type.BLOCK) this.setDead(); + if(result.typeOfHit == RayTraceResult.Type.BLOCK) this.setDead(); } @Override @@ -61,10 +63,9 @@ public class EntityLightningDisc extends EntityMagicProjectile { // Particle effect if(world.isRemote){ for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, this.posX + rand.nextFloat() * 2 - 1, - this.posY, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0, 3); - // world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + rand.nextFloat() - 0.5, this.posY + - // this.height/2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0); + // TODO: Why are the x and z parameters different? + ParticleBuilder.create(Type.SPARK).pos(this.posX + rand.nextFloat() * 2 - 1, + this.posY, this.posZ + rand.nextFloat() - 0.5).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java index 41351d98..9acce846 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java @@ -1,7 +1,7 @@ package electroblob.wizardry.entity.projectile; -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; @@ -53,16 +53,8 @@ public class EntityMagicMissile extends EntityMagicArrow { } if(this.world.isRemote){ - - if(this.ticksExisted % 2 == 1){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, this.posX, this.posY, this.posZ, 0, 0, - 0, 20 + rand.nextInt(10), 0.5f + (rand.nextFloat() / 2), 0.5f + (rand.nextFloat() / 2), - 0.5f + (rand.nextFloat() / 2)); - }else{ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, this.posX, this.posY, this.posZ, 0, 0, - 0, 20 + rand.nextInt(10), 0.5f + (rand.nextFloat() / 2), 0.5f + (rand.nextFloat() / 2), - 0.5f + (rand.nextFloat() / 2)); - } + ParticleBuilder.create(Type.SPARKLE).pos(this.posX, this.posY, this.posZ).lifetime(20 + rand.nextInt(10)) + .colour(0.5f + (rand.nextFloat() / 2), 0.5f + (rand.nextFloat() / 2), 0.5f + (rand.nextFloat() / 2)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java index af033b37..94f739f8 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java @@ -2,10 +2,10 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -54,16 +54,12 @@ public class EntityPoisonBomb extends EntityBomb { // Particle effect if(world.isRemote){ for(int i = 0; i < 60 * blastMultiplier; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, - this.posX + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posY + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posZ + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, 0.0d, 0.0d, 0.0d, 35, - 0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, - this.posX + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posY + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posZ + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, 0.0d, 0.0d, 0.0d, 0, - 0.2f + rand.nextFloat() * 0.2f, 0.8f, 0.0f); + + ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).lifetime(35) + .colour(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); + + ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) + .colour(0.2f + rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world); } // Spawning this after the other particles fixes the rendering colour bug. It's a bit of a cheat, but it // works pretty well. diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java index d2491481..5d6a432d 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java @@ -2,9 +2,9 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -42,16 +42,15 @@ public class EntitySmokeBomb extends EntityBomb { if(world.isRemote){ this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); for(int i = 0; i < 60 * blastMultiplier; i++){ + this.world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, this.posY + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, this.posZ + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, 0, 0, 0); + float brightness = rand.nextFloat() * 0.3f; - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, - this.posX + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posY + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, - this.posZ + (this.rand.nextDouble() * 4 - 2) * blastMultiplier, 0.0d, 0.0d, 0.0d, 0, brightness, - brightness, brightness); + ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) + .colour(brightness, brightness, brightness).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java index d05d4878..8415bbee 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java @@ -2,11 +2,11 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -55,9 +55,10 @@ public class EntitySpark extends EntityMagicProjectile { // Particle effect if(world.isRemote){ for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, this.posX + rand.nextFloat() - 0.5, - this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, - 0, 3); + double x = this.posX + rand.nextDouble() - 0.5; + double y = this.posY + this.height / 2 + rand.nextDouble() - 0.5; + double z = this.posZ + rand.nextDouble() - 0.5; + ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java index e854cea2..d6cac02d 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java @@ -2,12 +2,12 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; @@ -63,9 +63,10 @@ public class EntitySparkBomb extends EntityBomb { // Particle effect if(world.isRemote){ for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, this.posX + rand.nextFloat() - 0.5, - this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, - 0, 3); + double x = this.posX + rand.nextDouble() - 0.5; + double y = this.posY + this.height / 2 + rand.nextDouble() - 0.5; + double z = this.posZ + rand.nextDouble() - 0.5; + ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + rand.nextFloat() - 0.5, this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0); @@ -106,10 +107,10 @@ public class EntitySparkBomb extends EntityBomb { }else{ // Particle effect for(int j = 0; j < 8; j++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, - target.posX + rand.nextFloat() - 0.5, - target.getEntityBoundingBox().minY + target.height * rand.nextFloat(), - target.posZ + rand.nextFloat() - 0.5, 0, 0, 0, 3); + double x = target.posX + rand.nextFloat() - 0.5; + double y = target.getEntityBoundingBox().minY + target.height * rand.nextFloat(); + double z = target.posZ + rand.nextFloat() - 0.5; + ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, target.posX + rand.nextFloat() - 0.5, target.getEntityBoundingBox().minY + target.height * rand.nextFloat(), target.posZ + rand.nextFloat() - 0.5, 0, 0, 0); diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java index 48e2a4d0..d38bcfce 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java @@ -1,9 +1,9 @@ package electroblob.wizardry.entity.projectile; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; @@ -68,9 +68,7 @@ public class EntityThunderbolt extends EntityMagicProjectile { super.onUpdate(); if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, this.posX + rand.nextFloat() * 0.2 - 0.1, - this.posY + this.height / 2 + rand.nextFloat() * 0.2 - 0.1, - this.posZ + rand.nextFloat() * 0.2 - 0.1, 0, 0, 0, 3); + ParticleBuilder.create(Type.SPARK, rand, posX, posY + height/2, posZ, 0.1, false).spawn(world); for(int i = 0; i < 4; i++){ world.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, this.posX + rand.nextFloat() * 0.2 - 0.1, this.posY + this.height / 2 + rand.nextFloat() * 0.2 - 0.1, diff --git a/src/main/java/electroblob/wizardry/potion/PotionFrost.java b/src/main/java/electroblob/wizardry/potion/PotionFrost.java index 6f267755..7cb709e2 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionFrost.java +++ b/src/main/java/electroblob/wizardry/potion/PotionFrost.java @@ -3,7 +3,8 @@ package electroblob.wizardry.potion; import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; @@ -39,8 +40,7 @@ public class PotionFrost extends Potion implements ICustomPotionParticles { @Override public void spawnCustomParticle(World world, double x, double y, double z){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, x, y, z, 0, -0.02, 0, - 15 + world.rand.nextInt(5)); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).lifetime(15 + world.rand.nextInt(5)).spawn(world); } @Override diff --git a/src/main/java/electroblob/wizardry/registry/WizardryPotions.java b/src/main/java/electroblob/wizardry/registry/WizardryPotions.java index 681c26f7..60f43f9d 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryPotions.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryPotions.java @@ -5,7 +5,8 @@ import electroblob.wizardry.potion.PotionDecay; import electroblob.wizardry.potion.PotionFrost; import electroblob.wizardry.potion.PotionMagicEffect; import electroblob.wizardry.potion.PotionMagicEffectParticles; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.potion.Potion; import net.minecraft.util.EnumParticleTypes; @@ -36,8 +37,7 @@ public final class WizardryPotions { public static final Potion transience = new PotionMagicEffectParticles(false, 0, 0){ @Override public void spawnCustomParticle(World world, double x, double y, double z){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DUST, world, x, y, z, 0, 0, 0, - (int)(16.0D / (Math.random() * 0.8D + 0.2D)), 0.8f, 0.8f, 1.0f); + ParticleBuilder.create(Type.DUST).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); } }.setBeneficial(); // 0xffe89b @@ -58,17 +58,15 @@ public final class WizardryPotions { @Override public void spawnCustomParticle(World world, double x, double y, double z){ float brightness = 0.5f + (world.rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x, y, z, 0, 0, 0, - 48 + world.rand.nextInt(12), brightness, brightness + 0.1f, 1.0f, true, 0); - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, x, y, z, 0, -0.02, 0, - 40 + world.rand.nextInt(10)); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).colour(brightness, brightness + 0.1f, 1.0f).gravity(true).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).spawn(world); } }.setBeneficial(); // 0x52f1ff public static final Potion static_aura = new PotionMagicEffectParticles(false, 0, 3){ @Override public void spawnCustomParticle(World world, double x, double y, double z){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, x, y, z, 0, 0, 0, 3); + ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); } }.setBeneficial(); // 0x0070ff diff --git a/src/main/java/electroblob/wizardry/spell/Agility.java b/src/main/java/electroblob/wizardry/spell/Agility.java index cdd36fb3..4f6b0587 100644 --- a/src/main/java/electroblob/wizardry/spell/Agility.java +++ b/src/main/java/electroblob/wizardry/spell/Agility.java @@ -6,8 +6,9 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -31,13 +32,13 @@ public class Agility extends Spell { caster.addPotionEffect(new PotionEffect(MobEffects.JUMP_BOOST, (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); + if(world.isRemote){ + for(int i = 0; i < 10; i++){ + double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); + double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); + ParticleBuilder.create(Type.SPARKLE).pos(x1, y1, z1).vel(0, 0.1F, 0) + .lifetime(48 + world.rand.nextInt(12)).colour(0.4f, 1.0f, 0.8f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Arc.java b/src/main/java/electroblob/wizardry/spell/Arc.java index d2065b15..56335ed2 100644 --- a/src/main/java/electroblob/wizardry/spell/Arc.java +++ b/src/main/java/electroblob/wizardry/spell/Arc.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; @@ -48,7 +48,7 @@ public class Arc extends Spell { world.spawnEntity(arc); }else{ for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, 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, 0, 0, 0, 3); @@ -88,7 +88,7 @@ public class Arc extends Spell { world.spawnEntity(arc); }else{ for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, 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, 0, 0, 0, 3); diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java index 102fa9c5..6316b0f1 100644 --- a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java +++ b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java @@ -11,7 +11,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -56,7 +56,7 @@ public class ArcaneJammer extends Spell { double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.9f, 0.3f, 0.7f); } } @@ -89,7 +89,7 @@ public class ArcaneJammer extends Spell { - 0.1f; double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.9f, 0.3f, 0.7f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Banish.java b/src/main/java/electroblob/wizardry/spell/Banish.java index 5d49397c..01b01c73 100644 --- a/src/main/java/electroblob/wizardry/spell/Banish.java +++ b/src/main/java/electroblob/wizardry/spell/Banish.java @@ -6,7 +6,7 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -87,7 +87,7 @@ public class Banish extends Spell { double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.2f, 0.0f, 0.2f); } } @@ -125,7 +125,7 @@ public class Banish extends Spell { double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.2f, 0.0f, 0.2f); } diff --git a/src/main/java/electroblob/wizardry/spell/Bubble.java b/src/main/java/electroblob/wizardry/spell/Bubble.java index 3886ee36..7a9c5ff2 100644 --- a/src/main/java/electroblob/wizardry/spell/Bubble.java +++ b/src/main/java/electroblob/wizardry/spell/Bubble.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -59,7 +59,7 @@ public class Bubble extends Spell { double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; world.spawnParticle(EnumParticleTypes.WATER_SPLASH, x1, y1, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_BUBBLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0); + Wizardry.proxy.spawnParticle(Type.MAGIC_BUBBLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0); } } caster.swingArm(hand); @@ -102,7 +102,7 @@ public class Bubble extends Spell { double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; world.spawnParticle(EnumParticleTypes.WATER_SPLASH, x1, y1, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_BUBBLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.MAGIC_BUBBLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0); } } diff --git a/src/main/java/electroblob/wizardry/spell/ChainLightning.java b/src/main/java/electroblob/wizardry/spell/ChainLightning.java index fcaea29f..78422b25 100644 --- a/src/main/java/electroblob/wizardry/spell/ChainLightning.java +++ b/src/main/java/electroblob/wizardry/spell/ChainLightning.java @@ -12,7 +12,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -55,7 +55,7 @@ public class ChainLightning extends Spell { world.spawnEntity(arc); }else{ for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, 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, 0, 0, 0, 3); @@ -97,7 +97,7 @@ public class ChainLightning extends Spell { world.spawnEntity(arc); }else{ for(int j = 0; j < 8; j++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, secondaryTarget.posX + world.rand.nextFloat() - 0.5, secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2 + world.rand.nextFloat() * 2 - 1, @@ -144,7 +144,7 @@ public class ChainLightning extends Spell { world.spawnEntity(arc); }else{ for(int k = 0; k < 8; k++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, tertiaryTarget.posX + world.rand.nextFloat() - 0.5, tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2 + world.rand.nextFloat() * 2 - 1, diff --git a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java index 8b6fa959..5f648b1c 100644 --- a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java +++ b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java @@ -13,7 +13,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryPathFinder; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.SharedMonsterAttributes; @@ -123,7 +123,7 @@ public class Clairvoyance extends Spell { nextPoint = path.getCurrentPathLength() - path.getCurrentPathIndex() <= 2 ? path.getFinalPathPoint() : path.getPathPointFromIndex(path.getCurrentPathIndex() + 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.PATH, world, point.x + 0.5, point.y + 0.5, point.z + 0.5, + Wizardry.proxy.spawnParticle(Type.PATH, world, point.x + 0.5, point.y + 0.5, point.z + 0.5, (nextPoint.x - point.x) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.y - point.y) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.z - point.z) / (float)PARTICLE_MOVEMENT_INTERVAL, (int)(1800 * durationMultiplier), 0, 1, 0.3f); @@ -133,7 +133,7 @@ public class Clairvoyance extends Spell { point = path.getFinalPathPoint(); - Wizardry.proxy.spawnParticle(WizardryParticleType.PATH, world, point.x + 0.5, point.y + 0.5, point.z + 0.5, 0, 0, 0, + Wizardry.proxy.spawnParticle(Type.PATH, world, point.x + 0.5, point.y + 0.5, point.z + 0.5, 0, 0, 0, (int)(1800 * durationMultiplier), 1, 1, 1); } diff --git a/src/main/java/electroblob/wizardry/spell/ConjureArmour.java b/src/main/java/electroblob/wizardry/spell/ConjureArmour.java index 74f5e238..7a9f14a1 100644 --- a/src/main/java/electroblob/wizardry/spell/ConjureArmour.java +++ b/src/main/java/electroblob/wizardry/spell/ConjureArmour.java @@ -8,7 +8,7 @@ import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; @@ -54,7 +54,7 @@ public class ConjureArmour extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.7f, 0.9f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/ConjureBow.java b/src/main/java/electroblob/wizardry/spell/ConjureBow.java index c03f2d2a..488327bd 100644 --- a/src/main/java/electroblob/wizardry/spell/ConjureBow.java +++ b/src/main/java/electroblob/wizardry/spell/ConjureBow.java @@ -8,7 +8,7 @@ import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -36,7 +36,7 @@ public class ConjureBow extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.7f, 0.9f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java b/src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java index ae4a192c..9e51ef3a 100644 --- a/src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java +++ b/src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java @@ -8,7 +8,7 @@ import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -37,7 +37,7 @@ public class ConjurePickaxe extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.7f, 0.9f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/ConjureSword.java b/src/main/java/electroblob/wizardry/spell/ConjureSword.java index cefd59c9..a9876cfa 100644 --- a/src/main/java/electroblob/wizardry/spell/ConjureSword.java +++ b/src/main/java/electroblob/wizardry/spell/ConjureSword.java @@ -8,7 +8,7 @@ import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -36,7 +36,7 @@ public class ConjureSword extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.7f, 0.9f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/CureEffects.java b/src/main/java/electroblob/wizardry/spell/CureEffects.java index 82051fb3..6597a7a6 100644 --- a/src/main/java/electroblob/wizardry/spell/CureEffects.java +++ b/src/main/java/electroblob/wizardry/spell/CureEffects.java @@ -6,7 +6,7 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -29,7 +29,7 @@ public class CureEffects extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); } } @@ -58,7 +58,7 @@ public class CureEffects extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java index e2494bce..8baa67aa 100644 --- a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java +++ b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java @@ -8,7 +8,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.IElementalDamage; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -52,11 +52,11 @@ public class CurseOfSoulbinding extends Spell { + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.4f, 0.0f, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 1.0f, 0.8f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Darkvision.java b/src/main/java/electroblob/wizardry/spell/Darkvision.java index d9e8d7c1..40b829e8 100644 --- a/src/main/java/electroblob/wizardry/spell/Darkvision.java +++ b/src/main/java/electroblob/wizardry/spell/Darkvision.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -33,7 +33,7 @@ public class Darkvision extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.0f, 0.4f, 0.7f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Diamondflesh.java b/src/main/java/electroblob/wizardry/spell/Diamondflesh.java index 32175e6a..848f4a68 100644 --- a/src/main/java/electroblob/wizardry/spell/Diamondflesh.java +++ b/src/main/java/electroblob/wizardry/spell/Diamondflesh.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -33,13 +33,13 @@ public class Diamondflesh extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.0f, 0.5f, 1.0f); x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.7f, 0.9f); } diff --git a/src/main/java/electroblob/wizardry/spell/Entrapment.java b/src/main/java/electroblob/wizardry/spell/Entrapment.java index 44436b4b..db7503a0 100644 --- a/src/main/java/electroblob/wizardry/spell/Entrapment.java +++ b/src/main/java/electroblob/wizardry/spell/Entrapment.java @@ -9,7 +9,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -57,7 +57,7 @@ public class Entrapment extends Spell { double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); } } @@ -99,7 +99,7 @@ public class Entrapment extends Spell { double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/FireResistance.java b/src/main/java/electroblob/wizardry/spell/FireResistance.java index d4c85af3..42596b3b 100644 --- a/src/main/java/electroblob/wizardry/spell/FireResistance.java +++ b/src/main/java/electroblob/wizardry/spell/FireResistance.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -35,7 +35,7 @@ public class FireResistance extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 0.5f, 0.0f); } } @@ -59,7 +59,7 @@ public class FireResistance extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 0.5f, 0.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Firestorm.java b/src/main/java/electroblob/wizardry/spell/Firestorm.java index 4717aab2..baf1d219 100644 --- a/src/main/java/electroblob/wizardry/spell/Firestorm.java +++ b/src/main/java/electroblob/wizardry/spell/Firestorm.java @@ -9,7 +9,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -70,11 +70,11 @@ public class Firestorm extends Spell { double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 + world.rand.nextFloat() * 0.4f - 0.2f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() * 0.6f - 0.3f; - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_FIRE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, look.x * modifiers.get(WizardryItems.range_upgrade), look.y * modifiers.get(WizardryItems.range_upgrade), look.z * modifiers.get(WizardryItems.range_upgrade), 0, 3 + world.rand.nextFloat(), 0, 0); - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_FIRE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, look.x * modifiers.get(WizardryItems.range_upgrade), look.y * modifiers.get(WizardryItems.range_upgrade), look.z * modifiers.get(WizardryItems.range_upgrade), 0, 3 + world.rand.nextFloat(), 0, 0); diff --git a/src/main/java/electroblob/wizardry/spell/FlameRay.java b/src/main/java/electroblob/wizardry/spell/FlameRay.java index f2384b74..7a41edbb 100644 --- a/src/main/java/electroblob/wizardry/spell/FlameRay.java +++ b/src/main/java/electroblob/wizardry/spell/FlameRay.java @@ -9,7 +9,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -58,11 +58,11 @@ public class FlameRay extends Spell { double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_FIRE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, look.x * modifiers.get(WizardryItems.range_upgrade), look.y * modifiers.get(WizardryItems.range_upgrade), look.z * modifiers.get(WizardryItems.range_upgrade), 0); - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_FIRE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, look.x * modifiers.get(WizardryItems.range_upgrade), look.y * modifiers.get(WizardryItems.range_upgrade), look.z * modifiers.get(WizardryItems.range_upgrade), 0); @@ -94,11 +94,11 @@ public class FlameRay extends Spell { double y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + vec.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_FIRE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, vec.x * modifiers.get(WizardryItems.range_upgrade), vec.y * modifiers.get(WizardryItems.range_upgrade), vec.z * modifiers.get(WizardryItems.range_upgrade), 0); - Wizardry.proxy.spawnParticle(WizardryParticleType.MAGIC_FIRE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, vec.x * modifiers.get(WizardryItems.range_upgrade), vec.y * modifiers.get(WizardryItems.range_upgrade), vec.z * modifiers.get(WizardryItems.range_upgrade), 0); diff --git a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java index f347d6e5..b70f491a 100644 --- a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; @@ -54,7 +54,7 @@ public class FlamingWeapon extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.9f, 0.7f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Flight.java b/src/main/java/electroblob/wizardry/spell/Flight.java index 2a79a85b..97db2f9c 100644 --- a/src/main/java/electroblob/wizardry/spell/Flight.java +++ b/src/main/java/electroblob/wizardry/spell/Flight.java @@ -5,7 +5,7 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; @@ -37,11 +37,11 @@ public class Flight extends Spell { caster.fallDistance = 0.0f; } if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX - 1 + world.rand.nextDouble() * 2, WizardryUtilities.getPlayerEyesPos(caster) - 0.5f + world.rand.nextDouble(), caster.posZ - 1 + world.rand.nextDouble() * 2, 0, -0.1F, 0, 15, 0.8f, 1.0f, 0.5f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX - 1 + world.rand.nextDouble() * 2, WizardryUtilities.getPlayerEyesPos(caster) - 0.5f + world.rand.nextDouble(), caster.posZ - 1 + world.rand.nextDouble() * 2, 0, -0.1F, 0, 15, 1.0f, 1.0f, 1.0f); diff --git a/src/main/java/electroblob/wizardry/spell/FontOfMana.java b/src/main/java/electroblob/wizardry/spell/FontOfMana.java index cbe2ef35..3915ae6d 100644 --- a/src/main/java/electroblob/wizardry/spell/FontOfMana.java +++ b/src/main/java/electroblob/wizardry/spell/FontOfMana.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -46,7 +46,7 @@ public class FontOfMana extends Spell { double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); double angle = world.rand.nextDouble() * Math.PI * 2; float hue = world.rand.nextFloat() * 0.4f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX + radius * Math.cos(angle), caster.getEntityBoundingBox().minY, caster.posZ + radius * Math.sin(angle), 0, 0.03, 0, 50, 1, 1 - hue, 0.6f + hue); diff --git a/src/main/java/electroblob/wizardry/spell/FontOfVitality.java b/src/main/java/electroblob/wizardry/spell/FontOfVitality.java index e951008c..88f4cec7 100644 --- a/src/main/java/electroblob/wizardry/spell/FontOfVitality.java +++ b/src/main/java/electroblob/wizardry/spell/FontOfVitality.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -36,14 +36,14 @@ public class FontOfVitality extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 0.6f, 0.7f); x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 0.8f, 0.3f); } diff --git a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java index 33487073..44b7a30e 100644 --- a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java +++ b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -52,16 +52,16 @@ public class ForestsCurse extends Spell { double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); double angle = world.rand.nextDouble() * Math.PI * 2; float brightness = world.rand.nextFloat() / 4; - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, caster.posX + radius * Math.cos(angle), WizardryUtilities.getPlayerEyesPos(caster) + 0.5, caster.posZ + radius * Math.sin(angle), 0, -0.2, 0, 0, 0.05f + brightness, 0.2f + brightness, 0.0f); brightness = world.rand.nextFloat() / 4; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX + radius * Math.cos(angle), WizardryUtilities.getPlayerEyesPos(caster) + 0.5, caster.posZ + radius * Math.sin(angle), 0, -0.05, 0, 50, 0.1f + brightness, 0.2f + brightness, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, world, caster.posX + radius * Math.cos(angle), + Wizardry.proxy.spawnParticle(Type.LEAF, world, caster.posX + radius * Math.cos(angle), WizardryUtilities.getPlayerEyesPos(caster) + 0.5, caster.posZ + radius * Math.sin(angle), 0, -0.01, 0, 40 + world.rand.nextInt(12)); diff --git a/src/main/java/electroblob/wizardry/spell/Freeze.java b/src/main/java/electroblob/wizardry/spell/Freeze.java index 500d5c79..2f9a2790 100644 --- a/src/main/java/electroblob/wizardry/spell/Freeze.java +++ b/src/main/java/electroblob/wizardry/spell/Freeze.java @@ -11,7 +11,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -71,12 +71,12 @@ public class Freeze extends Spell { double dz = target.posZ - caster.posZ; for(int i = 1; i < 5; i++){ float brightness = 0.5f + (world.rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, + Wizardry.proxy.spawnParticle(Type.SNOW, world, caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, -0.02, 0, @@ -117,13 +117,13 @@ public class Freeze extends Spell { for(int i = 1; i < 5; i++){ float brightness = 0.5f + (world.rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0.0d, 0.0d, 0.0d, 20 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, @@ -169,12 +169,12 @@ public class Freeze extends Spell { double dz = target.posZ - caster.posZ; for(int i = 1; i < 5; i++){ float brightness = 0.5f + (world.rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, caster.posY + caster.getEyeHeight() + (i * (dy / 5)) + world.rand.nextFloat() / 5, caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, + Wizardry.proxy.spawnParticle(Type.SNOW, world, caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, caster.posY + caster.getEyeHeight() + (i * (dy / 5)) + world.rand.nextFloat() / 5, caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, -0.02, 0, diff --git a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java index 3c85b63d..765d8df6 100644 --- a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; @@ -60,7 +60,7 @@ public class FreezingWeapon extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.9f, 0.7f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/FrostAxe.java b/src/main/java/electroblob/wizardry/spell/FrostAxe.java index c997425a..0daffc81 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostAxe.java +++ b/src/main/java/electroblob/wizardry/spell/FrostAxe.java @@ -8,7 +8,7 @@ import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -38,7 +38,7 @@ public class FrostAxe extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, x1, y1, z1, 0, -0.02d, 0, + Wizardry.proxy.spawnParticle(Type.SNOW, world, x1, y1, z1, 0, -0.02d, 0, 40 + world.rand.nextInt(10)); } } diff --git a/src/main/java/electroblob/wizardry/spell/FrostRay.java b/src/main/java/electroblob/wizardry/spell/FrostRay.java index b7b3d942..4f560b6e 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostRay.java +++ b/src/main/java/electroblob/wizardry/spell/FrostRay.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -69,7 +69,7 @@ public class FrostRay extends Spell { double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, look.x * modifiers.get(WizardryItems.range_upgrade), look.y * modifiers.get(WizardryItems.range_upgrade), look.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, @@ -79,7 +79,7 @@ public class FrostRay extends Spell { y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, look.x * modifiers.get(WizardryItems.range_upgrade), look.y * modifiers.get(WizardryItems.range_upgrade), look.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, @@ -125,7 +125,7 @@ public class FrostRay extends Spell { double y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + vec.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, vec.x * modifiers.get(WizardryItems.range_upgrade), vec.y * modifiers.get(WizardryItems.range_upgrade), vec.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, @@ -135,7 +135,7 @@ public class FrostRay extends Spell { y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; z1 = caster.posZ + vec.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, vec.x * modifiers.get(WizardryItems.range_upgrade), vec.y * modifiers.get(WizardryItems.range_upgrade), vec.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, diff --git a/src/main/java/electroblob/wizardry/spell/Glide.java b/src/main/java/electroblob/wizardry/spell/Glide.java index bab250b9..9878e3ac 100644 --- a/src/main/java/electroblob/wizardry/spell/Glide.java +++ b/src/main/java/electroblob/wizardry/spell/Glide.java @@ -5,7 +5,7 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; @@ -32,11 +32,11 @@ public class Glide extends Spell { } if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX - 0.25d + world.rand.nextDouble() / 2, WizardryUtilities.getPlayerEyesPos(caster) - 1.5f + world.rand.nextDouble(), caster.posZ - 0.25d + world.rand.nextDouble() / 2, 0, -0.1F, 0, 15, 1.0f, 1.0f, 1.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, world, + Wizardry.proxy.spawnParticle(Type.LEAF, world, caster.posX - 0.25d + world.rand.nextDouble() / 2, WizardryUtilities.getPlayerEyesPos(caster) - 1.5f + world.rand.nextDouble(), caster.posZ - 0.25d + world.rand.nextDouble() / 2, 0, -0.03, 0, 20); diff --git a/src/main/java/electroblob/wizardry/spell/GreaterHeal.java b/src/main/java/electroblob/wizardry/spell/GreaterHeal.java index 5664cb3b..1173dc11 100644 --- a/src/main/java/electroblob/wizardry/spell/GreaterHeal.java +++ b/src/main/java/electroblob/wizardry/spell/GreaterHeal.java @@ -6,7 +6,7 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -32,7 +32,7 @@ public class GreaterHeal extends Spell { double dy = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double dz = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); } } @@ -54,7 +54,7 @@ public class GreaterHeal extends Spell { double dx = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double dy = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); double dz = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); } } diff --git a/src/main/java/electroblob/wizardry/spell/GroupHeal.java b/src/main/java/electroblob/wizardry/spell/GroupHeal.java index 2324a906..fe25fbff 100644 --- a/src/main/java/electroblob/wizardry/spell/GroupHeal.java +++ b/src/main/java/electroblob/wizardry/spell/GroupHeal.java @@ -10,7 +10,7 @@ import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -48,7 +48,7 @@ public class GroupHeal extends Spell { double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos((EntityPlayer)target) - 0.5F + world.rand.nextFloat()); double d2 = (double)((float)target.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); } } @@ -77,7 +77,7 @@ public class GroupHeal extends Spell { double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos((EntityPlayer)target) - 0.5F + world.rand.nextFloat()); double d2 = (double)((float)target.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Heal.java b/src/main/java/electroblob/wizardry/spell/Heal.java index f3bdad94..5fa338b3 100644 --- a/src/main/java/electroblob/wizardry/spell/Heal.java +++ b/src/main/java/electroblob/wizardry/spell/Heal.java @@ -6,7 +6,7 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -31,12 +31,11 @@ public class Heal extends Spell { if(world.isRemote){ for(int i = 0; i < 10; i++){ double d0 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - // Apparently the client side spawns the particles 1 block higher than it should... hence the - - // 0.5F. + // Apparently the client side spawns the particles 1 block higher than it should... hence the -0.5F. double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double d2 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); } } @@ -59,7 +58,7 @@ public class Heal extends Spell { double dx = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double dy = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); double dz = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); } } diff --git a/src/main/java/electroblob/wizardry/spell/HealAlly.java b/src/main/java/electroblob/wizardry/spell/HealAlly.java index 9f824bfb..d8f3edc4 100644 --- a/src/main/java/electroblob/wizardry/spell/HealAlly.java +++ b/src/main/java/electroblob/wizardry/spell/HealAlly.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -41,7 +41,7 @@ public class HealAlly extends Spell { double d1 = (double)((float)target.getEntityBoundingBox().minY + target.height - 0.5f + world.rand.nextFloat()); double d2 = (double)((float)target.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); } } diff --git a/src/main/java/electroblob/wizardry/spell/IceStatue.java b/src/main/java/electroblob/wizardry/spell/IceStatue.java index 59938921..c32cfc6d 100644 --- a/src/main/java/electroblob/wizardry/spell/IceStatue.java +++ b/src/main/java/electroblob/wizardry/spell/IceStatue.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.tileentity.TileEntityStatue; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.monster.EntityBlaze; @@ -115,9 +115,9 @@ public class IceStatue extends Spell { + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SNOW, world, x1, y1, z1, 0.0d, -0.02d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SNOW, world, x1, y1, z1, 0.0d, -0.02d, 0.0d, 20 + world.rand.nextInt(10)); } diff --git a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java index 88e8b5b5..66f7ea82 100644 --- a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; @@ -69,7 +69,7 @@ public class ImbueWeapon extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.9f, 0.7f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Intimidate.java b/src/main/java/electroblob/wizardry/spell/Intimidate.java index ba78e956..5cbabdff 100644 --- a/src/main/java/electroblob/wizardry/spell/Intimidate.java +++ b/src/main/java/electroblob/wizardry/spell/Intimidate.java @@ -9,7 +9,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityCreature; @@ -62,7 +62,7 @@ public class Intimidate extends Spell { }else{ for(int i = 0; i < 30; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, caster.posX - 1 + world.rand.nextDouble() * 2, caster.getEntityBoundingBox().minY + 1.5 + world.rand.nextDouble() * 0.5, caster.posZ - 1 + world.rand.nextDouble() * 2, 0, 0, 0, 0, 0.9f, 0.1f, 0.0f); diff --git a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java index 71cf0216..a8ede484 100644 --- a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java +++ b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java @@ -9,7 +9,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -44,7 +44,7 @@ public class InvigoratingPresence extends Spell { for(int i = 0; i < 50 * modifiers.get(WizardryItems.blast_upgrade); i++){ double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); double angle = world.rand.nextDouble() * Math.PI * 2; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX + radius * Math.cos(angle), caster.getEntityBoundingBox().minY, caster.posZ + radius * Math.sin(angle), 0, 0.03, 0, 50, 1, 0.2f, 0.2f); diff --git a/src/main/java/electroblob/wizardry/spell/Invisibility.java b/src/main/java/electroblob/wizardry/spell/Invisibility.java index ed70f40c..0fe1caba 100644 --- a/src/main/java/electroblob/wizardry/spell/Invisibility.java +++ b/src/main/java/electroblob/wizardry/spell/Invisibility.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -35,7 +35,7 @@ public class Invisibility extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.7f, 1.0f, 1.0f); } } @@ -58,7 +58,7 @@ public class Invisibility extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.7f, 1.0f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java index edf5f0d6..9046e787 100644 --- a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java +++ b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; @@ -54,7 +54,7 @@ public class InvokeWeather extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.5f, 0.7f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Ironflesh.java b/src/main/java/electroblob/wizardry/spell/Ironflesh.java index acbbff3c..7828b4d0 100644 --- a/src/main/java/electroblob/wizardry/spell/Ironflesh.java +++ b/src/main/java/electroblob/wizardry/spell/Ironflesh.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -35,7 +35,7 @@ public class Ironflesh extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.4f, 0.5f, 0.6f); } } @@ -59,7 +59,7 @@ public class Ironflesh extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.4f, 0.5f, 0.6f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Levitation.java b/src/main/java/electroblob/wizardry/spell/Levitation.java index 03907a3a..1879e9bc 100644 --- a/src/main/java/electroblob/wizardry/spell/Levitation.java +++ b/src/main/java/electroblob/wizardry/spell/Levitation.java @@ -6,7 +6,7 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -27,7 +27,7 @@ public class Levitation extends Spell { caster.motionY = caster.motionY < 0.5d ? caster.motionY + 0.1d : caster.motionY; if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX - 0.25d + world.rand.nextDouble() / 2, WizardryUtilities.getPlayerEyesPos(caster) - 1.5f, caster.posZ - 0.25d + world.rand.nextDouble() / 2, 0, -0.1F, 0, 15, 0.5f, 1.0f, 0.7f); diff --git a/src/main/java/electroblob/wizardry/spell/LifeDrain.java b/src/main/java/electroblob/wizardry/spell/LifeDrain.java index 818cc010..909c9ad2 100644 --- a/src/main/java/electroblob/wizardry/spell/LifeDrain.java +++ b/src/main/java/electroblob/wizardry/spell/LifeDrain.java @@ -9,7 +9,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -54,10 +54,10 @@ public class LifeDrain extends Spell { double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); if(i % 5 == 0){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); } - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, -0.05 * look.x * i, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, -0.05 * look.x * i, -0.05 * look.y * i, -0.05 * look.z * i, 8 + world.rand.nextInt(6), 0.5f, 0.0f, 0.0f); } } @@ -92,10 +92,10 @@ public class LifeDrain extends Spell { double z1 = caster.posZ + vec.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); if(i % 5 == 0){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); } - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, -0.05 * vec.x * i, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, -0.05 * vec.x * i, -0.05 * vec.y * i, -0.05 * vec.z * i, 8 + world.rand.nextInt(6), 0.5f, 0.0f, 0.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/LightningRay.java b/src/main/java/electroblob/wizardry/spell/LightningRay.java index ced7a07c..0d7236b2 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningRay.java +++ b/src/main/java/electroblob/wizardry/spell/LightningRay.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; @@ -63,7 +63,7 @@ public class LightningRay extends Spell { }else{ for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, 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, 0, 0, 0, 3); @@ -132,7 +132,7 @@ public class LightningRay extends Spell { }else{ for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, 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, 0, 0, 0, 3); diff --git a/src/main/java/electroblob/wizardry/spell/LightningWeb.java b/src/main/java/electroblob/wizardry/spell/LightningWeb.java index 3a86a31f..7bc5519b 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningWeb.java +++ b/src/main/java/electroblob/wizardry/spell/LightningWeb.java @@ -12,7 +12,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -71,7 +71,7 @@ public class LightningWeb extends Spell { } }else{ for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, 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, 0, 0, 0, 3); @@ -121,7 +121,7 @@ public class LightningWeb extends Spell { } }else{ for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, secondaryTarget.posX + world.rand.nextFloat() - 0.5, secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2 + world.rand.nextFloat() * 2 - 1, @@ -173,7 +173,7 @@ public class LightningWeb extends Spell { } }else{ for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, tertiaryTarget.posX + world.rand.nextFloat() - 0.5, tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2 + world.rand.nextFloat() * 2 - 1, diff --git a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java index 12975e93..5489e28d 100644 --- a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java +++ b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java @@ -12,7 +12,7 @@ import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -121,11 +121,11 @@ public class Metamorphosis extends Spell { + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.2f, 0.0f, 0.1f); } for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, xPos, yPos, zPos, 0.0d, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, xPos, yPos, zPos, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/MindControl.java b/src/main/java/electroblob/wizardry/spell/MindControl.java index 3edff448..527ca68b 100644 --- a/src/main/java/electroblob/wizardry/spell/MindControl.java +++ b/src/main/java/electroblob/wizardry/spell/MindControl.java @@ -11,7 +11,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; @@ -76,12 +76,12 @@ public class MindControl extends Spell { } }else{ for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble() * 0.5, target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble() * 0.5, target.posZ - 0.25 + world.rand.nextDouble() * 0.5, 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble() * 0.5, target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble() * 0.5, @@ -116,12 +116,12 @@ public class MindControl extends Spell { } }else{ for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble() * 0.5, target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble() * 0.5, target.posZ - 0.25 + world.rand.nextDouble() * 0.5, 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble() * 0.5, target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble() * 0.5, diff --git a/src/main/java/electroblob/wizardry/spell/MindTrick.java b/src/main/java/electroblob/wizardry/spell/MindTrick.java index d2f5dae2..9f4f0dab 100644 --- a/src/main/java/electroblob/wizardry/spell/MindTrick.java +++ b/src/main/java/electroblob/wizardry/spell/MindTrick.java @@ -8,7 +8,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -56,7 +56,7 @@ public class MindTrick extends Spell { } }else{ for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble() * 0.5, target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble() * 0.5, @@ -91,7 +91,7 @@ public class MindTrick extends Spell { } }else{ for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, target.posX - 0.25 + world.rand.nextDouble() * 0.5, target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 + world.rand.nextDouble() * 0.5, diff --git a/src/main/java/electroblob/wizardry/spell/Oakflesh.java b/src/main/java/electroblob/wizardry/spell/Oakflesh.java index 0f35c253..21488735 100644 --- a/src/main/java/electroblob/wizardry/spell/Oakflesh.java +++ b/src/main/java/electroblob/wizardry/spell/Oakflesh.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -35,7 +35,7 @@ public class Oakflesh extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.5f, 0.4f); } } @@ -59,7 +59,7 @@ public class Oakflesh extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.5f, 0.4f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Petrify.java b/src/main/java/electroblob/wizardry/spell/Petrify.java index b207fd34..7b1f1a6a 100644 --- a/src/main/java/electroblob/wizardry/spell/Petrify.java +++ b/src/main/java/electroblob/wizardry/spell/Petrify.java @@ -8,7 +8,7 @@ import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.tileentity.TileEntityStatue; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.player.EntityPlayer; @@ -112,9 +112,9 @@ public class Petrify extends Spell { + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.1f, 0.1f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.2f, 0.2f, 0.2f); } } diff --git a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java index 4559ca53..03d4ba9e 100644 --- a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java +++ b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java @@ -10,7 +10,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -50,12 +50,12 @@ public class PlagueOfDarkness extends Spell { for(int i = 0; i < 40 * modifiers.get(WizardryItems.blast_upgrade); i++){ particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, particleX, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, particleX, WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, 0, 0.1f, 0.0f, 0.0f); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, particleX, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, particleX, WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, 30, 0.1f, 0.0f, 0.05f); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); diff --git a/src/main/java/electroblob/wizardry/spell/Poison.java b/src/main/java/electroblob/wizardry/spell/Poison.java index 630c0a3e..8fd97d21 100644 --- a/src/main/java/electroblob/wizardry/spell/Poison.java +++ b/src/main/java/electroblob/wizardry/spell/Poison.java @@ -9,7 +9,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -59,9 +59,9 @@ public class Poison extends Spell { + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.3f, 0.7f, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.1f, 0.4f, 0.0f); } } @@ -99,9 +99,9 @@ public class Poison extends Spell { - 0.1f; double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.3f, 0.7f, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.1f, 0.4f, 0.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java index e9939d35..0af5b579 100644 --- a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java +++ b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java @@ -6,7 +6,7 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -32,7 +32,7 @@ public class ReplenishHunger extends Spell { double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 0.7f, 0.3f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Shockwave.java b/src/main/java/electroblob/wizardry/spell/Shockwave.java index 60d2fedc..e1a63679 100644 --- a/src/main/java/electroblob/wizardry/spell/Shockwave.java +++ b/src/main/java/electroblob/wizardry/spell/Shockwave.java @@ -11,7 +11,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -71,12 +71,12 @@ public class Shockwave extends Spell { for(int i = 0; i < 40; i++){ particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, particleX, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, particleX, WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, 30, 0.8f, 0.8f, 1.0f); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, particleX, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, particleX, WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, 30, 0.9f, 0.9f, 0.9f); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); diff --git a/src/main/java/electroblob/wizardry/spell/Slime.java b/src/main/java/electroblob/wizardry/spell/Slime.java index 6ba62b8e..b1569eab 100644 --- a/src/main/java/electroblob/wizardry/spell/Slime.java +++ b/src/main/java/electroblob/wizardry/spell/Slime.java @@ -9,7 +9,7 @@ import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -66,7 +66,7 @@ public class Slime extends Spell { double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; world.spawnParticle(EnumParticleTypes.SLIME, x1, y1, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.2f, 0.8f, 0.1f); } } @@ -103,7 +103,7 @@ public class Slime extends Spell { double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; world.spawnParticle(EnumParticleTypes.SLIME, x1, y1, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.2f, 0.8f, 0.1f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Snare.java b/src/main/java/electroblob/wizardry/spell/Snare.java index d8a5f262..64fb6f55 100644 --- a/src/main/java/electroblob/wizardry/spell/Snare.java +++ b/src/main/java/electroblob/wizardry/spell/Snare.java @@ -8,7 +8,7 @@ import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.tileentity.TileEntityPlayerSave; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; @@ -51,13 +51,13 @@ public class Snare extends Spell { if(world.isRemote){ for(int i = 1; i < 5; i++){ float brightness = world.rand.nextFloat() / 4; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0.0d, 0.0d, 0.0d, 20 + world.rand.nextInt(8), brightness, brightness + 0.1f, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.LEAF, world, + Wizardry.proxy.spawnParticle(Type.LEAF, world, caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, diff --git a/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java b/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java index 00fdc4bf..87d30b8d 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java +++ b/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java @@ -8,7 +8,7 @@ import electroblob.wizardry.entity.living.EntityIceGiant; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -40,7 +40,7 @@ public class SummonIceGiant extends Spell { double x1 = (double)((float)pos.getX() + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); double z1 = (double)((float)pos.getZ() + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java index d7f48844..fa2a0759 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java @@ -5,7 +5,7 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.monster.EntityIronGolem; import net.minecraft.entity.player.EntityPlayer; @@ -38,7 +38,7 @@ public class SummonIronGolem extends Spell { double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); double z1 = (double)((float)pos.getZ() + world.rand.nextFloat() * 2 - 1.0F); if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java index 06c71eee..d50da8c1 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java @@ -6,7 +6,7 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.monster.EntitySnowman; import net.minecraft.entity.player.EntityPlayer; @@ -37,7 +37,7 @@ public class SummonSnowGolem extends Spell { double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); double z1 = (double)((float)pos.getZ() + world.rand.nextFloat() * 2 - 1.0F); if(world.isRemote){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java index 3a3e88a5..cb533a50 100644 --- a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java +++ b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java @@ -12,7 +12,7 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.effect.EntityLightningBolt; @@ -70,7 +70,7 @@ public class Thunderstorm extends Spell { world.spawnEntity(arc); }else{ for(int j = 0; j < 8; j++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, secondaryTarget.posX + world.rand.nextFloat() - 0.5, secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2 + world.rand.nextFloat() * 2 - 1, @@ -111,7 +111,7 @@ public class Thunderstorm extends Spell { world.spawnEntity(arc); }else{ for(int k = 0; k < 8; k++){ - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARK, world, + Wizardry.proxy.spawnParticle(Type.SPARK, world, tertiaryTarget.posX + world.rand.nextFloat() - 0.5, tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2 + world.rand.nextFloat() * 2 - 1, diff --git a/src/main/java/electroblob/wizardry/spell/WallOfFrost.java b/src/main/java/electroblob/wizardry/spell/WallOfFrost.java index 4220fdde..98907300 100644 --- a/src/main/java/electroblob/wizardry/spell/WallOfFrost.java +++ b/src/main/java/electroblob/wizardry/spell/WallOfFrost.java @@ -8,7 +8,7 @@ import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -74,7 +74,7 @@ public class WallOfFrost extends Spell { double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, look.x * modifiers.get(WizardryItems.range_upgrade), look.y * modifiers.get(WizardryItems.range_upgrade), look.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, @@ -84,7 +84,7 @@ public class WallOfFrost extends Spell { y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 + world.rand.nextFloat() / 5 - 0.1f; z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, look.x * modifiers.get(WizardryItems.range_upgrade), look.y * modifiers.get(WizardryItems.range_upgrade), look.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, diff --git a/src/main/java/electroblob/wizardry/spell/WaterBreathing.java b/src/main/java/electroblob/wizardry/spell/WaterBreathing.java index 8effe686..4b2462eb 100644 --- a/src/main/java/electroblob/wizardry/spell/WaterBreathing.java +++ b/src/main/java/electroblob/wizardry/spell/WaterBreathing.java @@ -7,7 +7,7 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -32,7 +32,7 @@ public class WaterBreathing extends Spell { double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 0.3f, 0.3f, 1.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/Wither.java b/src/main/java/electroblob/wizardry/spell/Wither.java index 88712ceb..9234756d 100644 --- a/src/main/java/electroblob/wizardry/spell/Wither.java +++ b/src/main/java/electroblob/wizardry/spell/Wither.java @@ -8,7 +8,7 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -65,9 +65,9 @@ public class Wither extends Spell { + world.rand.nextFloat() / 5 - 0.1f; double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.1f, 0.0f, 0.05f); } } @@ -103,9 +103,9 @@ public class Wither extends Spell { - 0.1f; double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(WizardryParticleType.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); - Wizardry.proxy.spawnParticle(WizardryParticleType.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, + Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 12 + world.rand.nextInt(8), 0.1f, 0.0f, 0.05f); } } diff --git a/src/main/java/electroblob/wizardry/util/WizardryParticleType.java b/src/main/java/electroblob/wizardry/util/WizardryParticleType.java deleted file mode 100644 index 2be30685..00000000 --- a/src/main/java/electroblob/wizardry/util/WizardryParticleType.java +++ /dev/null @@ -1,9 +0,0 @@ -package electroblob.wizardry.util; - -/** - * Enum constants representing the different types of particle added by wizardry. This was renamed from the previous - * EnumParticleType in the 1.10.2 port to avoid confusion with the vanilla version, EnumParticleTypes. - */ -public enum WizardryParticleType { - BLIZZARD, BRIGHT_DUST, DARK_MAGIC, DUST, ICE, LEAF, MAGIC_BUBBLE, MAGIC_FIRE, PATH, SNOW, SPARK, SPARKLE, SPARKLE_ROTATING -} From 0341a603d5ba159a2c3b6b108e89dc911f44f2e1 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 5 Jun 2018 21:15:02 +0100 Subject: [PATCH 07/68] Missed the imports on that one... --- src/main/java/electroblob/wizardry/block/BlockSpectral.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/electroblob/wizardry/block/BlockSpectral.java b/src/main/java/electroblob/wizardry/block/BlockSpectral.java index 99d1ee17..1aa8948f 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSpectral.java +++ b/src/main/java/electroblob/wizardry/block/BlockSpectral.java @@ -2,10 +2,10 @@ package electroblob.wizardry.block; import java.util.Random; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.tileentity.TileEntityTimer; -import electroblob.wizardry.util.WizardryParticleType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.block.Block; import net.minecraft.block.BlockContainer; import net.minecraft.block.SoundType; From b9ba25c1161d71b66cdea222b4144f5db8a2922e Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 5 Jun 2018 21:18:01 +0100 Subject: [PATCH 08/68] Add test cases for new particle effects; to be applied to everything once spells have been reorganised --- .../entity/projectile/EntityMagicMissile.java | 11 +++++++++++ src/main/java/electroblob/wizardry/spell/Agility.java | 1 + src/main/java/electroblob/wizardry/spell/Heal.java | 1 + 3 files changed, 13 insertions(+) diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java index 9acce846..76ddbda4 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java @@ -43,6 +43,17 @@ public class EntityMagicMissile extends EntityMagicArrow { @Override public void onEntityHit(EntityLivingBase entityHit){ this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + if(this.world.isRemote) spawnImpactParticles(); + } + + @Override + public void onBlockHit(){ + if(this.world.isRemote) spawnImpactParticles(); + } + + private void spawnImpactParticles(){ + ParticleBuilder.create(Type.FLASH).pos(posX, posY, posZ).colour(0.5f + rand.nextFloat()/2, 0.5f + rand.nextFloat()/2, + 0.5f + rand.nextFloat()/2).spawn(world); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Agility.java b/src/main/java/electroblob/wizardry/spell/Agility.java index 4f6b0587..dd760919 100644 --- a/src/main/java/electroblob/wizardry/spell/Agility.java +++ b/src/main/java/electroblob/wizardry/spell/Agility.java @@ -40,6 +40,7 @@ public class Agility extends Spell { ParticleBuilder.create(Type.SPARKLE).pos(x1, y1, z1).vel(0, 0.1F, 0) .lifetime(48 + world.rand.nextInt(12)).colour(0.4f, 1.0f, 0.8f).spawn(world); } + Wizardry.proxy.spawnEntityParticle(world, caster, 15, 0.4f, 1.0f, 0.8f); } WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, diff --git a/src/main/java/electroblob/wizardry/spell/Heal.java b/src/main/java/electroblob/wizardry/spell/Heal.java index 5fa338b3..3b9977f4 100644 --- a/src/main/java/electroblob/wizardry/spell/Heal.java +++ b/src/main/java/electroblob/wizardry/spell/Heal.java @@ -38,6 +38,7 @@ public class Heal extends Spell { Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); } + Wizardry.proxy.spawnEntityParticle(world, caster, 15, 1.0f, 1.0f, 0.3f); } WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, From dcec7c72816ad785d6bc8e47b55d2de6020b9880 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 5 Jun 2018 21:24:09 +0100 Subject: [PATCH 09/68] Miscellaneous cleanup and commenting --- src/main/java/electroblob/wizardry/Wizardry.java | 8 +++++++- .../electroblob/wizardry/block/BlockSpectral.java | 6 ++---- .../wizardry/client/WizardryClientEventHandler.java | 5 +++++ .../wizardry/client/renderer/LayerStone.java | 2 ++ .../electroblob/wizardry/enchantment/Imbuement.java | 2 +- .../wizardry/entity/living/EntityWizard.java | 11 +++++------ 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index 996258b9..6e5e1ab5 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -87,7 +87,13 @@ public class Wizardry { /** Static instance of the {@link Settings} object for Wizardry. */ public static final Settings settings = new Settings(); - /** Static instance of the {@link Logger} object for Wizardry. */ + /** Static instance of the {@link Logger} object for Wizardry. + *

+ * Logging conventions for wizardry (only these levels are used currently): + *

+ * - ERROR: Anything that threw an exception; may or may not crash the game.
+ * - WARN: Anything that isn't supposed to happen during normal operation, but didn't throw an exception.
+ * - INFO: Anything that might happen during normal mod operation that the user needs to know about. */ public static Logger logger; // private static Pattern entityNamePattern; diff --git a/src/main/java/electroblob/wizardry/block/BlockSpectral.java b/src/main/java/electroblob/wizardry/block/BlockSpectral.java index 1aa8948f..708f3fe6 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSpectral.java +++ b/src/main/java/electroblob/wizardry/block/BlockSpectral.java @@ -45,10 +45,8 @@ public class BlockSpectral extends BlockContainer { return EnumBlockRenderType.MODEL; } - // Apparently it's OK to override this, despite it being deprecated. More - // importantly, it being deprecated is not - // Forge's doing, rather it is Mojang themselves misusing the @Deprecated - // annotation to mean 'internal, don't call'. + // Apparently it's OK to override this, despite it being deprecated. More importantly, it being deprecated is not + // Forge's doing, rather it is Mojang themselves misusing the @Deprecated annotation to mean 'internal, don't call'. @Override public boolean isOpaqueCube(IBlockState state){ return false; diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java index ea695342..d188784f 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -79,8 +79,13 @@ public final class WizardryClientEventHandler { @SubscribeEvent public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_CRYSTAL); event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_UPGRADE); + +// for(int i=0; i<7; i++){ +// event.getMap().registerSprite(new ResourceLocation(Wizardry.MODID, "particle/ice_" + i)); +// } } // Shift-scrolling to change spells diff --git a/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java b/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java index 82f5950f..3630e58a 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java +++ b/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java @@ -53,6 +53,8 @@ public class LayerStone implements LayerRenderer { this.renderer = renderer; this.model = renderer.getMainModel(); } + + // FIXME: Does not work with zombie pigmen, I have no idea why. @Override public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, diff --git a/src/main/java/electroblob/wizardry/enchantment/Imbuement.java b/src/main/java/electroblob/wizardry/enchantment/Imbuement.java index 959e73fe..0aa62bf8 100644 --- a/src/main/java/electroblob/wizardry/enchantment/Imbuement.java +++ b/src/main/java/electroblob/wizardry/enchantment/Imbuement.java @@ -78,7 +78,7 @@ public interface Imbuement { // If any imbuements were removed, replaces the enchantments on the book with the new ones, or // deletes the book entirely if there are none left. if(enchantments.isEmpty()){ - slot.putStack(ItemStack.EMPTY); // NOTE: Will need changing in 1.11 + slot.putStack(ItemStack.EMPTY); Wizardry.logger.info("Deleted enchanted book with illegal enchantments"); }else{ EnchantmentHelper.setEnchantments(enchantments, slot.getStack()); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index b686924c..5e70bd7f 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -161,12 +161,12 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit // ... and is a mob, a summoned creature ... if((entity instanceof IMob || entity instanceof ISummonedCreature - // ... or in the whitelist ... + // ... or in the whitelist ... || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist) - .contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))) + .contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))) // ... and isn't in the blacklist ... && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist) - .contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))){ + .contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))){ // ... it can be attacked. return true; } @@ -520,7 +520,7 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit } // TODO: Switch all of this over to some kind of loot pool system? - + private ItemStack getRandomPrice(Tier tier){ ItemStack itemstack = ItemStack.EMPTY; switch(this.rand.nextInt(3)){ @@ -594,8 +594,7 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit }else if(randomiser < 8){ return new ItemStack(WizardryItems.arcane_tome, 1, 1); }else if(randomiser < 10){ - EntityEquipmentSlot slot = WizardryUtilities.ARMOUR_SLOTS[rand - .nextInt(WizardryUtilities.ARMOUR_SLOTS.length)]; + EntityEquipmentSlot slot = WizardryUtilities.ARMOUR_SLOTS[rand.nextInt(WizardryUtilities.ARMOUR_SLOTS.length)]; if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ // This means it is more likely for armour sold to be of the same element as the wizard if the // wizard has an element. From 330c78a92c0bc7b0c378af9bf4007e049e60342f Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 5 Jun 2018 21:24:47 +0100 Subject: [PATCH 10/68] Change non-evil wizard health from 20 to 30 --- .../java/electroblob/wizardry/entity/living/EntityWizard.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 5e70bd7f..8731fdef 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -186,6 +186,7 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit protected void applyEntityAttributes(){ super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.5); + this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(30); } private int getHealCooldown(){ From 726a3068301a72514f3f020bdfdbd48a169777f7 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 5 Jun 2018 21:25:41 +0100 Subject: [PATCH 11/68] Delete redundant classes --- .../advancement/AdvancementHelper.java | 61 ------------------- .../client/particle/ParticleGiantBubble.java | 49 --------------- 2 files changed, 110 deletions(-) delete mode 100644 src/main/java/electroblob/wizardry/advancement/AdvancementHelper.java delete mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleGiantBubble.java diff --git a/src/main/java/electroblob/wizardry/advancement/AdvancementHelper.java b/src/main/java/electroblob/wizardry/advancement/AdvancementHelper.java deleted file mode 100644 index 1a725a97..00000000 --- a/src/main/java/electroblob/wizardry/advancement/AdvancementHelper.java +++ /dev/null @@ -1,61 +0,0 @@ -package electroblob.wizardry.advancement; - -import electroblob.wizardry.Wizardry; -import net.minecraft.advancements.Advancement; -import net.minecraft.advancements.AdvancementManager; -import net.minecraft.advancements.AdvancementProgress; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.util.ResourceLocation; - -/** - * This is a provisory class for the transition to 1.12 - * It contains an enum with all the advancements of this mod - * and an helper to grant advancements on the server side only (like the command) - * @author Corail31 - * @since Wizardry 4.1 - */ -public class AdvancementHelper { - public enum EnumAdvancement { - crystal, - arcane_initiate, - apprentice, - master, - all_spells, - wizard_trade, - buy_master_spell, - freeze_blaze, - charge_creeper, - frankenstein, - special_upgrade, - craft_flask, - elemental, - armour_set, - legendary, - self_destruct, - pig_tornado, - jam_wizard, - slime_skeleton, - anger_wizard, - defeat_evil_wizard, - max_out_wand, - element_master, - identify_spell; - } - - public static boolean grantAdvancement(EntityPlayer player, EnumAdvancement advancementName) { - if (player == null) { return false; } - if (player.world.isRemote) { return true; } - EntityPlayerMP player_mp = player.getServer().getPlayerList().getPlayerByUUID(player.getUniqueID()); - AdvancementManager am = player_mp.getServerWorld().getAdvancementManager(); - Advancement advancement = am.getAdvancement(new ResourceLocation(Wizardry.MODID, advancementName.name())); - if (advancement == null) { return false; } - AdvancementProgress advancementprogress = player_mp.getAdvancements().getProgress(advancement); - if (!advancementprogress.isDone()) { - for (String criteria : advancementprogress.getRemaningCriteria()) { - player_mp.getAdvancements().grantCriterion(advancement, criteria); - } - } - return true; - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleGiantBubble.java b/src/main/java/electroblob/wizardry/client/particle/ParticleGiantBubble.java deleted file mode 100644 index b512aaba..00000000 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleGiantBubble.java +++ /dev/null @@ -1,49 +0,0 @@ -package electroblob.wizardry.client.particle; - -import electroblob.wizardry.Wizardry; -import net.minecraft.client.particle.Particle; -import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -@SideOnly(Side.CLIENT) -public class ParticleGiantBubble extends Particle { - /** - * The name used to identify this particle. Uses the mod id to avoid any possible conflicts (Not that there would be - * any, but I may as well.) - */ - public static final String NAME = Wizardry.MODID + "magicbubble"; - - public ParticleGiantBubble(World par1World, double par2, double par4, double par6, double par8, double par10, - double par12){ - super(par1World, par2, par4, par6, par8, par10, par12); - this.particleRed = 1.0F; - this.particleGreen = 1.0F; - this.particleBlue = 1.0F; - this.setParticleTextureIndex(32); - this.setSize(0.02F, 0.02F); - this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F; - this.motionX = par8 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); - this.motionY = par10 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); - this.motionZ = par12 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F); - this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D)); - } - - /** - * Called to update the entity's position/logic. - */ - public void onUpdate(){ - this.prevPosX = this.posX; - this.prevPosY = this.posY; - this.prevPosZ = this.posZ; - this.motionY += 0.002D; - this.move(this.motionX, this.motionY, this.motionZ); - this.motionX *= 0.8500000238418579D; - this.motionY *= 0.8500000238418579D; - this.motionZ *= 0.8500000238418579D; - - if(this.particleMaxAge-- <= 0){ - this.setExpired(); - } - } -} From dec5b1ac2c7c858c97bae1c6b6bf99b9bcb2559f Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 5 Jun 2018 21:26:07 +0100 Subject: [PATCH 12/68] Add witty/stupid comments to a few classes --- src/main/java/electroblob/wizardry/Wizardry.java | 10 ++++++++++ .../java/electroblob/wizardry/util/MagicDamage.java | 2 ++ .../java/electroblob/wizardry/util/SpellModifiers.java | 2 ++ .../java/electroblob/wizardry/util/WandHelper.java | 2 ++ .../electroblob/wizardry/util/WizardryUtilities.java | 3 +++ 5 files changed, 19 insertions(+) diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index 6e5e1ab5..8fc5b236 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -31,6 +31,16 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.registry.GameRegistry; +/** + * "Electroblob's Wizardry adds an RPG-like system of spells to Minecraft, with the aim of being as playable as + * possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master + * the arcane! - But you knew that, right?" + *

+ * Main mod class for Wizardry. Contains the logger and settings instances, along with all the other stuff that's normally + * in a main mod class. + * @author Electroblob + * @since Wizardry 1.0 + */ @Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, guiFactory = "electroblob.wizardry.WizardryGuiFactory") public class Wizardry { diff --git a/src/main/java/electroblob/wizardry/util/MagicDamage.java b/src/main/java/electroblob/wizardry/util/MagicDamage.java index 4df3bccb..9d6ca61b 100644 --- a/src/main/java/electroblob/wizardry/util/MagicDamage.java +++ b/src/main/java/electroblob/wizardry/util/MagicDamage.java @@ -45,6 +45,8 @@ import net.minecraft.util.EntityDamageSource; // type 'attributes'. This is my attempt to collect all of these into a reasonably coherent system. /** + * "Ouch, that hurt!" + *

* As of wizardry 1.1, this class has replaced the damagesource-related methods in WizardryUtilities, allowing a * {@link DamageType} to be specified with the damage. The main reason for this is so that damage sources can fit with * the vanilla behaviour on armour enchantments and such like whilst still being classified as wizardry damage for the diff --git a/src/main/java/electroblob/wizardry/util/SpellModifiers.java b/src/main/java/electroblob/wizardry/util/SpellModifiers.java index 8e840226..bbb7c08c 100644 --- a/src/main/java/electroblob/wizardry/util/SpellModifiers.java +++ b/src/main/java/electroblob/wizardry/util/SpellModifiers.java @@ -12,6 +12,8 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fml.common.network.ByteBufUtils; /** + * "{@code SpellModifiers} - modify all the things!" + *

* Object that wraps any number of spell modifiers into one, allowing for expandability within the Spell#cast methods. * This class is essentially a glorified {@link Map} which can be written to and read from a {@link ByteBuf}. It is * possible to calculate spell modifiers from wand NBT within the cast methods, but this is cumbersome and does not diff --git a/src/main/java/electroblob/wizardry/util/WandHelper.java b/src/main/java/electroblob/wizardry/util/WandHelper.java index d21aa8ac..6c47c18a 100644 --- a/src/main/java/electroblob/wizardry/util/WandHelper.java +++ b/src/main/java/electroblob/wizardry/util/WandHelper.java @@ -12,6 +12,8 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; /** + * "Never fear, {@code WandHelper} is here!" + *

* Much like {@link net.minecraft.enchantment.EnchantmentHelper EnchantmentHelper}, this class has some static methods * which allow cleaner and more concise interaction with the wand NBT data, which is quite a complex structure. Such * interaction previously resulted in rather verbose and repetitive code which was hard to read and even harder to diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index 1b18fe79..6fdf1f5e 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -59,6 +59,9 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; /** + * "Where do you put random but useful bits and pieces? {@code WizardryUtilities} of course - the 'stuff that doesn't + * fit anywhere else' class!" + *

* This class contains some useful static methods for use anywhere - items, entities, spells, events, blocks, etc. * Broadly speaking, these fall into the following categories: *

From 719c6d5fbb26ca85bfab1778ad1e8e6983bdc55a Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 9 Jun 2018 17:33:37 +0100 Subject: [PATCH 13/68] Add new spell types --- .../java/electroblob/wizardry/constants/SpellType.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/constants/SpellType.java b/src/main/java/electroblob/wizardry/constants/SpellType.java index 5f58dede..e1791940 100644 --- a/src/main/java/electroblob/wizardry/constants/SpellType.java +++ b/src/main/java/electroblob/wizardry/constants/SpellType.java @@ -6,7 +6,14 @@ import net.minecraftforge.fml.relauncher.SideOnly; public enum SpellType { - ATTACK("attack"), DEFENCE("defence"), UTILITY("utility"), MINION("minion"); + ATTACK("attack"), + DEFENCE("defence"), + UTILITY("utility"), + MINION("minion"), + BUFF("buff"), + CONSTRUCT("construct"), + PROJECTILE("projectile"), + ALTERATION("alteration"); private final String unlocalisedName; From b6400c72a7bd6fbbb8ba542f8279fc40f4ddb133 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 9 Jun 2018 17:36:54 +0100 Subject: [PATCH 14/68] Genericise spell casting AI class --- .../entity/living/EntityAIAttackSpell.java | 51 ++++++++----------- .../entity/living/EntityEvilWizard.java | 2 +- .../wizardry/entity/living/EntityPhoenix.java | 2 +- .../entity/living/EntityShadowWraith.java | 2 +- .../entity/living/EntityStormElemental.java | 2 +- .../wizardry/entity/living/EntityWizard.java | 2 +- 6 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java index e4384e9b..57e5cadf 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java @@ -22,14 +22,14 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage; * Entity AI class for use by instances of {@link ISpellCaster}. This deals with pathing, the spell casting itself and * the attack cooldown. Also provides an automatic implementation of continuous spell casting using the methods * specified in {@code ISpellCaster}; all the entity class needs to do is implement those methods. + * @param The type of entity that this AI belongs to; must both extend EntityLiving and implement ISpellCaster */ -public class EntityAIAttackSpell extends EntityAIBase { +// Mmmm generics... +public class EntityAIAttackSpell extends EntityAIBase { - /** The entity the AI instance has been applied to. */ - private final EntityLiving attacker; - /** The entity the AI instance has been applied to, but as an ISpellCaster. */ - private final ISpellCaster caster; - /** The tagret to be attacked. */ + /** The entity the AI instance has been applied to. Thanks to type parameters, methods from both EntityLiving and + * ISummonedCreature may be invoked on this field. */ + private final T attacker; private EntityLivingBase target; /** * Decremented each tick while greater than 0. When a spell is cast, this is set to that spell's cooldown plus the @@ -65,23 +65,14 @@ public class EntityAIAttackSpell extends EntityAIBase { * attacking, and also the amount that is added to the cooldown of the spell that has just been cast. * @param continuousSpellDuration The number of ticks that continuous spells will be cast for before cooling down. */ - public EntityAIAttackSpell(ISpellCaster attacker, double speed, float maxDistance, int baseCooldown, - int continuousSpellDuration){ - + public EntityAIAttackSpell(T attacker, double speed, float maxDistance, int baseCooldown, int continuousSpellDuration){ this.cooldown = -1; - - if(!(attacker instanceof EntityLiving)){ - throw new IllegalArgumentException( - "Tried to create an EntityAICastSpell for an entity that isn't an EntityLiving"); - }else{ - this.caster = attacker; - this.attacker = (EntityLiving)attacker; - this.baseCooldown = baseCooldown; - this.continuousSpellDuration = continuousSpellDuration; - this.speed = speed; - this.maxAttackDistance = maxDistance * maxDistance; - this.setMutexBits(3); - } + this.attacker = attacker; + this.baseCooldown = baseCooldown; + this.continuousSpellDuration = continuousSpellDuration; + this.speed = speed; + this.maxAttackDistance = maxDistance * maxDistance; + this.setMutexBits(3); } @Override @@ -112,7 +103,7 @@ public class EntityAIAttackSpell extends EntityAIBase { } private void setContinuousSpellAndNotify(Spell spell, SpellModifiers modifiers){ - caster.setContinuousSpell(spell); + attacker.setContinuousSpell(spell); WizardryPacketHandler.net.sendToAllAround( new PacketNPCCastSpell.Message(attacker.getEntityId(), target == null ? -1 : target.getEntityId(), EnumHand.MAIN_HAND, spell.id(), modifiers), @@ -151,11 +142,11 @@ public class EntityAIAttackSpell extends EntityAIBase { if(distanceSq > (double)this.maxAttackDistance || !targetIsVisible // ...or the spell is cancelled via events... || MinecraftForge.EVENT_BUS - .post(new SpellCastEvent.Tick(attacker, caster.getContinuousSpell(), caster.getModifiers(), + .post(new SpellCastEvent.Tick(attacker, attacker.getContinuousSpell(), attacker.getModifiers(), Source.NPC, this.continuousSpellDuration - this.continuousSpellTimer)) // ...or the spell no longer succeeds... - || !caster.getContinuousSpell().cast(attacker.world, attacker, EnumHand.MAIN_HAND, - this.continuousSpellDuration - this.continuousSpellTimer, target, caster.getModifiers()) + || !attacker.getContinuousSpell().cast(attacker.world, attacker, EnumHand.MAIN_HAND, + this.continuousSpellDuration - this.continuousSpellTimer, target, attacker.getModifiers()) // ...or the time has elapsed... || this.continuousSpellTimer == 0){ @@ -167,8 +158,8 @@ public class EntityAIAttackSpell extends EntityAIBase { }else if(this.continuousSpellDuration - this.continuousSpellTimer == 1){ // On the first tick, if the spell did succeed, fire SpellCastEvent.Post. - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(attacker, caster.getContinuousSpell(), - caster.getModifiers(), Source.NPC)); + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(attacker, attacker.getContinuousSpell(), + attacker.getModifiers(), Source.NPC)); } }else if(--this.cooldown == 0){ @@ -180,7 +171,7 @@ public class EntityAIAttackSpell extends EntityAIBase { double dx = target.posX - attacker.posX; double dz = target.posZ - attacker.posZ; - List spells = new ArrayList(caster.getSpells()); + List spells = new ArrayList(attacker.getSpells()); if(spells.size() > 0){ @@ -194,7 +185,7 @@ public class EntityAIAttackSpell extends EntityAIBase { spell = spells.get(attacker.world.rand.nextInt(spells.size())); - SpellModifiers modifiers = caster.getModifiers(); + SpellModifiers modifiers = attacker.getModifiers(); if(spell != null && attemptCastSpell(spell, modifiers)){ // The spell worked, so we're done! diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java index 74b4e734..ad9119b3 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java @@ -55,7 +55,7 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData { - private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50); + private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50); public int textureIndex = 0; diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java index 0414dfc8..54325cd5 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java @@ -27,7 +27,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste private double AISpeed = 0.5; // Can attack for 7 seconds, then must cool down for 3. - private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 60, 140); + private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 60, 140); private Spell continuousSpell; diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java index 9b03593b..835fab80 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java @@ -31,7 +31,7 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell private double AISpeed = 1.0; - private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 30, 0); + private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 30, 0); private static final List attack = Collections.singletonList(Spells.darkness_orb); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java index 6991713a..f86586c5 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java @@ -29,7 +29,7 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe private double AISpeed = 1.0; - private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 30, 0); + private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 30, 0); private static final List attack = Collections.singletonList(Spells.lightning_disc); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 62da92ce..ccdec06d 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -84,7 +84,7 @@ import net.minecraftforge.oredict.OreDictionary; @Mod.EventBusSubscriber public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISpellCaster, IEntityAdditionalSpawnData { - private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50); + private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50); public int textureIndex = 0; From 29261082f1d4ccdb21563f4a0685a2305006136b Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 22:25:54 +0100 Subject: [PATCH 15/68] Spell hierarchisation and refactoring, plus miscellaneous renaming and minor refactoring - Adds new generic spell superclasses which aim to group spells such that duplicate code is eliminated, and functions standardised, as much as possible. - Removes numerous spell classes which are no longer required as a result of this change, and replaces them with instances of the relevant generic spell classes. - Changes the remaining spell classes to fit with the new system, mostly by having them extend the generic spell classes. - Completes the transfer of particle spawning to the ParticleBuilder system. --- .../wizardry/block/BlockStatue.java | 88 ++++- .../client/WizardryClientEventHandler.java | 2 +- .../wizardry/client/renderer/LayerStone.java | 4 +- .../wizardry/client/renderer/RenderDecay.java | 2 +- .../entity/construct/EntityArrowRain.java | 12 +- .../entity/construct/EntityBlackHole.java | 27 +- .../entity/construct/EntityBlizzard.java | 11 +- .../entity/construct/EntityBubble.java | 7 - .../entity/construct/EntityDecay.java | 39 +-- .../entity/construct/EntityEarthquake.java | 31 +- .../entity/construct/EntityFireRing.java | 11 +- .../entity/construct/EntityFireSigil.java | 30 +- .../entity/construct/EntityForcefield.java | 37 +- .../entity/construct/EntityFrostSigil.java | 40 +-- .../entity/construct/EntityHailstorm.java | 19 +- .../entity/construct/EntityHammer.java | 11 +- .../entity/construct/EntityHealAura.java | 15 +- .../entity/construct/EntityIceSpike.java | 7 +- .../construct/EntityLightningPulse.java | 12 +- .../construct/EntityLightningSigil.java | 33 +- .../construct/EntityMagicConstruct.java | 24 +- .../entity/construct/EntityTornado.java | 10 +- .../entity/living/EntityBlazeMinion.java | 49 +-- .../wizardry/entity/living/EntityDecoy.java | 8 +- .../entity/living/EntityEvilWizard.java | 12 + .../entity/living/EntityIceGiant.java | 125 ++----- .../entity/living/EntityIceWraith.java | 21 +- .../entity/living/EntityLightningWraith.java | 31 +- .../entity/living/EntityMagicSlime.java | 81 +---- .../wizardry/entity/living/EntityPhoenix.java | 10 +- .../entity/living/EntityShadowWraith.java | 14 +- .../entity/living/EntitySilverfishMinion.java | 95 +---- .../entity/living/EntitySkeletonMinion.java | 96 +---- .../entity/living/EntitySpiderMinion.java | 89 +---- .../entity/living/EntityStormElemental.java | 6 +- .../entity/living/EntitySummonedCreature.java | 57 +-- .../living/EntityWitherSkeletonMinion.java | 103 ++---- .../wizardry/entity/living/EntityWizard.java | 14 +- .../entity/living/EntityZombieMinion.java | 19 +- .../wizardry/entity/living/ISpellCaster.java | 11 + .../entity/living/ISummonedCreature.java | 8 + .../entity/projectile/EntityBomb.java | 18 +- .../entity/projectile/EntityDarknessOrb.java | 34 +- .../entity/projectile/EntityDart.java | 55 +-- .../entity/projectile/EntityFirebolt.java | 28 +- .../entity/projectile/EntityFirebomb.java | 21 +- .../entity/projectile/EntityForceArrow.java | 29 +- .../entity/projectile/EntityForceOrb.java | 46 +-- .../entity/projectile/EntityIceCharge.java | 28 +- .../entity/projectile/EntityIceLance.java | 82 +---- .../entity/projectile/EntityIceShard.java | 69 +--- .../projectile/EntityLightningArrow.java | 55 +-- .../projectile/EntityLightningDisc.java | 27 +- .../entity/projectile/EntityMagicArrow.java | 329 ++++++++---------- .../entity/projectile/EntityMagicMissile.java | 48 +-- .../projectile/EntityMagicProjectile.java | 107 +++--- .../entity/projectile/EntityPoisonBomb.java | 24 +- .../entity/projectile/EntitySmokeBomb.java | 19 +- .../entity/projectile/EntitySpark.java | 44 +-- .../entity/projectile/EntitySparkBomb.java | 48 +-- .../entity/projectile/EntityThunderbolt.java | 40 +-- .../wizardry/item/ItemFirebomb.java | 5 +- .../wizardry/item/ItemPoisonBomb.java | 5 +- .../wizardry/item/ItemSmokeBomb.java | 5 +- .../electroblob/wizardry/item/ItemWand.java | 4 +- .../wizardry/item/ItemWizardArmour.java | 4 +- .../wizardry/potion/PotionDecay.java | 9 +- .../electroblob/wizardry/registry/Spells.java | 143 +++++--- .../electroblob/wizardry/spell/Agility.java | 51 --- .../java/electroblob/wizardry/spell/Arc.java | 93 ++--- .../wizardry/spell/ArcaneJammer.java | 93 ++--- .../electroblob/wizardry/spell/ArrowRain.java | 64 ++-- .../electroblob/wizardry/spell/Banish.java | 139 ++------ .../electroblob/wizardry/spell/BlackHole.java | 70 ---- .../electroblob/wizardry/spell/Blink.java | 6 +- .../electroblob/wizardry/spell/Blizzard.java | 81 ----- .../electroblob/wizardry/spell/Bubble.java | 125 +++---- .../wizardry/spell/ChainLightning.java | 207 ++++------- .../wizardry/spell/Clairvoyance.java | 18 +- .../electroblob/wizardry/spell/Cobwebs.java | 130 ++----- .../wizardry/spell/ConjureArmour.java | 38 +- .../wizardry/spell/ConjureBow.java | 60 ---- .../wizardry/spell/ConjurePickaxe.java | 50 --- .../wizardry/spell/ConjureSword.java | 49 --- .../wizardry/spell/CureEffects.java | 63 +--- .../wizardry/spell/CurseOfSoulbinding.java | 76 ++-- .../wizardry/spell/DarknessOrb.java | 68 ---- .../wizardry/spell/Darkvision.java | 45 --- .../java/electroblob/wizardry/spell/Dart.java | 67 ---- .../electroblob/wizardry/spell/Decay.java | 97 ++---- .../electroblob/wizardry/spell/Decoy.java | 80 ++--- .../electroblob/wizardry/spell/Detonate.java | 128 ++----- .../wizardry/spell/Diamondflesh.java | 53 --- .../wizardry/spell/Earthquake.java | 66 ++-- .../wizardry/spell/Entrapment.java | 116 ++---- .../wizardry/spell/FireResistance.java | 78 ----- .../electroblob/wizardry/spell/FireSigil.java | 51 --- .../electroblob/wizardry/spell/Fireball.java | 2 +- .../electroblob/wizardry/spell/Firebolt.java | 69 ---- .../electroblob/wizardry/spell/Firebomb.java | 70 ---- .../electroblob/wizardry/spell/Fireskin.java | 70 ---- .../electroblob/wizardry/spell/Firestorm.java | 125 ++++--- .../electroblob/wizardry/spell/FlameRay.java | 135 +++---- .../wizardry/spell/FlamingAxe.java | 42 +-- .../wizardry/spell/FlamingWeapon.java | 22 +- .../electroblob/wizardry/spell/Flight.java | 25 +- .../wizardry/spell/FontOfMana.java | 20 +- .../wizardry/spell/FontOfVitality.java | 57 --- .../wizardry/spell/ForceArrow.java | 69 ---- .../electroblob/wizardry/spell/ForceOrb.java | 70 ---- .../wizardry/spell/Forcefield.java | 73 ---- .../wizardry/spell/ForestsCurse.java | 88 ++--- .../electroblob/wizardry/spell/Freeze.java | 193 +++------- .../wizardry/spell/FreezingWeapon.java | 24 +- .../electroblob/wizardry/spell/FrostAxe.java | 45 +-- .../electroblob/wizardry/spell/FrostRay.java | 182 ++++------ .../wizardry/spell/FrostSigil.java | 51 --- .../electroblob/wizardry/spell/Glide.java | 23 +- .../wizardry/spell/GreaterFireball.java | 2 +- .../wizardry/spell/GreaterHeal.java | 60 +--- .../electroblob/wizardry/spell/GroupHeal.java | 38 +- .../wizardry/spell/GrowthAura.java | 2 +- .../electroblob/wizardry/spell/Hailstorm.java | 60 ++-- .../java/electroblob/wizardry/spell/Heal.java | 63 +--- .../electroblob/wizardry/spell/HealAlly.java | 68 ++-- .../wizardry/spell/HealingAura.java | 68 ---- .../wizardry/spell/HomingSpark.java | 65 ---- .../electroblob/wizardry/spell/IceAge.java | 2 +- .../electroblob/wizardry/spell/IceCharge.java | 70 ---- .../electroblob/wizardry/spell/IceLance.java | 67 ---- .../electroblob/wizardry/spell/IceShard.java | 67 ---- .../electroblob/wizardry/spell/IceShroud.java | 71 ---- .../electroblob/wizardry/spell/IceSpikes.java | 117 ++----- .../electroblob/wizardry/spell/IceStatue.java | 138 ++------ .../electroblob/wizardry/spell/Ignite.java | 163 ++------- .../wizardry/spell/ImbueWeapon.java | 28 +- .../wizardry/spell/Intimidate.java | 23 +- .../wizardry/spell/InvigoratingPresence.java | 28 +- .../wizardry/spell/Invisibility.java | 78 ----- .../wizardry/spell/InvokeWeather.java | 22 +- .../electroblob/wizardry/spell/Ironflesh.java | 79 ----- .../java/electroblob/wizardry/spell/Leap.java | 4 +- .../wizardry/spell/Levitation.java | 18 +- .../electroblob/wizardry/spell/LifeDrain.java | 137 +++----- .../electroblob/wizardry/spell/Light.java | 4 +- .../wizardry/spell/LightningArrow.java | 69 ---- .../wizardry/spell/LightningBolt.java | 78 ++--- .../wizardry/spell/LightningDisc.java | 69 ---- .../wizardry/spell/LightningHammer.java | 53 +-- .../wizardry/spell/LightningPulse.java | 28 +- .../wizardry/spell/LightningRay.java | 175 ++++------ .../wizardry/spell/LightningSigil.java | 53 --- .../wizardry/spell/LightningWeb.java | 296 +++++++--------- .../wizardry/spell/MagicMissile.java | 71 ---- .../wizardry/spell/Metamorphosis.java | 86 +++-- .../electroblob/wizardry/spell/Meteor.java | 53 ++- .../wizardry/spell/MindControl.java | 113 ++---- .../electroblob/wizardry/spell/MindTrick.java | 88 ++--- .../java/electroblob/wizardry/spell/None.java | 4 +- .../electroblob/wizardry/spell/Oakflesh.java | 79 ----- .../electroblob/wizardry/spell/Petrify.java | 136 ++------ .../electroblob/wizardry/spell/PhaseStep.java | 6 +- .../wizardry/spell/PlagueOfDarkness.java | 36 +- .../wizardry/spell/PocketFurnace.java | 4 +- .../wizardry/spell/PocketWorkbench.java | 2 +- .../electroblob/wizardry/spell/Poison.java | 143 +++----- .../wizardry/spell/PoisonBomb.java | 70 ---- .../wizardry/spell/ReplenishHunger.java | 36 +- .../wizardry/spell/RingOfFire.java | 74 ---- .../wizardry/spell/ShadowWard.java | 4 +- .../electroblob/wizardry/spell/Shield.java | 2 +- .../electroblob/wizardry/spell/Shockwave.java | 32 +- .../wizardry/spell/SilverfishSwarm.java | 49 --- .../wizardry/spell/SixthSense.java | 2 +- .../electroblob/wizardry/spell/Slime.java | 119 +++---- .../electroblob/wizardry/spell/SmokeBomb.java | 70 ---- .../electroblob/wizardry/spell/Snare.java | 94 +++-- .../electroblob/wizardry/spell/Snowball.java | 2 +- .../electroblob/wizardry/spell/SparkBomb.java | 70 ---- .../wizardry/spell/SpectralPathway.java | 2 +- .../electroblob/wizardry/spell/Spell.java | 75 ++-- .../wizardry/spell/SpellAreaEffect.java | 140 ++++++++ .../wizardry/spell/SpellArrow.java | 135 +++++++ .../electroblob/wizardry/spell/SpellBuff.java | 153 ++++++++ .../wizardry/spell/SpellConjuration.java | 120 +++++++ .../wizardry/spell/SpellConstruct.java | 185 ++++++++++ .../wizardry/spell/SpellConstructRanged.java | 133 +++++++ .../wizardry/spell/SpellMinion.java | 165 +++++++++ .../wizardry/spell/SpellProjectile.java | 135 +++++++ .../electroblob/wizardry/spell/SpellRay.java | 320 +++++++++++++++++ .../wizardry/spell/SpiderSwarm.java | 76 ---- .../wizardry/spell/StaticAura.java | 71 ---- .../wizardry/spell/SummonBlaze.java | 71 ---- .../wizardry/spell/SummonIceGiant.java | 53 --- .../wizardry/spell/SummonIceWraith.java | 70 ---- .../wizardry/spell/SummonIronGolem.java | 27 +- .../wizardry/spell/SummonLightningWraith.java | 70 ---- .../wizardry/spell/SummonPhoenix.java | 46 --- .../wizardry/spell/SummonShadowWraith.java | 37 +- .../wizardry/spell/SummonSkeleton.java | 63 +--- .../wizardry/spell/SummonSkeletonLegion.java | 76 +--- .../wizardry/spell/SummonSnowGolem.java | 27 +- .../wizardry/spell/SummonSpiritHorse.java | 2 +- .../wizardry/spell/SummonSpiritWolf.java | 2 +- .../wizardry/spell/SummonStormElemental.java | 45 --- .../wizardry/spell/SummonWitherSkeleton.java | 76 ---- .../wizardry/spell/SummonZombie.java | 67 ---- .../wizardry/spell/Telekinesis.java | 127 +++---- .../wizardry/spell/Thunderbolt.java | 68 ---- .../wizardry/spell/Thunderstorm.java | 53 ++- .../electroblob/wizardry/spell/Tornado.java | 62 +--- .../wizardry/spell/Transience.java | 2 +- .../wizardry/spell/Transportation.java | 2 +- .../wizardry/spell/VanishingBox.java | 7 +- .../wizardry/spell/WallOfFrost.java | 140 +++++--- .../wizardry/spell/WaterBreathing.java | 44 --- .../electroblob/wizardry/spell/Whirlwind.java | 78 +---- .../electroblob/wizardry/spell/Wither.java | 115 ++---- .../wizardry/spell/WitherSkull.java | 2 +- .../wizardry/util/ParticleBuilder.java | 18 + .../wizardry/util/SpellModifiers.java | 4 +- .../wizardry/util/WizardryUtilities.java | 92 ++--- 222 files changed, 4412 insertions(+), 9016 deletions(-) delete mode 100644 src/main/java/electroblob/wizardry/spell/Agility.java delete mode 100644 src/main/java/electroblob/wizardry/spell/BlackHole.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Blizzard.java delete mode 100644 src/main/java/electroblob/wizardry/spell/ConjureBow.java delete mode 100644 src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java delete mode 100644 src/main/java/electroblob/wizardry/spell/ConjureSword.java delete mode 100644 src/main/java/electroblob/wizardry/spell/DarknessOrb.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Darkvision.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Dart.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Diamondflesh.java delete mode 100644 src/main/java/electroblob/wizardry/spell/FireResistance.java delete mode 100644 src/main/java/electroblob/wizardry/spell/FireSigil.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Firebolt.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Firebomb.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Fireskin.java delete mode 100644 src/main/java/electroblob/wizardry/spell/FontOfVitality.java delete mode 100644 src/main/java/electroblob/wizardry/spell/ForceArrow.java delete mode 100644 src/main/java/electroblob/wizardry/spell/ForceOrb.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Forcefield.java delete mode 100644 src/main/java/electroblob/wizardry/spell/FrostSigil.java delete mode 100644 src/main/java/electroblob/wizardry/spell/HealingAura.java delete mode 100644 src/main/java/electroblob/wizardry/spell/HomingSpark.java delete mode 100644 src/main/java/electroblob/wizardry/spell/IceCharge.java delete mode 100644 src/main/java/electroblob/wizardry/spell/IceLance.java delete mode 100644 src/main/java/electroblob/wizardry/spell/IceShard.java delete mode 100644 src/main/java/electroblob/wizardry/spell/IceShroud.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Invisibility.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Ironflesh.java delete mode 100644 src/main/java/electroblob/wizardry/spell/LightningArrow.java delete mode 100644 src/main/java/electroblob/wizardry/spell/LightningDisc.java delete mode 100644 src/main/java/electroblob/wizardry/spell/LightningSigil.java delete mode 100644 src/main/java/electroblob/wizardry/spell/MagicMissile.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Oakflesh.java delete mode 100644 src/main/java/electroblob/wizardry/spell/PoisonBomb.java delete mode 100644 src/main/java/electroblob/wizardry/spell/RingOfFire.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SilverfishSwarm.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SmokeBomb.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SparkBomb.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellAreaEffect.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellArrow.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellBuff.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellConjuration.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellConstruct.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellMinion.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellProjectile.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpellRay.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SpiderSwarm.java delete mode 100644 src/main/java/electroblob/wizardry/spell/StaticAura.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SummonBlaze.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SummonIceGiant.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SummonIceWraith.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SummonLightningWraith.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SummonPhoenix.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SummonStormElemental.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java delete mode 100644 src/main/java/electroblob/wizardry/spell/SummonZombie.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Thunderbolt.java delete mode 100644 src/main/java/electroblob/wizardry/spell/WaterBreathing.java diff --git a/src/main/java/electroblob/wizardry/block/BlockStatue.java b/src/main/java/electroblob/wizardry/block/BlockStatue.java index d4c3d891..d52295b8 100644 --- a/src/main/java/electroblob/wizardry/block/BlockStatue.java +++ b/src/main/java/electroblob/wizardry/block/BlockStatue.java @@ -2,13 +2,14 @@ package electroblob.wizardry.block; import java.util.Random; -import electroblob.wizardry.spell.Petrify; import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.BlockContainer; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLiving; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.EnumBlockRenderType; @@ -23,6 +24,9 @@ import net.minecraftforge.fml.relauncher.SideOnly; public class BlockStatue extends BlockContainer { private boolean isIce; + + /** The NBT tag name for storing the petrified flag (used for rendering) in the target's tag compound. */ + public static final String NBT_KEY = "petrified"; public BlockStatue(Material material){ super(material); @@ -146,7 +150,7 @@ public class BlockStatue extends BlockContainer { // This is only when position == 1 because world.destroyBlock calls this function for the other blocks. if(tileentity != null && tileentity.position == 1 && tileentity.creature != null){ - tileentity.creature.getEntityData().removeTag(Petrify.NBT_KEY); + tileentity.creature.getEntityData().removeTag(BlockStatue.NBT_KEY); tileentity.creature.isDead = false; world.spawnEntity(tileentity.creature); } @@ -166,4 +170,84 @@ public class BlockStatue extends BlockContainer { return this.isIce && block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side); } + + /** + * Turns the given entity into a statue. The type of statue depends on the block instance this method was invoked on. + * @param entity The entity to turn into a statue. + * @param duration The time for which the entity should remain a statue. For petrified creatures, this is the minimum + * time it can stay as a statue. + * @return True if the entity was successfully turned into a statue, false if not (i.e. something was in the way). + */ + // Making this an instance method means it works equally well for both types of statue + public boolean convertToStatue(EntityLiving entity, int duration){ + + if(entity.deathTime > 0) return false; + + BlockPos pos = new BlockPos(entity); + World world = entity.world; + + entity.hurtTime = 0; // Stops the entity looking red while frozen and the resulting z-fighting + entity.extinguish(); + + // Short mobs such as spiders and pigs + if((entity.height < 1.2 || entity.isChild()) && WizardryUtilities.canBlockBeReplaced(world, pos)){ + + world.setBlockState(pos, this.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(entity, 1, 1); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration); + } + + if(!this.isIce) entity.getEntityData().setBoolean(NBT_KEY, true); + entity.setDead(); + return true; + } + // Normal sized mobs like zombies and skeletons + else if(entity.height < 2.5 && WizardryUtilities.canBlockBeReplaced(world, pos) + && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + + world.setBlockState(pos, this.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(entity, 1, 2); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration); + } + + world.setBlockState(pos.up(), this.getDefaultState()); + if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(entity, 2, 2); + } + + if(!this.isIce) entity.getEntityData().setBoolean(NBT_KEY, true); + entity.setDead(); + return true; + } + // Tall mobs like endermen + else if(WizardryUtilities.canBlockBeReplaced(world, pos) + && WizardryUtilities.canBlockBeReplaced(world, pos.up()) + && WizardryUtilities.canBlockBeReplaced(world, pos.up(2))){ + + world.setBlockState(pos, this.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(entity, 1, 3); + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration); + } + + world.setBlockState(pos.up(), this.getDefaultState()); + if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(entity, 2, 3); + } + + world.setBlockState(pos.up(2), this.getDefaultState()); + if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(entity, 3, 3); + } + + if(!this.isIce) entity.getEntityData().setBoolean(NBT_KEY, true); + entity.setDead(); + return true; + } + + return false; + } + } diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java index 04ff6202..e9ea54fb 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -208,7 +208,7 @@ public final class WizardryClientEventHandler { Minecraft mc = Minecraft.getMinecraft(); WizardData properties = WizardData.get(mc.player); - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.world, mc.player, 16); + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.world, mc.player, 16, false); RenderManager renderManager = event.getRenderer().getRenderManager(); ItemStack wand = mc.player.getHeldItemMainhand(); diff --git a/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java b/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java index 3630e58a..7978e26e 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java +++ b/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java @@ -4,8 +4,8 @@ import java.util.Map.Entry; import org.lwjgl.opengl.GL11; +import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.client.ClientProxy; -import electroblob.wizardry.spell.Petrify; import net.minecraft.client.Minecraft; import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelBiped; @@ -60,7 +60,7 @@ public class LayerStone implements LayerRenderer { public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){ - if(entity.getEntityData().getBoolean(Petrify.NBT_KEY)){ + if(entity.getEntityData().getBoolean(BlockStatue.NBT_KEY)){ GlStateManager.enableLighting(); int i = this.getBlockBrightnessForEntity(entity, partialTicks); diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderDecay.java b/src/main/java/electroblob/wizardry/client/renderer/RenderDecay.java index 272b8527..b631a5a7 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderDecay.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderDecay.java @@ -44,7 +44,7 @@ public class RenderDecay extends Render { GlStateManager.rotate(-90, 1, 0, 0); - float scale = 2 * Math.min(1, (float)(EntityDecay.LIFETIME - entity.ticksExisted) / 50f); + float scale = 2 * Math.min(1, (float)(entity.lifetime - entity.ticksExisted) / 50f); GlStateManager.scale(scale, scale, scale); diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java b/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java index 1ad7632d..b2ecca42 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java @@ -1,6 +1,5 @@ package electroblob.wizardry.entity.construct; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.projectile.EntityTippedArrow; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; @@ -8,15 +7,8 @@ import net.minecraft.world.World; public class EntityArrowRain extends EntityMagicConstruct { - public EntityArrowRain(World par1World){ - super(par1World); - this.height = 3.0f; - this.width = 5.0f; - } - - public EntityArrowRain(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); + public EntityArrowRain(World world){ + super(world); this.height = 3.0f; this.width = 5.0f; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java index b7d77fb8..68fc1ae6 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java @@ -12,8 +12,9 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.SPacketEntityVelocity; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; public class EntityBlackHole extends EntityMagicConstruct { @@ -34,21 +35,6 @@ public class EntityBlackHole extends EntityMagicConstruct { } } - public EntityBlackHole(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); - this.width = 6.0f; - this.height = 3.0f; - randomiser = new int[30]; - for(int i = 0; i < randomiser.length; i++){ - randomiser[i] = this.rand.nextInt(10); - } - randomiser2 = new int[30]; - for(int i = 0; i < randomiser2.length; i++){ - randomiser2[i] = this.rand.nextInt(10); - } - } - @Override protected void readEntityFromNBT(NBTTagCompound nbttagcompound){ super.readEntityFromNBT(nbttagcompound); @@ -135,11 +121,10 @@ public class EntityBlackHole extends EntityMagicConstruct { } } } - - /** - * Checks using a Vec3dd to determine if this entity is within range of that vector to be rendered. Args: Vec3dD - */ - public boolean isInRangeToRenderVec3dD(Vec3d par1Vec3d){ + + @Override + @SideOnly(Side.CLIENT) + public boolean isInRangeToRenderDist(double distance){ return true; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java index 358eb4a6..c45abe77 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java @@ -16,15 +16,8 @@ import net.minecraft.world.World; public class EntityBlizzard extends EntityMagicConstruct { - public EntityBlizzard(World par1World){ - super(par1World); - this.height = 1.0f; - this.width = 1.0f; - } - - public EntityBlizzard(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); + public EntityBlizzard(World world){ + super(world); this.height = 1.0f; this.width = 1.0f; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java index a864526b..58c3e0e5 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java @@ -28,13 +28,6 @@ public class EntityBubble extends EntityMagicConstruct { super(world); } - public EntityBubble(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - boolean isDarkOrb, float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); - // this.setSize(0.1f, 0.1f); - this.isDarkOrb = isDarkOrb; - } - @Override public double getMountedYOffset(){ return 0.1; diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java index 19b150d6..6c40f523 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java @@ -10,23 +10,14 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class EntityDecay extends EntityMagicConstruct { public int textureIndex = 0; - public static final int LIFETIME = 400; - public EntityDecay(World par1World){ - super(par1World); - textureIndex = this.rand.nextInt(10); - this.height = 0.2f; - this.width = 2.0f; - } - - public EntityDecay(World par1World, double x, double y, double z, EntityLivingBase caster){ - super(par1World, x, y, z, caster, LIFETIME, 1); + public EntityDecay(World world){ + super(world); textureIndex = this.rand.nextInt(10); this.height = 0.2f; this.width = 2.0f; @@ -37,7 +28,7 @@ public class EntityDecay extends EntityMagicConstruct { super.onUpdate(); - if(this.rand.nextInt(700) == 0 && this.ticksExisted + 100 < LIFETIME) + if(this.rand.nextInt(700) == 0 && this.ticksExisted + 100 < lifetime) this.playSound(SoundEvents.BLOCK_LAVA_AMBIENT, 0.2F + rand.nextFloat() * 0.2F, 0.6F + rand.nextFloat() * 0.15F); @@ -50,7 +41,7 @@ public class EntityDecay extends EntityMagicConstruct { // damaged each tick. // In this case, we do want particles to be shown. if(!target.isPotionActive(WizardryPotions.decay)) - target.addPotionEffect(new PotionEffect(WizardryPotions.decay, LIFETIME, 0)); + target.addPotionEffect(new PotionEffect(WizardryPotions.decay, lifetime, 0)); } } @@ -67,23 +58,15 @@ public class EntityDecay extends EntityMagicConstruct { } } - protected void entityInit(){ - } + @Override protected void entityInit(){} + + @Override protected void readEntityFromNBT(NBTTagCompound nbttagcompound){} + + @Override protected void writeEntityToNBT(NBTTagCompound nbttagcompound){} @Override - protected void readEntityFromNBT(NBTTagCompound nbttagcompound){ - - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbttagcompound){ - - } - - /** - * Checks using a Vec3dd to determine if this entity is within range of that vector to be rendered. Args: Vec3dD - */ - public boolean isInRangeToRenderVec3dD(Vec3d par1Vec3d){ + public boolean isInRangeToRenderDist(double distance){ return true; } + } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java b/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java index abc8d982..4a26e83f 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java @@ -7,6 +7,7 @@ import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityFallingBlock; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.MobEffects; import net.minecraft.network.play.server.SPacketEntityVelocity; @@ -22,13 +23,6 @@ public class EntityEarthquake extends EntityMagicConstruct { this.width = 1.0f; } - public EntityEarthquake(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); - this.height = 1.0f; - this.width = 1.0f; - } - public void onUpdate(){ super.onUpdate(); @@ -99,19 +93,16 @@ public class EntityEarthquake extends EntityMagicConstruct { } } } - // TODO: Uncomment once 2.1.0 is released - // }else{ - // - // // Constant 15 blocks for now - // List targets = WizardryUtilities.getEntitiesWithinRadius(15, this.posX, this.posY, - // this.posZ, world, EntityPlayer.class); - // - // float magnitude = 6f * ((float)(this.lifetime - this.ticksExisted))/(float)this.lifetime; - // - // // Makes the screen shake - // for(EntityLivingBase target : targets){ - // target.setAngles(0, this.ticksExisted % 4 < 2 ? magnitude : -magnitude); - // } + }else{ + // Constant 15 blocks for now + List targets = WizardryUtilities.getEntitiesWithinRadius(15, posX, posY, posZ, world, EntityPlayer.class); + + float magnitude = 6f * ((float)(this.lifetime - this.ticksExisted))/(float)this.lifetime; + + // Makes the screen shake + for(EntityPlayer target : targets){ + target.rotationPitch = this.ticksExisted % 2 == 0 ? magnitude : -magnitude; + } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java index 97ed7876..5037b3bf 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java @@ -12,15 +12,8 @@ import net.minecraft.world.World; public class EntityFireRing extends EntityMagicConstruct { - public EntityFireRing(World par1World){ - super(par1World); - this.height = 1.0f; - this.width = 5.0f; - } - - public EntityFireRing(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); + public EntityFireRing(World world){ + super(world); this.height = 1.0f; this.width = 5.0f; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java index ecf45f74..bb6b7e34 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java @@ -13,34 +13,20 @@ import net.minecraft.world.World; public class EntityFireSigil extends EntityMagicConstruct { - public EntityFireSigil(World par1World){ - super(par1World); + public EntityFireSigil(World world){ + super(world); this.height = 0.2f; this.width = 2.0f; } - public EntityFireSigil(World par1World, double x, double y, double z, EntityLivingBase caster, - float damageMultiplier){ - super(par1World, x, y, z, caster, -1, damageMultiplier); - this.height = 0.2f; - this.width = 2.0f; - } - - // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow - // it to stick in blocks. - public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9){ - this.setPosition(par1, par3, par5); - this.setRotation(par7, par8); - } - + @Override public void onUpdate(){ super.onUpdate(); if(!this.world.isRemote){ - List targets = WizardryUtilities.getEntitiesWithinRadius(1.0d, this.posX, this.posY, - this.posZ, this.world); + List targets = WizardryUtilities.getEntitiesWithinRadius(width/2, posX, posY, posZ, world); for(EntityLivingBase target : targets){ @@ -76,13 +62,9 @@ public class EntityFireSigil extends EntityMagicConstruct { } @Override - protected void entityInit(){ + protected void entityInit(){} - } - - /** - * Return whether this entity should be rendered as on fire. - */ + @Override public boolean canRenderOnFire(){ return false; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java index 8717ccaa..1a77659d 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java @@ -20,40 +20,34 @@ public class EntityForcefield extends EntityMagicConstruct { super(world); this.height = 6; this.width = 6; - this.setEntityBoundingBox(new AxisAlignedBB(this.posX - 3, this.posY - 3, this.posZ - 3, this.posX + 3, - this.posY + 3, this.posZ + 3)); - } - - public EntityForcefield(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ // y-3 because it needs to be centred on the given position - // Damage multiplier is 1 because forcefields do no damage! - super(world, x, y - 3, z, caster, lifetime, 1.0f); - this.height = 6; - this.width = 6; - this.setEntityBoundingBox(new AxisAlignedBB(this.posX - 3, this.posY - 3, this.posZ - 3, this.posX + 3, - this.posY + 3, this.posZ + 3)); + this.setEntityBoundingBox(new AxisAlignedBB(posX - 3, posY - 3, posZ - 3, posX + 3, posY + 3, posZ + 3)); } + @Override public boolean canBeCollidedWith(){ return !this.isDead; } - public AxisAlignedBB getCollisionBox(Entity par1Entity){ - return par1Entity.getEntityBoundingBox(); + @Override + public AxisAlignedBB getCollisionBox(Entity entity){ + return entity.getEntityBoundingBox(); } + @Override public void onUpdate(){ super.onUpdate(); if(!this.world.isRemote){ - List targets = WizardryUtilities.getEntitiesWithinRadius(3.5, this.posX, this.posY + 3, - this.posZ, this.world); + // TESTME: This used to say posY+3, but I'm pretty sure that's wrong because of how the bounding box was set... + List targets = WizardryUtilities.getEntitiesWithinRadius(3.5, posX, posY, posZ, world); + for(EntityLivingBase target : targets){ if(this.isValidTarget(target)){ - double multiplier = (3.5 - target.getDistance(this.posX, this.posY + 3, this.posZ)) * 0.1; + double multiplier = (3.5 - target.getDistance(this.posX, this.posY, this.posZ)) * 0.1; target.addVelocity((target.posX - this.posX) * multiplier, - (target.posY - (this.posY + 3)) * multiplier, (target.posZ - this.posZ) * multiplier); + (target.posY - this.posY) * multiplier, (target.posZ - this.posZ) * multiplier); // Player motion is handled on that player's client so needs packets if(target instanceof EntityPlayerMP){ ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); @@ -78,19 +72,18 @@ public class EntityForcefield extends EntityMagicConstruct { } } - public boolean attackEntityFrom(DamageSource source, float par2){ + @Override + public boolean attackEntityFrom(DamageSource source, float damage){ if(source != null && source.getImmediateSource() != null){ // Now works for any source of damage. source.getImmediateSource().playSound(WizardrySounds.SPELL_DEFLECTION, 0.3f, 1.3f); } - super.attackEntityFrom(source, par2); + super.attackEntityFrom(source, damage); return false; } - /** - * Return whether this entity should be rendered as on fire. - */ + @Override public boolean canRenderOnFire(){ return false; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java index cb29f67e..1632335b 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java @@ -16,26 +16,13 @@ import net.minecraft.world.World; public class EntityFrostSigil extends EntityMagicConstruct { - public EntityFrostSigil(World par1World){ - super(par1World); + public EntityFrostSigil(World world){ + super(world); this.height = 0.2f; this.width = 2.0f; } - public EntityFrostSigil(World par1World, double x, double y, double z, EntityLivingBase caster, - float damageMultiplier){ - super(par1World, x, y, z, caster, -1, damageMultiplier); - this.height = 0.2f; - this.width = 2.0f; - } - - // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow - // it to stick in blocks. - public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9){ - this.setPosition(par1, par3, par5); - this.setRotation(par7, par8); - } - + @Override public void onUpdate(){ super.onUpdate(); @@ -48,20 +35,11 @@ public class EntityFrostSigil extends EntityMagicConstruct { for(EntityLivingBase target : targets){ if(this.isValidTarget(target)){ - - double velX = target.motionX; - double velY = target.motionY; - double velZ = target.motionZ; - - target.attackEntityFrom(this.getCaster() != null + + WizardryUtilities.attackEntityWithoutKnockback(target, this.getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.FROST) : DamageSource.MAGIC, 8); - // Removes knockback - target.motionX = velX; - target.motionY = velY; - target.motionZ = velZ; - if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 200, 1)); @@ -82,13 +60,9 @@ public class EntityFrostSigil extends EntityMagicConstruct { } @Override - protected void entityInit(){ + protected void entityInit(){} - } - - /** - * Return whether this entity should be rendered as on fire. - */ + @Override public boolean canRenderOnFire(){ return false; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java index 5bb73e18..6a2baaab 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java @@ -1,20 +1,12 @@ package electroblob.wizardry.entity.construct; import electroblob.wizardry.entity.projectile.EntityIceShard; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; public class EntityHailstorm extends EntityMagicConstruct { - public EntityHailstorm(World par1World){ - super(par1World); - this.height = 3.0f; - this.width = 5.0f; - } - - public EntityHailstorm(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); + public EntityHailstorm(World world){ + super(world); this.height = 3.0f; this.width = 5.0f; } @@ -25,12 +17,13 @@ public class EntityHailstorm extends EntityMagicConstruct { if(!this.world.isRemote){ // System.out.println(this.rotationYaw); - EntityIceShard iceshard = new EntityIceShard(world, this.posX + rand.nextDouble() * 6 - 3, - this.posY + rand.nextDouble() * 4 - 2, this.posZ + rand.nextDouble() * 6 - 3); + EntityIceShard iceshard = new EntityIceShard(world); + iceshard.setPosition(this.posX + rand.nextDouble() * 6 - 3, this.posY + rand.nextDouble() * 4 - 2, + this.posZ + rand.nextDouble() * 6 - 3); iceshard.motionX = Math.cos(Math.toRadians(this.rotationYaw + 90)); iceshard.motionY = -0.6; iceshard.motionZ = Math.sin(Math.toRadians(this.rotationYaw + 90)); - iceshard.setShootingEntity(this.getCaster()); + iceshard.setCaster(this.getCaster()); iceshard.damageMultiplier = this.damageMultiplier; this.world.spawnEntity(iceshard); } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java index a66fb43c..6f174d91 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java @@ -28,15 +28,8 @@ public class EntityHammer extends EntityMagicConstruct { /** How long the hammer has been falling for. */ public int fallTime; - public EntityHammer(World par1World){ - super(par1World); - this.setSize(1.0f, 1.9F); - this.noClip = false; - } - - public EntityHammer(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); + public EntityHammer(World world){ + super(world); this.setSize(1.0f, 1.9F); this.motionX = 0.0D; this.motionY = 0.0D; diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java index 8ca40faa..32e893f7 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java @@ -20,13 +20,7 @@ public class EntityHealAura extends EntityMagicConstruct { this.width = 5.0f; } - public EntityHealAura(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); - this.height = 1.0f; - this.width = 5.0f; - } - + @Override public void onUpdate(){ if(this.ticksExisted % 25 == 1){ @@ -37,8 +31,7 @@ public class EntityHealAura extends EntityMagicConstruct { if(!this.world.isRemote){ - List targets = WizardryUtilities.getEntitiesWithinRadius(2.5d, this.posX, this.posY, - this.posZ, this.world); + List targets = WizardryUtilities.getEntitiesWithinRadius(2.5, posX, posY, posZ, world); for(EntityLivingBase target : targets){ @@ -83,9 +76,7 @@ public class EntityHealAura extends EntityMagicConstruct { } } - /** - * Return whether this entity should be rendered as on fire. - */ + @Override public boolean canRenderOnFire(){ return false; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java b/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java index d415480e..86817bb4 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java @@ -16,12 +16,7 @@ public class EntityIceSpike extends EntityMagicConstruct { this.setSize(0.5f, 1.0f); } - public EntityIceSpike(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); - this.setSize(0.5f, 1.0f); - } - + @Override public void onUpdate(){ if(lifetime - this.ticksExisted < 15){ diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java index edab4346..b2d46ab5 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java @@ -1,8 +1,8 @@ package electroblob.wizardry.entity.construct; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; +@Deprecated // This needs changing into a particle public class EntityLightningPulse extends EntityMagicConstruct { public EntityLightningPulse(World world){ @@ -10,15 +10,7 @@ public class EntityLightningPulse extends EntityMagicConstruct { this.setSize(6, 0.2f); } - public EntityLightningPulse(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); - this.setSize(6, 0.2f); - } - - /** - * Return whether this entity should be rendered as on fire. - */ + @Override public boolean canRenderOnFire(){ return false; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java index 0c2bb112..62dcea76 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java @@ -16,26 +16,13 @@ import net.minecraft.world.World; public class EntityLightningSigil extends EntityMagicConstruct { - public EntityLightningSigil(World par1World){ - super(par1World); + public EntityLightningSigil(World world){ + super(world); this.height = 0.2f; this.width = 2.0f; } - public EntityLightningSigil(World par1World, double x, double y, double z, EntityLivingBase caster, - float damageMultiplier){ - super(par1World, x, y, z, caster, -1, damageMultiplier); - this.height = 0.2f; - this.width = 2.0f; - } - - // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow - // it to stick in blocks. - public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9){ - this.setPosition(par1, par3, par5); - this.setRotation(par7, par8); - } - + @Override public void onUpdate(){ super.onUpdate(); @@ -56,10 +43,8 @@ public class EntityLightningSigil extends EntityMagicConstruct { double velZ = target.motionZ; // Only works if target is actually damaged to account for hurtResistantTime - if(target.attackEntityFrom( - getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.SHOCK) - : DamageSource.MAGIC, - 6)){ + if(target.attackEntityFrom(getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, getCaster(), + DamageType.SHOCK) : DamageSource.MAGIC, 6)){ // Removes knockback target.motionX = velX; @@ -125,13 +110,9 @@ public class EntityLightningSigil extends EntityMagicConstruct { } @Override - protected void entityInit(){ + protected void entityInit(){} - } - - /** - * Return whether this entity should be rendered as on fire. - */ + @Override public boolean canRenderOnFire(){ return false; } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java b/src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java index 36e93b46..8951c743 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java @@ -10,6 +10,8 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; /** * This class is for all inanimate magical constructs which are not projectiles. It was made from scratch to provide a @@ -42,30 +44,18 @@ public abstract class EntityMagicConstruct extends Entity implements IEntityAddi /** The damage multiplier for this construct, determined by the wand with which it was cast. */ public float damageMultiplier = 1.0f; - public EntityMagicConstruct(World par1World){ - super(par1World); - this.height = 1.0f; - this.width = 1.0f; - this.noClip = true; - } - - public EntityMagicConstruct(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, - float damageMultiplier){ + public EntityMagicConstruct(World world){ super(world); this.height = 1.0f; this.width = 1.0f; - this.setPosition(x, y, z); - this.caster = new WeakReference(caster); this.noClip = true; - this.lifetime = lifetime; - this.damageMultiplier = damageMultiplier; } // Overrides the original to stop the entity moving when it intersects stuff. The default arrow does this to allow // it to stick in blocks. @Override - public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, - int posRotationIncrements, boolean teleport){ + @SideOnly(Side.CLIENT) + public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean teleport){ this.setPosition(x, y, z); this.setRotation(yaw, pitch); } @@ -136,6 +126,10 @@ public abstract class EntityMagicConstruct extends Entity implements IEntityAddi public EntityLivingBase getCaster(){ return caster == null ? null : caster.get(); } + + public void setCaster(EntityLivingBase caster){ + this.caster = new WeakReference(caster); + } /** * Shorthand for {@link WizardryUtilities#isValidTarget(Entity, Entity)}, with the owner of this construct as the diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java index 908ac574..f53c2b54 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java @@ -34,17 +34,13 @@ public class EntityTornado extends EntityMagicConstruct { this.width = 5.0f; this.isImmuneToFire = false; } - - public EntityTornado(World world, double x, double y, double z, EntityLivingBase caster, int lifetime, double velX, - double velZ, float damageMultiplier){ - super(world, x, y, z, caster, lifetime, damageMultiplier); - this.height = 8.0f; - this.width = 5.0f; + + public void setHorizontalVelocity(double velX, double velZ){ this.velX = velX; this.velZ = velZ; - this.isImmuneToFire = false; } + @Override public void onUpdate(){ super.onUpdate(); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java index c609375c..2bab8ebd 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java @@ -56,29 +56,12 @@ public class EntityBlazeMinion extends EntityBlaze implements ISummonedCreature this.casterUUID = uuid; } - /** - * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't matter - * because the client side entity immediately gets the lifetime value copied over to it by this class anyway. When - * extending this class, you must override this constructor or Minecraft won't like it, but there's no need to do - * anything inside it other than call super(). - */ + /** Creates a new blaze minion in the given world. */ public EntityBlazeMinion(World world){ super(world); this.experienceValue = 0; } - /** - * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when extending - * this class (be sure to call super()) so that AI and other things can be added. - */ - public EntityBlazeMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world); - this.setPosition(x, y, z); - this.casterReference = new WeakReference(caster); - this.experienceValue = 0; - this.lifetime = lifetime; - } - // EntityBlaze overrides // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its @@ -154,31 +137,13 @@ public class EntityBlazeMinion extends EntityBlaze implements ISummonedCreature // Recommended overrides - @Override - protected int getExperiencePoints(EntityPlayer player){ - return 0; - } - - @Override - protected boolean canDropLoot(){ - return false; - } - - @Override - protected Item getDropItem(){ - return null; - } - - @Override - protected ResourceLocation getLootTable(){ - return null; - } - + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } // This vanilla method has nothing to do with the custom despawn() method. - @Override - protected boolean canDespawn(){ - return false; - } + @Override protected boolean canDespawn(){ return false; } @Override public boolean canAttackClass(Class entityType){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java index 5ec8aa58..38665937 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java @@ -18,12 +18,14 @@ import net.minecraft.world.World; public class EntityDecoy extends EntitySummonedCreature { + /** Creates a new decoy in the given world. */ public EntityDecoy(World world){ super(world); } - - public EntityDecoy(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world, x, y, z, caster, lifetime); + + @Override + public void setCaster(EntityLivingBase caster){ + super.setCaster(caster); this.setAlwaysRenderNameTag(caster instanceof EntityPlayer); } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java index ad9119b3..44dc43b0 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java @@ -49,6 +49,7 @@ import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; @@ -178,6 +179,17 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity public Spell getContinuousSpell(){ return this.continuousSpell; } + + @Override + public int getAimingError(EnumDifficulty difficulty){ + // Being more intelligent than skeletons, wizards are a little more accurate. + switch(difficulty){ + case EASY: return 7; + case NORMAL: return 4; + case HARD: return 1; + default: return 7; // Peaceful counts as easy + } + } @Override public void onLivingUpdate(){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java index ebc34fdb..93e25d2b 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java @@ -37,61 +37,20 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature private UUID casterUUID; // Setter + getter implementations - @Override - public int getLifetime(){ - return lifetime; - } + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID(){ return casterUUID; } + @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } - @Override - public void setLifetime(int lifetime){ - this.lifetime = lifetime; - } - - @Override - public WeakReference getCasterReference(){ - return casterReference; - } - - @Override - public void setCasterReference(WeakReference reference){ - casterReference = reference; - } - - @Override - public UUID getCasterUUID(){ - return casterUUID; - } - - @Override - public void setCasterUUID(UUID uuid){ - this.casterUUID = uuid; - } - - /** - * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't matter - * because the client side entity immediately gets the lifetime value copied over to it by this class anyway. When - * extending this class, you must override this constructor or Minecraft won't like it, but there's no need to do - * anything inside it other than call super(). - */ + /** Creates a new ice giant in the given world. */ public EntityIceGiant(World world){ super(world); this.setSize(1.4F, 2.9F); this.experienceValue = 0; } - /** - * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when extending - * this class (be sure to call super()) so that AI and other things can be added. - */ - public EntityIceGiant(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world); - this.setSize(1.4F, 2.9F); - this.setPosition(x, y, z); - this.casterReference = new WeakReference(caster); - this.experienceValue = 0; - this.lifetime = lifetime; - } - @Override protected void initEntityAI(){ this.getNavigator().getNodeProcessor().setCanSwim(false); @@ -108,19 +67,9 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature // EntityIronGolem overrides - @Override - protected void updateAITasks(){ - } // Disables home-checking - - @Override - public Village getVillage(){ - return null; - } - - @Override - public int getHoldRoseTick(){ - return 0; - } + @Override protected void updateAITasks(){} // Disables home-checking + @Override public Village getVillage(){ return null; } + @Override public int getHoldRoseTick(){ return 0; } // Implementations @@ -137,20 +86,21 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature @Override public void onSpawn(){ + this.spawnParticleEffect(); } @Override public void onDespawn(){ this.playSound(WizardrySounds.SPELL_FREEZE, 1.0f, 1.0f); + this.spawnParticleEffect(); + } + + private void spawnParticleEffect(){ if(this.world.isRemote){ for(int i = 0; i < 30; i++){ float brightness = 0.5f + (rand.nextFloat() / 2); - ParticleBuilder.create(Type.SPARKLE) - .pos(this.posX - 1 + rand.nextDouble() * 2, this.posY + rand.nextDouble() * 3, this.posZ - 1 + rand.nextDouble() * 2) - .vel(0, -0.02, 0) - .lifetime(12 + rand.nextInt(8)) - .colour(brightness, brightness + 0.1f, 1.0f) - .spawn(world); + ParticleBuilder.create(Type.SPARKLE, this).vel(0, -0.02, 0).lifetime(12 + rand.nextInt(8)) + .colour(brightness, brightness + 0.1f, 1.0f).spawn(world); } } } @@ -161,9 +111,7 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature super.onLivingUpdate(); if(this.world.isRemote){ - ParticleBuilder.create(Type.SNOW) - .pos(this.posX - 1 + rand.nextDouble() * 2, this.posY + rand.nextDouble() * 3, this.posZ - 1 + rand.nextDouble() * 2) - .spawn(world); + ParticleBuilder.create(Type.SNOW, this).spawn(world); } } @@ -207,36 +155,13 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature // Recommended overrides - @Override - protected int getExperiencePoints(EntityPlayer player){ - return 0; - } - - @Override - protected boolean canDropLoot(){ - return false; - } - - @Override - protected Item getDropItem(){ - return null; - } - - @Override - protected ResourceLocation getLootTable(){ - return null; - } - - @Override - public boolean canPickUpLoot(){ - return false; - } - - // This vanilla method has nothing to do with the custom onDespawn() method. - @Override - protected boolean canDespawn(){ - return false; - } + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. + @Override protected boolean canDespawn(){ return false; } @Override public boolean canAttackClass(Class entityType){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java index e9ad7d34..3f2c07e1 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java @@ -25,12 +25,9 @@ public class EntityIceWraith extends EntityBlazeMinion { /** The version from EntityLivingBase is only used in onLivingUpdate, so it can safely be copied. */ private int jumpTicks; + /** Creates a new ice wraith in the given world. */ public EntityIceWraith(World world){ super(world); - } - - public EntityIceWraith(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world, x, y, z, caster, lifetime); this.isImmuneToFire = false; } @@ -204,32 +201,24 @@ public class EntityIceWraith extends EntityBlazeMinion { this.setMutexBits(3); } - /** - * Returns whether the EntityAIBase should begin execution. - */ + @Override public boolean shouldExecute(){ EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); return entitylivingbase != null && entitylivingbase.isEntityAlive(); } - /** - * Execute a one shot task or start executing a continuous task - */ + @Override public void startExecuting(){ this.attackStep = 0; } - /** - * Resets the task - */ + @Override public void resetTask(){ // This might be called setOnFire, but what it really controls is whether the wraith is in attack mode. this.blaze.setOnFire(false); } - /** - * Updates the task - */ + @Override public void updateTask(){ --this.attackTime; EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java index 3c90a171..fb5364e8 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java @@ -21,10 +21,6 @@ public class EntityLightningWraith extends EntityBlazeMinion { public EntityLightningWraith(World world){ super(world); - } - - public EntityLightningWraith(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world, x, y, z, caster, lifetime); this.isImmuneToFire = false; } @@ -44,12 +40,8 @@ public class EntityLightningWraith extends EntityBlazeMinion { if(this.world.isRemote){ for(int i = 0; i < 15; i++){ float brightness = 0.3f + (rand.nextFloat() / 2); - ParticleBuilder.create(Type.SPARKLE) - .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + this.height / 2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble()) - .vel(0, 0.05, 0) - .lifetime(20 + rand.nextInt(10)) - .colour(brightness, brightness + 0.2f, 1.0f) - .spawn(world); + ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) + .colour(brightness, brightness + 0.2f, 1.0f).spawn(world); } } } @@ -98,32 +90,24 @@ public class EntityLightningWraith extends EntityBlazeMinion { this.setMutexBits(3); } - /** - * Returns whether the EntityAIBase should begin execution. - */ + @Override public boolean shouldExecute(){ EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); return entitylivingbase != null && entitylivingbase.isEntityAlive(); } - /** - * Execute a one shot task or start executing a continuous task - */ + @Override public void startExecuting(){ this.attackStep = 0; } - /** - * Resets the task - */ + @Override public void resetTask(){ // This might be called setOnFire, but what it really controls is whether the wraith is in attack mode. this.blaze.setOnFire(false); } - /** - * Updates the task - */ + @Override public void updateTask(){ --this.attackTime; EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); @@ -154,8 +138,7 @@ public class EntityLightningWraith extends EntityBlazeMinion { if(this.attackStep > 1){ // Proof, if it were at all needed, of the elegance and versatility of the spell system. - Spells.arc.cast(this.blaze.world, this.blaze, EnumHand.MAIN_HAND, 0, entitylivingbase, - new SpellModifiers()); + Spells.arc.cast(this.blaze.world, this.blaze, EnumHand.MAIN_HAND, 0, entitylivingbase, new SpellModifiers()); // TODO: Decide if an event should be fired here. I'm guessing no. } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java b/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java index 3257701b..1c9da3ce 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java @@ -31,35 +31,12 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { private UUID casterUUID; // Setter + getter implementations - @Override - public int getLifetime(){ - return lifetime; - } - - @Override - public void setLifetime(int lifetime){ - this.lifetime = lifetime; - } - - @Override - public WeakReference getCasterReference(){ - return casterReference; - } - - @Override - public void setCasterReference(WeakReference reference){ - casterReference = reference; - } - - @Override - public UUID getCasterUUID(){ - return casterUUID; - } - - @Override - public void setCasterUUID(UUID uuid){ - this.casterUUID = uuid; - } + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID(){ return casterUUID; } + @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } public EntityMagicSlime(World world){ super(world); @@ -88,13 +65,8 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { // EntitySlime overrides - @Override - protected void initEntityAI(){ - } // Has no AI! - - @Override - protected void dealDamage(EntityLivingBase entity){ - } // Handles damage itself + @Override protected void initEntityAI(){} // Has no AI! + @Override protected void dealDamage(EntityLivingBase entity){} // Handles damage itself @Override public void setDead(){ @@ -197,35 +169,12 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { // Recommended overrides - @Override - protected int getExperiencePoints(EntityPlayer player){ - return 0; - } - - @Override - protected boolean canDropLoot(){ - return false; - } - - @Override - protected Item getDropItem(){ - return null; - } - - @Override - protected ResourceLocation getLootTable(){ - return null; - } - - @Override - public boolean canPickUpLoot(){ - return false; - } - - // This vanilla method has nothing to do with the custom onDespawn() method. - @Override - protected boolean canDespawn(){ - return false; - } + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. + @Override protected boolean canDespawn(){ return false; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java index 54325cd5..73170416 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java @@ -27,18 +27,15 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste private double AISpeed = 0.5; // Can attack for 7 seconds, then must cool down for 3. - private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell(this, AISpeed, 15f, 60, 140); + private EntityAIAttackSpell spellAttackAI = new EntityAIAttackSpell<>(this, AISpeed, 15f, 60, 140); private Spell continuousSpell; private static final List attack = Collections.singletonList(Spells.flame_ray); + /** Creates a new phoenix in the given world. */ public EntityPhoenix(World world){ super(world); - } - - public EntityPhoenix(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world, x, y, z, caster, lifetime); this.isImmuneToFire = true; this.height = 2.0f; // For some reason this can't be in initEntityAI @@ -185,8 +182,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste } @Override - public void fall(float distance, float damageMultiplier){ - } // Immune to fall damage + public void fall(float distance, float damageMultiplier){} // Immune to fall damage @Override public boolean isBurning(){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java index 835fab80..b182af36 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java @@ -35,12 +35,9 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell private static final List attack = Collections.singletonList(Spells.darkness_orb); + /** Creates a new shadow wraith in the gievn world. */ public EntityShadowWraith(World world){ super(world); - } - - public EntityShadowWraith(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world, x, y, z, caster, lifetime); // For some reason this can't be in initEntityAI this.tasks.addTask(0, this.spellAttackAI); } @@ -128,13 +125,8 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell if(this.world.isRemote){ for(int i = 0; i < 15; i++){ float brightness = rand.nextFloat() * 0.4f; - ParticleBuilder.create(Type.SPARKLE) - .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + this.height / 2 - 0.5d + rand.nextDouble(), - this.posZ - 0.5d + rand.nextDouble()) - .vel(0, 0.05, 0) - .lifetime(20 + rand.nextInt(10)) - .colour(brightness, 0.0f, brightness) - .spawn(world); + ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) + .colour(brightness, 0.0f, brightness).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java index a1a79b4d..b2a2c8fa 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java @@ -30,59 +30,19 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone private UUID casterUUID; // Setter + getter implementations - @Override - public int getLifetime(){ - return lifetime; - } + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID(){ return casterUUID; } + @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } - @Override - public void setLifetime(int lifetime){ - this.lifetime = lifetime; - } - - @Override - public WeakReference getCasterReference(){ - return casterReference; - } - - @Override - public void setCasterReference(WeakReference reference){ - casterReference = reference; - } - - @Override - public UUID getCasterUUID(){ - return casterUUID; - } - - @Override - public void setCasterUUID(UUID uuid){ - this.casterUUID = uuid; - } - - /** - * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't matter - * because the client side entity immediately gets the lifetime value copied over to it by this class anyway. When - * extending this class, you must override this constructor or Minecraft won't like it, but there's no need to do - * anything inside it other than call super(). - */ + /** Creates a new silverfish minion in the given world. */ public EntitySilverfishMinion(World world){ super(world); this.experienceValue = 0; } - /** - * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when extending - * this class (be sure to call super()) so that AI and other things can be added. - */ - public EntitySilverfishMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world); - this.setPosition(x, y, z); - this.casterReference = new WeakReference(caster); - this.experienceValue = 0; - this.lifetime = lifetime; - } - // EntitySilverfish overrides @Override protected void initEntityAI(){ @@ -144,8 +104,10 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone int alliesToSummon = rand.nextInt(4) + 1; for(int i = 0; i < alliesToSummon; i++){ - EntitySilverfishMinion silverfish = new EntitySilverfishMinion(this.world, victim.posX, victim.posY, - victim.posZ, this.getCaster(), this.lifetime); + EntitySilverfishMinion silverfish = new EntitySilverfishMinion(this.world); + silverfish.setPosition(victim.posX, victim.posY, victim.posZ); + silverfish.setCaster(this.getCaster()); + silverfish.setLifetime(this.getLifetime()); this.world.spawnEntity(silverfish); } } @@ -177,36 +139,13 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone // Recommended overrides - @Override - protected int getExperiencePoints(EntityPlayer player){ - return 0; - } - - @Override - protected boolean canDropLoot(){ - return false; - } - - @Override - protected Item getDropItem(){ - return null; - } - - @Override - protected ResourceLocation getLootTable(){ - return null; - } - - @Override - public boolean canPickUpLoot(){ - return false; - } - + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } // This vanilla method has nothing to do with the custom despawn() method. - @Override - protected boolean canDespawn(){ - return false; - } + @Override protected boolean canDespawn(){ return false; } @Override public boolean canAttackClass(Class entityType){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java index 167d34f1..c1801d76 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java @@ -7,6 +7,7 @@ import java.util.UUID; import javax.annotation.Nullable; import electroblob.wizardry.Wizardry; +import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; import net.minecraft.entity.SharedMonsterAttributes; @@ -19,6 +20,7 @@ import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.Item; +import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumHand; @@ -37,59 +39,19 @@ public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCre private UUID casterUUID; // Setter + getter implementations - @Override - public int getLifetime(){ - return lifetime; - } + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID(){ return casterUUID; } + @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } - @Override - public void setLifetime(int lifetime){ - this.lifetime = lifetime; - } - - @Override - public WeakReference getCasterReference(){ - return casterReference; - } - - @Override - public void setCasterReference(WeakReference reference){ - casterReference = reference; - } - - @Override - public UUID getCasterUUID(){ - return casterUUID; - } - - @Override - public void setCasterUUID(UUID uuid){ - this.casterUUID = uuid; - } - - /** - * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't matter - * because the client side entity immediately gets the lifetime value copied over to it by this class anyway. When - * extending this class, you must override this constructor or Minecraft won't like it, but there's no need to do - * anything inside it other than call super(). - */ + /** Creates a new skeleton minion in the given world. */ public EntitySkeletonMinion(World world){ super(world); this.experienceValue = 0; } - /** - * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when extending - * this class (be sure to call super()) so that AI and other things can be added. - */ - public EntitySkeletonMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world); - this.setPosition(x, y, z); - this.casterReference = new WeakReference(caster); - this.experienceValue = 0; - this.lifetime = lifetime; - } - // EntitySkeleton overrides // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its @@ -120,7 +82,7 @@ public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCre this.setLeftHanded(true); }else{ this.setLeftHanded(false); - } + } // Halloween pumpkin heads! Why not? if(this.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty()){ @@ -194,40 +156,18 @@ public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCre // Recommended overrides - @Override - protected int getExperiencePoints(EntityPlayer player){ - return 0; - } - - @Override - protected boolean canDropLoot(){ - return false; - } - - @Override - protected Item getDropItem(){ - return null; - } - - @Override - protected ResourceLocation getLootTable(){ - return null; - } - - @Override - public boolean canPickUpLoot(){ - return false; - } - + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } // This vanilla method has nothing to do with the custom despawn() method. - @Override - protected boolean canDespawn(){ - return false; - } + @Override protected boolean canDespawn(){ return false; } @Override public boolean canAttackClass(Class entityType){ - return true; + // Returns true unless the given entity type is a flying entity and this skeleton does not have a bow. + return !EntityFlying.class.isAssignableFrom(entityType) || this.getHeldItemMainhand().getItem() instanceof ItemBow; } @Override diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java index 4a979455..23b7824b 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java @@ -35,59 +35,19 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre private UUID casterUUID; // Setter + getter implementations - @Override - public int getLifetime(){ - return lifetime; - } + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID(){ return casterUUID; } + @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } - @Override - public void setLifetime(int lifetime){ - this.lifetime = lifetime; - } - - @Override - public WeakReference getCasterReference(){ - return casterReference; - } - - @Override - public void setCasterReference(WeakReference reference){ - casterReference = reference; - } - - @Override - public UUID getCasterUUID(){ - return casterUUID; - } - - @Override - public void setCasterUUID(UUID uuid){ - this.casterUUID = uuid; - } - - /** - * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't matter - * because the client side entity immediately gets the lifetime value copied over to it by this class anyway. When - * extending this class, you must override this constructor or Minecraft won't like it, but there's no need to do - * anything inside it other than call super(). - */ + /** Creates a new spider minion in the given world. */ public EntitySpiderMinion(World world){ super(world); this.experienceValue = 0; } - /** - * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when extending - * this class (be sure to call super()) so that AI and other things can be added. - */ - public EntitySpiderMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world); - this.setPosition(x, y, z); - this.casterReference = new WeakReference(caster); - this.experienceValue = 0; - this.lifetime = lifetime; - } - // EntitySpider overrides // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its @@ -198,36 +158,13 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre // Recommended overrides - @Override - protected int getExperiencePoints(EntityPlayer player){ - return 0; - } - - @Override - protected boolean canDropLoot(){ - return false; - } - - @Override - protected Item getDropItem(){ - return null; - } - - @Override - protected ResourceLocation getLootTable(){ - return null; - } - - @Override - public boolean canPickUpLoot(){ - return false; - } - + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } // This vanilla method has nothing to do with the custom despawn() method. - @Override - protected boolean canDespawn(){ - return false; - } + @Override protected boolean canDespawn(){ return false; } @Override public boolean canAttackClass(Class entityType){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java index f86586c5..602a6941 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java @@ -33,13 +33,11 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe private static final List attack = Collections.singletonList(Spells.lightning_disc); + /** Creates a new storm elemental in the given world. */ public EntityStormElemental(World world){ super(world); - } - - public EntityStormElemental(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world, x, y, z, caster, lifetime); // For some reason this can't be in initEntityAI + // TESTME: May need to be inside a !world.isRemote check. this.tasks.addTask(0, this.spellAttackAI); } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java index 64d2e46b..2ef50929 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java @@ -64,29 +64,12 @@ public abstract class EntitySummonedCreature extends EntityCreature implements I this.casterUUID = uuid; } - /** - * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't matter - * because the client side entity immediately gets the lifetime value copied over to it by this class anyway. When - * extending this class, you must override this constructor or Minecraft won't like it, but there's no need to do - * anything inside it other than call super(). - */ + /** Creates a new summoned creature in the given world. */ public EntitySummonedCreature(World world){ super(world); this.experienceValue = 0; } - /** - * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when extending - * this class (be sure to call super()) so that AI and other things can be added. - */ - public EntitySummonedCreature(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world); - this.setPosition(x, y, z); - this.casterReference = new WeakReference(caster); - this.experienceValue = 0; - this.lifetime = lifetime; - } - // Implementations @Override @@ -134,36 +117,13 @@ public abstract class EntitySummonedCreature extends EntityCreature implements I // Recommended overrides - @Override - protected int getExperiencePoints(EntityPlayer player){ - return 0; - } - - @Override - protected boolean canDropLoot(){ - return false; - } - - @Override - protected Item getDropItem(){ - return null; - } - - @Override - protected ResourceLocation getLootTable(){ - return null; - } - - @Override - public boolean canPickUpLoot(){ - return false; - } - - // This vanilla method has nothing to do with the custom onDespawn() method. - @Override - protected boolean canDespawn(){ - return false; - } + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. + @Override protected boolean canDespawn(){ return false; } @Override public boolean canAttackClass(Class entityType){ @@ -171,7 +131,6 @@ public abstract class EntitySummonedCreature extends EntityCreature implements I return !EntityFlying.class.isAssignableFrom(entityType) || this.hasRangedAttack(); } - // TODO: Backport the following two methods to 1.7.10. @Override public ITextComponent getDisplayName(){ if(getCaster() != null){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWitherSkeletonMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityWitherSkeletonMinion.java index dee3d51e..8606978b 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWitherSkeletonMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWitherSkeletonMinion.java @@ -7,6 +7,7 @@ import java.util.UUID; import javax.annotation.Nullable; import electroblob.wizardry.Wizardry; +import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; import net.minecraft.entity.SharedMonsterAttributes; @@ -20,6 +21,7 @@ import net.minecraft.init.Items; import net.minecraft.init.MobEffects; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.Item; +import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; @@ -39,59 +41,19 @@ public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements private UUID casterUUID; // Setter + getter implementations - @Override - public int getLifetime(){ - return lifetime; - } + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public WeakReference getCasterReference(){ return casterReference; } + @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } + @Override public UUID getCasterUUID(){ return casterUUID; } + @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } - @Override - public void setLifetime(int lifetime){ - this.lifetime = lifetime; - } - - @Override - public WeakReference getCasterReference(){ - return casterReference; - } - - @Override - public void setCasterReference(WeakReference reference){ - casterReference = reference; - } - - @Override - public UUID getCasterUUID(){ - return casterUUID; - } - - @Override - public void setCasterUUID(UUID uuid){ - this.casterUUID = uuid; - } - - /** - * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't matter - * because the client side entity immediately gets the lifetime value copied over to it by this class anyway. When - * extending this class, you must override this constructor or Minecraft won't like it, but there's no need to do - * anything inside it other than call super(). - */ + /** Creates a new wither skeleton minion in the given world. */ public EntityWitherSkeletonMinion(World world){ super(world); this.experienceValue = 0; } - /** - * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when extending - * this class (be sure to call super()) so that AI and other things can be added. - */ - public EntityWitherSkeletonMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world); - this.setPosition(x, y, z); - this.casterReference = new WeakReference(caster); - this.experienceValue = 0; - this.lifetime = lifetime; - } - // EntitySkeleton overrides // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its @@ -105,13 +67,13 @@ public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements 0, false, true, this.getTargetSelector())); } - // Shouldn't have randomised armour, but does still need a bow! + // Shouldn't have randomised armour, but does still need a sword! @Override protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty){ - this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); + this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.STONE_SWORD)); + this.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); } - // Where the skeleton minion is summoned does not affect its type. @Override public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata){ // Can't call super, so the code from the next level up (EntityLiving) had to be copied as well. @@ -123,6 +85,9 @@ public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements }else{ this.setLeftHanded(false); } + + this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.STONE_SWORD)); + this.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); // Halloween pumpkin heads! Why not? if(this.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty()){ @@ -201,40 +166,18 @@ public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements // Recommended overrides - @Override - protected int getExperiencePoints(EntityPlayer player){ - return 0; - } - - @Override - protected boolean canDropLoot(){ - return false; - } - - @Override - protected Item getDropItem(){ - return null; - } - - @Override - protected ResourceLocation getLootTable(){ - return null; - } - - @Override - public boolean canPickUpLoot(){ - return false; - } - + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } // This vanilla method has nothing to do with the custom despawn() method. - @Override - protected boolean canDespawn(){ - return false; - } + @Override protected boolean canDespawn(){ return false; } @Override public boolean canAttackClass(Class entityType){ - return true; + // Returns true unless the given entity type is a flying entity and this skeleton does not have a bow. + return !EntityFlying.class.isAssignableFrom(entityType) || this.getHeldItemMainhand().getItem() instanceof ItemBow; } @Override diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index ccdec06d..339e6f41 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -23,10 +23,10 @@ import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WandHelper; import electroblob.wizardry.util.WildcardTradeList; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; @@ -70,6 +70,7 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.village.MerchantRecipe; import net.minecraft.village.MerchantRecipeList; import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.FakePlayer; @@ -216,6 +217,17 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp public Spell getContinuousSpell(){ return this.continuousSpell; } + + @Override + public int getAimingError(EnumDifficulty difficulty){ + // Being more intelligent than skeletons, wizards are a little more accurate. + switch(difficulty){ + case EASY: return 7; + case NORMAL: return 4; + case HARD: return 1; + default: return 7; // Peaceful counts as easy + } + } @Override public void setCustomer(EntityPlayer player){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java index 7a7b10d8..3613d614 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java @@ -36,29 +36,12 @@ public class EntityZombieMinion extends EntityZombie implements ISummonedCreatur @Override public UUID getCasterUUID(){ return casterUUID; } @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } - /** - * Default shell constructor, only used by client. Lifetime defaults arbitrarily to 600, but this doesn't matter - * because the client side entity immediately gets the lifetime value copied over to it by this class anyway. When - * extending this class, you must override this constructor or Minecraft won't like it, but there's no need to do - * anything inside it other than call super(). - */ + /** Creates a new zombie minion in the given world. */ public EntityZombieMinion(World world){ super(world); this.experienceValue = 0; } - /** - * Set lifetime to -1 to allow this creature to last forever. This constructor should be overridden when extending - * this class (be sure to call super()) so that AI and other things can be added. - */ - public EntityZombieMinion(World world, double x, double y, double z, EntityLivingBase caster, int lifetime){ - super(world); - this.setPosition(x, y, z); - this.casterReference = new WeakReference(caster); - this.experienceValue = 0; - this.lifetime = lifetime; - } - // EntityZombie overrides (EntityZombie is a long class so there are lots of these) @Override diff --git a/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java b/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java index a43c0153..86eda769 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java @@ -7,6 +7,8 @@ import javax.annotation.Nonnull; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.world.EnumDifficulty; /** * Interface for entities that can cast spells. Mainly intended for use by wizard-type entities, but can be implemented @@ -65,4 +67,13 @@ public interface ISpellCaster { * to NBT is up to you. If the implementing class does not deal with continuous spells, leave this method blank. */ public void setContinuousSpell(Spell spell); + + /** + * Returns the aiming arror for the given difficulty, used in projectile spells. Defaults to the values used by + * skeletons, which are: Easy - 10, Normal - 6, Hard - 2, Peaceful - 10 (rarely used). + */ + // This is what default methods are actually intended for! + public default int getAimingError(EnumDifficulty difficulty) { + return WizardryUtilities.getDefaultAimingError(difficulty); + } } diff --git a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java index 4219b6bf..1b6a0069 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java @@ -130,6 +130,14 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { default EntityLivingBase getCaster(){ return getCasterReference() == null ? null : getCasterReference().get(); } + + /** + * Sets the EntityLivingBase that summoned this creature. This is the correct method to use to set the owner of + * this summoned creature. + */ + default void setCaster(@Nullable EntityLivingBase caster){ + setCasterReference(new WeakReference(caster)); + } // Miscellaneous diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityBomb.java index 11cb8562..6f4af21a 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityBomb.java @@ -1,7 +1,6 @@ package electroblob.wizardry.entity.projectile; import io.netty.buffer.ByteBuf; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; @@ -21,29 +20,16 @@ public abstract class EntityBomb extends EntityMagicProjectile { super(world); } - public EntityBomb(World world, EntityLivingBase thrower){ - super(world, thrower); - } - - public EntityBomb(World world, EntityLivingBase thrower, float damageMultiplier, float blastMultiplier){ - super(world, thrower, damageMultiplier); - this.blastMultiplier = blastMultiplier; - } - - public EntityBomb(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); - } - @Override public void writeSpawnData(ByteBuf buffer){ - super.writeSpawnData(buffer); buffer.writeFloat(blastMultiplier); + super.writeSpawnData(buffer); } @Override public void readSpawnData(ByteBuf buffer){ - super.readSpawnData(buffer); blastMultiplier = buffer.readFloat(); + super.readSpawnData(buffer); } @Override diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java index 6fb6f290..43e81c5e 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java @@ -14,30 +14,14 @@ import net.minecraft.world.World; public class EntityDarknessOrb extends EntityMagicProjectile { - public EntityDarknessOrb(World par1World){ - super(par1World); - } - - public EntityDarknessOrb(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntityDarknessOrb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier); - } - - public EntityDarknessOrb(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); + public EntityDarknessOrb(World world){ + super(world); } @Override - protected float getSpeed(){ - return 0.5F; - } - - @Override - protected void onImpact(RayTraceResult RayTraceResult){ - Entity target = RayTraceResult.entityHit; + protected void onImpact(RayTraceResult rayTrace){ + + Entity target = rayTrace.entityHit; if(target != null && !MagicDamage.isEntityImmune(DamageType.WITHER, target)){ float damage = 8 * damageMultiplier; @@ -79,10 +63,8 @@ public class EntityDarknessOrb extends EntityMagicProjectile { this.motionZ /= 0.99; } - /** - * Gets the amount of gravity to apply to the thrown entity with each tick. - */ - protected float getGravityVelocity(){ - return 0.0F; + @Override + public boolean hasNoGravity(){ + return true; } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java index 7208a8f0..02eafdb6 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java @@ -1,9 +1,7 @@ package electroblob.wizardry.entity.projectile; -import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; import net.minecraft.init.SoundEvents; @@ -11,36 +9,17 @@ import net.minecraft.potion.PotionEffect; import net.minecraft.world.World; public class EntityDart extends EntityMagicArrow { - /** Basic shell constructor. Should only be used by the client. */ + + /** Creates a new dart in the given world. */ public EntityDart(World world){ super(world); } - /** - * Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this constructor - * and then call setVelocity() as that method is, bizarrely, client-side only. - */ - public EntityDart(World world, double x, double y, double z){ - super(world, x, y, z); - } + @Override public double getDamage(){ return 4.0d; } - /** - * Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be - * altered slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on - * easy, 6 on normal and 2 on hard difficulty. - */ - public EntityDart(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, - float damageMultiplier){ - super(world, caster, target, speed, aimingError, damageMultiplier); - } + @Override public boolean doGravity(){ return true; } - /** - * Creates a projectile pointing in the direction the caster is looking, with the given speed. USE THIS CONSTRUCTOR - * FOR NORMAL SPELLS. - */ - public EntityDart(World world, EntityLivingBase caster, float speed, float damageMultiplier){ - super(world, caster, speed, damageMultiplier); - } + @Override public boolean doDeceleration(){ return true; } @Override public void onEntityHit(EntityLivingBase entityHit){ @@ -70,28 +49,6 @@ public class EntityDart extends EntityMagicArrow { } @Override - public double getDamage(){ - return 4.0d; - } - - @Override - public DamageType getDamageType(){ - return DamageType.MAGIC; - } - - @Override - public boolean doGravity(){ - return true; - } - - @Override - public boolean doDeceleration(){ - return true; - } - - @Override - protected void entityInit(){ - - } + protected void entityInit(){} } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java index 268a15c2..d0bfcf28 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java @@ -3,27 +3,15 @@ package electroblob.wizardry.entity.projectile; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; public class EntityFirebolt extends EntityMagicProjectile { - public EntityFirebolt(World par1World){ - super(par1World); - } - - public EntityFirebolt(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntityFirebolt(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier); - } - - public EntityFirebolt(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); + + public EntityFirebolt(World world){ + super(world); } @Override @@ -72,17 +60,11 @@ public class EntityFirebolt extends EntityMagicProjectile { } } - /** - * Gets the amount of gravity to apply to the thrown entity with each tick. - */ @Override - protected float getGravityVelocity(){ - return 0.0F; + public boolean hasNoGravity(){ + return true; } - /** - * Return whether this entity should be rendered as on fire. - */ @Override public boolean canRenderOnFire(){ return false; diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java index b181ab2b..d6e207c5 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java @@ -16,27 +16,14 @@ import net.minecraft.world.World; public class EntityFirebomb extends EntityBomb { - public EntityFirebomb(World par1World){ - super(par1World); - } - - public EntityFirebomb(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntityFirebomb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, - float blastMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); - } - - public EntityFirebomb(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); + public EntityFirebomb(World world){ + super(world); } @Override - protected void onImpact(RayTraceResult par1RayTraceResult){ + protected void onImpact(RayTraceResult rayTrace){ - Entity entityHit = par1RayTraceResult.entityHit; + Entity entityHit = rayTrace.entityHit; if(entityHit != null){ // This is if the firebomb gets a direct hit diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java index c1b6f1be..89738294 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java @@ -1,44 +1,17 @@ package electroblob.wizardry.entity.projectile; import electroblob.wizardry.util.MagicDamage.DamageType; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; import net.minecraft.world.World; public class EntityForceArrow extends EntityMagicArrow { - /** Basic shell constructor. Should only be used by the client. */ + /** Creates a new force arrow in the given world. */ public EntityForceArrow(World world){ super(world); } - /** - * Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this constructor - * and then call setVelocity() as that method is, bizarrely, client-side only. - */ - public EntityForceArrow(World world, double x, double y, double z){ - super(world, x, y, z); - } - - /** - * Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be - * altered slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on - * easy, 6 on normal and 2 on hard difficulty. - */ - public EntityForceArrow(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, - float damageMultiplier){ - super(world, caster, target, speed, aimingError, damageMultiplier); - } - - /** - * Creates a projectile pointing in the direction the caster is looking, with the given speed. USE THIS CONSTRUCTOR - * FOR NORMAL SPELLS. - */ - public EntityForceArrow(World world, EntityLivingBase caster, float speed, float damageMultiplier){ - super(world, caster, speed, damageMultiplier); - } - @Override public void onEntityHit(EntityLivingBase entityHit){ this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java index d7edcb12..5c554aa2 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java @@ -9,40 +9,17 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class EntityForceOrb extends EntityMagicProjectile { - - /** - * The entity blast multiplier. In this particular case, it doesn't need syncing, so this class doesn't extend - * EntityBlastProjectile. - */ - public float blastMultiplier; - - public EntityForceOrb(World par1World){ - super(par1World); +public class EntityForceOrb extends EntityBomb { + + public EntityForceOrb(World world){ + super(world); } - public EntityForceOrb(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntityForceOrb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, - float blastMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier); - this.blastMultiplier = blastMultiplier; - } - - public EntityForceOrb(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); - } - - /** - * Called when this EntityThrowable hits a block or entity. - */ + @Override protected void onImpact(RayTraceResult par1RayTraceResult){ if(par1RayTraceResult.entityHit != null){ @@ -96,16 +73,5 @@ public class EntityForceOrb extends EntityMagicProjectile { this.setDead(); } } - - @Override - public void readEntityFromNBT(NBTTagCompound nbttagcompound){ - super.readEntityFromNBT(nbttagcompound); - blastMultiplier = nbttagcompound.getFloat("blastMultiplier"); - } - - @Override - public void writeEntityToNBT(NBTTagCompound nbttagcompound){ - super.writeEntityToNBT(nbttagcompound); - nbttagcompound.setFloat("blastMultiplier", blastMultiplier); - } + } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java index a6768266..25282d28 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java @@ -21,26 +21,11 @@ import net.minecraft.world.World; public class EntityIceCharge extends EntityBomb { - public EntityIceCharge(World par1World){ - super(par1World); + public EntityIceCharge(World world){ + super(world); } - public EntityIceCharge(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntityIceCharge(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, - float blastMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); - } - - public EntityIceCharge(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); - } - - /** - * Called when this EntityThrowable hits a block or entity. - */ + @Override protected void onImpact(RayTraceResult par1RayTraceResult){ Entity entityHit = par1RayTraceResult.entityHit; @@ -62,7 +47,7 @@ public class EntityIceCharge extends EntityBomb { for(int i = 0; i < 30 * blastMultiplier; i++){ ParticleBuilder.create(Type.ICE, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) - .lifetime(35).spawn(world); + .lifetime(35).gravity(true).spawn(world); float brightness = 0.4f + rand.nextFloat() * 0.5f; ParticleBuilder.create(Type.DARK_MAGIC, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) @@ -118,11 +103,12 @@ public class EntityIceCharge extends EntityBomb { double dx = rand.nextDouble() - 0.5; double dy = rand.nextDouble() - 0.5; double dz = rand.nextDouble() - 0.5; - EntityIceShard iceshard = new EntityIceShard(world, this.posX + dx, this.posY + dy, this.posZ + dz); + EntityIceShard iceshard = new EntityIceShard(world); + iceshard.setPosition(this.posX + dx, this.posY + dy, this.posZ + dz); iceshard.motionX = dx; iceshard.motionY = dy; iceshard.motionZ = dz; - iceshard.setShootingEntity(this.getThrower()); + iceshard.setCaster(this.getThrower()); iceshard.damageMultiplier = this.damageMultiplier; world.spawnEntity(iceshard); } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java index f8cb6ee3..2a6094c0 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java @@ -5,7 +5,6 @@ import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; @@ -13,40 +12,23 @@ import net.minecraft.world.World; public class EntityIceLance extends EntityMagicArrow { - /** Basic shell constructor. Should only be used by the client. */ + /** Creates a new ice lance in the given world. */ public EntityIceLance(World world){ super(world); this.setKnockbackStrength(1); } - /** - * Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this constructor - * and then call setVelocity() as that method is, bizarrely, client-side only. - */ - public EntityIceLance(World world, double x, double y, double z){ - super(world, x, y, z); - this.setKnockbackStrength(1); - } + @Override public double getDamage(){ return 10.0d; } - /** - * Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be - * altered slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on - * easy, 6 on normal and 2 on hard difficulty. - */ - public EntityIceLance(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, - float damageMultiplier){ - super(world, caster, target, speed, aimingError, damageMultiplier); - this.setKnockbackStrength(1); - } + @Override public DamageType getDamageType(){ return DamageType.FROST; } - /** - * Creates a projectile pointing in the direction the caster is looking, with the given speed. USE THIS CONSTRUCTOR - * FOR NORMAL SPELLS. - */ - public EntityIceLance(World world, EntityLivingBase caster, float speed, float damageMultiplier){ - super(world, caster, speed, damageMultiplier); - this.setKnockbackStrength(1); - } + @Override public boolean doGravity(){ return true; } + + @Override public boolean doDeceleration(){ return true; } + + @Override public boolean doOverpenetration(){ return true; } + + @Override public boolean canRenderOnFire(){ return false; } @Override public void onEntityHit(EntityLivingBase entityHit){ @@ -58,11 +40,6 @@ public class EntityIceLance extends EntityMagicArrow { this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); } - @Override - public void tickInAir(){ - - } - @Override public void onBlockHit(){ // Adds a particle effect when the ice lance hits a block. @@ -78,43 +55,6 @@ public class EntityIceLance extends EntityMagicArrow { } @Override - public void tickInGround(){ - this.setDead(); - } - - @Override - public double getDamage(){ - return 10.0d; - } - - @Override - public DamageType getDamageType(){ - return DamageType.FROST; - } - - @Override - public boolean doGravity(){ - return true; - } - - @Override - public boolean doDeceleration(){ - return true; - } - - @Override - public boolean doOverpenetration(){ - return true; - } - - @Override - protected void entityInit(){ - - } - - @Override - public boolean canRenderOnFire(){ - return false; - } + protected void entityInit(){} } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java index 19e72bb6..483d1c55 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java @@ -5,7 +5,6 @@ import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; @@ -13,36 +12,20 @@ import net.minecraft.world.World; public class EntityIceShard extends EntityMagicArrow { - /** Basic shell constructor. Should only be used by the client. */ + /** Creates a new ice shard in the given world. */ public EntityIceShard(World world){ super(world); } - /** - * Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this constructor - * and then call setVelocity() as that method is, bizarrely, client-side only. - */ - public EntityIceShard(World world, double x, double y, double z){ - super(world, x, y, z); - } + @Override public double getDamage(){ return 6.0d; } - /** - * Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be - * altered slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on - * easy, 6 on normal and 2 on hard difficulty. - */ - public EntityIceShard(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, - float damageMultiplier){ - super(world, caster, target, speed, aimingError, damageMultiplier); - } + @Override public DamageType getDamageType(){ return DamageType.FROST; } - /** - * Creates a projectile pointing in the direction the caster is looking, with the given speed. USE THIS CONSTRUCTOR - * FOR NORMAL SPELLS. - */ - public EntityIceShard(World world, EntityLivingBase caster, float speed, float damageMultiplier){ - super(world, caster, speed, damageMultiplier); - } + @Override public boolean doGravity(){ return true; } + + @Override public boolean doDeceleration(){ return true; } + + @Override public boolean canRenderOnFire(){ return false; } @Override public void onEntityHit(EntityLivingBase entityHit){ @@ -54,18 +37,13 @@ public class EntityIceShard extends EntityMagicArrow { this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); } - @Override - public void tickInAir(){ - - } - @Override public void onBlockHit(){ // Adds a particle effect when the ice shard hits a block. if(this.world.isRemote){ for(int j = 0; j < 10; j++){ ParticleBuilder.create(Type.ICE, this.rand, this.posX, this.posY, this.posZ, 0.5, true) - .lifetime(20 + rand.nextInt(10)).spawn(world); + .lifetime(20 + rand.nextInt(10)).gravity(true).spawn(world); } } // Parameters for sound: sound event name, volume, pitch. @@ -74,33 +52,6 @@ public class EntityIceShard extends EntityMagicArrow { } @Override - public double getDamage(){ - return 6.0d; - } - - @Override - public DamageType getDamageType(){ - return DamageType.FROST; - } - - @Override - public boolean doGravity(){ - return true; - } - - @Override - public boolean doDeceleration(){ - return true; - } - - @Override - protected void entityInit(){ - - } - - @Override - public boolean canRenderOnFire(){ - return false; - } + protected void entityInit(){} } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java index 4da5d2d0..8e5d38dc 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java @@ -4,42 +4,23 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; public class EntityLightningArrow extends EntityMagicArrow { - /** Basic shell constructor. Should only be used by the client. */ + /** Creates a new lightning arrow in the given world. */ public EntityLightningArrow(World world){ super(world); } - /** - * Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this constructor - * and then call setVelocity() as that method is, bizarrely, client-side only. - */ - public EntityLightningArrow(World world, double x, double y, double z){ - super(world, x, y, z); - } + @Override public double getDamage(){ return 7.0d; } - /** - * Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be - * altered slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on - * easy, 6 on normal and 2 on hard difficulty. - */ - public EntityLightningArrow(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, - float damageMultiplier){ - super(world, caster, target, speed, aimingError, damageMultiplier); - } + @Override public DamageType getDamageType(){ return DamageType.SHOCK; } - /** - * Creates a projectile pointing in the direction the caster is looking, with the given speed. USE THIS CONSTRUCTOR - * FOR NORMAL SPELLS. - */ - public EntityLightningArrow(World world, EntityLivingBase caster, float speed, float damageMultiplier){ - super(world, caster, speed, damageMultiplier); - } + @Override public boolean doGravity(){ return false; } + + @Override public boolean doDeceleration(){ return false; } @Override public void onEntityHit(EntityLivingBase entityHit){ @@ -67,28 +48,6 @@ public class EntityLightningArrow extends EntityMagicArrow { } @Override - public double getDamage(){ - return 7.0d; - } - - @Override - public DamageType getDamageType(){ - return DamageType.SHOCK; - } - - @Override - public boolean doGravity(){ - return false; - } - - @Override - public boolean doDeceleration(){ - return false; - } - - @Override - protected void entityInit(){ - - } + protected void entityInit(){} } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java index 988fd2ba..afa24ff8 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java @@ -15,29 +15,12 @@ import net.minecraft.world.World; public class EntityLightningDisc extends EntityMagicProjectile { - public EntityLightningDisc(World par1World){ - super(par1World); - } - - public EntityLightningDisc(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntityLightningDisc(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier); - } - - public EntityLightningDisc(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); + public EntityLightningDisc(World world){ + super(world); this.width = 2.0f; this.height = 0.5f; } - @Override - protected float getSpeed(){ - return 1.2f; - } - @Override protected void onImpact(RayTraceResult result){ @@ -65,7 +48,7 @@ public class EntityLightningDisc extends EntityMagicProjectile { for(int i = 0; i < 8; i++){ // TODO: Why are the x and z parameters different? ParticleBuilder.create(Type.SPARK).pos(this.posX + rand.nextFloat() * 2 - 1, - this.posY, this.posZ + rand.nextFloat() - 0.5).spawn(world); + this.posY, this.posZ + rand.nextFloat() * 2 - 1).spawn(world); } } @@ -105,8 +88,8 @@ public class EntityLightningDisc extends EntityMagicProjectile { } @Override - protected float getGravityVelocity(){ - return 0.0F; + public boolean hasNoGravity(){ + return true; } @Override diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java index cbcc6208..64091a91 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java @@ -59,7 +59,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE /** Seems to be some sort of timer for animating an arrow. */ public int arrowShake; /** The owner of this arrow. */ - private WeakReference shootingEntity; + private WeakReference caster; /** * The UUID of the caster. Note that this is only for loading purposes; during normal updates the actual entity * instance is stored (so that getEntityByUUID is not called constantly), so this will not always be synced (this is @@ -70,87 +70,74 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE int ticksInAir; /** The amount of knockback an arrow applies when it hits a mob. */ private int knockbackStrength; - /** - * The damage multiplier for the arrow. Normally this isn't set directly, since it can be done via the constructor. - * An exception is where other entities need to pass in their multipliers, e.g. ice charge. - */ + /** The damage multiplier for the projectile. */ public float damageMultiplier = 1.0f; - /** Basic shell constructor. Should only be used by the client. */ + /** Creates a new projectile in the given world. */ public EntityMagicArrow(World world){ super(world); this.setSize(0.5F, 0.5F); } - - /** - * Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this constructor - * and then call setVelocity() as that method is, bizarrely, client-side only. - */ - public EntityMagicArrow(World world, double x, double y, double z){ - super(world); - this.setSize(0.5F, 0.5F); - this.setPosition(x, y, z); - // yOffset was set to 0 here, but that has been replaced by getYOffset(), which returns 0 in Entity anyway. - } - - /** - * Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be - * altered slightly by a random amount determined by the aimingError parameter. For reference, skeletons set this to - * 10 on easy, 6 on normal and 2 on hard difficulty. - */ - public EntityMagicArrow(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, - float damageMultiplier){ - super(world); - this.shootingEntity = new WeakReference(caster); - this.damageMultiplier = damageMultiplier; - - this.posY = caster.posY + (double)caster.getEyeHeight() - 0.10000000149011612D; - double d0 = target.posX - caster.posX; - double d1 = this.doGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0F) - this.posY - : target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - this.posY; - double d2 = target.posZ - caster.posZ; - double d3 = (double)MathHelper.sqrt(d0 * d0 + d2 * d2); - - if(d3 >= 1.0E-7D){ - float f2 = (float)(Math.atan2(d2, d0) * 180.0D / Math.PI) - 90.0F; - float f3 = (float)(-(Math.atan2(d1, d3) * 180.0D / Math.PI)); - double d4 = d0 / d3; - double d5 = d2 / d3; - this.setLocationAndAngles(caster.posX + d4, this.posY, caster.posZ + d5, f2, f3); - // yOffset was set to 0 here, but that has been replaced by getYOffset(), which returns 0 in Entity anyway. - - // f4 depends on the horizontal distance between the two entities and accounts for bullet drop, - // but of course if gravity is ignored this should be 0. - float bulletDropCompensation = this.doGravity() ? (float)d3 * 0.2F : 0; - this.shoot(d0, d1 + (double)bulletDropCompensation, d2, speed, aimingError); - } - } - - /** - * Creates a projectile pointing in the direction the caster is looking, with the given speed. Use this - * constructor for normal, player-cast spells. - */ - public EntityMagicArrow(World world, EntityLivingBase caster, float speed, float damageMultiplier){ - super(world); - this.shootingEntity = new WeakReference(caster); - this.damageMultiplier = damageMultiplier; - - this.setSize(0.5F, 0.5F); + + // Initialiser methods + + /** Sets the shooter of the projectile to the given caster, positions the projctile at the given caster's eyes and + * aims it in the direction they are looking with the given speed. */ + public void aim(EntityLivingBase caster, float speed){ + + this.setCaster(caster); + this.setLocationAndAngles(caster.posX, caster.posY + (double)caster.getEyeHeight(), caster.posZ, caster.rotationYaw, caster.rotationPitch); + this.posX -= (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F); this.posY -= 0.10000000149011612D; this.posZ -= (double)(MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F); + this.setPosition(this.posX, this.posY, this.posZ); + // yOffset was set to 0 here, but that has been replaced by getYOffset(), which returns 0 in Entity anyway. this.motionX = (double)(-MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI)); + this.motionY = (double)(-MathHelper.sin(this.rotationPitch / 180.0F * (float)Math.PI)); this.motionZ = (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI)); - this.motionY = (double)(-MathHelper.sin(this.rotationPitch / 180.0F * (float)Math.PI)); + this.shoot(this.motionX, this.motionY, this.motionZ, speed * 1.5F, 1.0F); } + /** Sets the shooter of the projectile to the given caster, positions the projctile at the given caster's eyes and + * aims it at the given target with the given speed. The trajectory will be altered slightly by a random amount + * determined by the aimingError parameter. For reference, skeletons set this to 10 on easy, 6 on normal and 2 on hard + * difficulty. */ + public void aim(EntityLivingBase caster, Entity target, float speed, float aimingError){ + + this.setCaster(caster); + + this.posY = caster.posY + (double)caster.getEyeHeight() - 0.1d; + double dx = target.posX - caster.posX; + double dy = this.doGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0f) - this.posY + : target.getEntityBoundingBox().minY + (double)(target.height / 2.0f) - this.posY; + double dz = target.posZ - caster.posZ; + double horizontalDistance = (double)MathHelper.sqrt(dx * dx + dz * dz); + + if(horizontalDistance >= 1.0E-7D){ + float yaw = (float)(Math.atan2(dz, dx) * 180.0d / Math.PI) - 90.0f; + float pitch = (float)(-(Math.atan2(dy, horizontalDistance) * 180.0d / Math.PI)); + double dxNormalised = dx / horizontalDistance; + double dzNormalised = dz / horizontalDistance; + this.setLocationAndAngles(caster.posX + dxNormalised, this.posY, caster.posZ + dzNormalised, yaw, pitch); + // yOffset was set to 0 here, but that has been replaced by getYOffset(), which returns 0 in Entity anyway. + + // Depends on the horizontal distance between the two entities and accounts for bullet drop, + // but of course if gravity is ignored this should be 0 since there is no bullet drop. + float bulletDropCompensation = this.doGravity() ? (float)horizontalDistance * 0.2f : 0; + this.shoot(dx, dy + (double)bulletDropCompensation, dz, speed, aimingError); + } + } + + // Property getters (to be overridden by subclasses) + /** Subclasses must override this to set their own base damage. */ public abstract double getDamage(); @@ -180,86 +167,52 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE return false; } + // Setters and getters + + /** Sets the amount of knockback the projectile applies when it hits a mob. */ + public void setKnockbackStrength(int knockback){ + this.knockbackStrength = knockback; + } + /** - * Similar to setArrowHeading, it's point the throwable entity to a x, y, z direction. + * Returns the EntityLivingBase that created this construct, or null if it no longer exists. Cases where the entity + * may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported to + * another dimension, or this construct simply had no caster in the first place. */ - @Override - public void shoot(double x, double y, double z, float speed, float randomness){ - float f2 = MathHelper.sqrt(x * x + y * y + z * z); - x /= (double)f2; - y /= (double)f2; - z /= (double)f2; - x += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D - * (double)randomness; - y += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D - * (double)randomness; - z += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D - * (double)randomness; - x *= (double)speed; - y *= (double)speed; - z *= (double)speed; - this.motionX = x; - this.motionY = y; - this.motionZ = z; - float f3 = MathHelper.sqrt(x * x + z * z); - this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(x, z) * 180.0D / Math.PI); - this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(y, (double)f3) * 180.0D / Math.PI); - this.ticksInGround = 0; + public EntityLivingBase getCaster(){ + return caster == null ? null : caster.get(); } - // There was an override for setPositionAndRotationDirect here, but it was exactly the same as the superclass - // method (in Entity), so it was removed since it was redundant. - - /** - * Sets the velocity to the args. Args: x, y, z. THIS IS CLIENT SIDE ONLY! DO NOT USE IN COMMON OR SERVER CODE! - */ - @Override - @SideOnly(Side.CLIENT) - public void setVelocity(double p_70016_1_, double p_70016_3_, double p_70016_5_){ - this.motionX = p_70016_1_; - this.motionY = p_70016_3_; - this.motionZ = p_70016_5_; - - if(this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F){ - float f = MathHelper.sqrt(p_70016_1_ * p_70016_1_ + p_70016_5_ * p_70016_5_); - this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(p_70016_1_, p_70016_5_) * 180.0D / Math.PI); - this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(p_70016_3_, (double)f) * 180.0D / Math.PI); - this.prevRotationPitch = this.rotationPitch; - this.prevRotationYaw = this.rotationYaw; - this.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch); - this.ticksInGround = 0; - } + public void setCaster(EntityLivingBase entity){ + caster = new WeakReference(entity); } + + // Methods triggered during the update cycle - /** - * Called each tick when the projectile is in a block. Defaults to setDead(), but can be overridden to change the - * behaviour. - */ - public void tickInGround(){ + /** Called each tick when the projectile is in a block. Defaults to setDead(), but can be overridden to change the + * behaviour. */ + protected void tickInGround(){ this.setDead(); } /** Called each tick when the projectile is in the air. Override to add particles and such like. */ - public void tickInAir(){ - } + protected void tickInAir(){} /** Called when the projectile hits an entity. Override to add potion effects and such like. */ - public void onEntityHit(EntityLivingBase entityHit){ - } + protected void onEntityHit(EntityLivingBase entityHit){} /** Called when the projectile hits a block. Override to add sound effects and such like. */ - public void onBlockHit(){ - } + protected void onBlockHit(){} @Override public void onUpdate(){ super.onUpdate(); - if(this.getShootingEntity() == null && this.casterUUID != null){ + if(this.getCaster() == null && this.casterUUID != null){ Entity entity = WizardryUtilities.getEntityByUUID(world, casterUUID); if(entity instanceof EntityLivingBase){ - this.shootingEntity = new WeakReference((EntityLivingBase)entity); + this.caster = new WeakReference((EntityLivingBase)entity); } } @@ -320,7 +273,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE for(i = 0; i < list.size(); ++i){ Entity entity1 = (Entity)list.get(i); - if(entity1.canBeCollidedWith() && (entity1 != this.getShootingEntity() || this.ticksInAir >= 5)){ + if(entity1.canBeCollidedWith() && (entity1 != this.getCaster() || this.ticksInAir >= 5)){ f1 = 0.3F; AxisAlignedBB axisalignedbb1 = entity1.getEntityBoundingBox().grow((double)f1, (double)f1, (double)f1); @@ -347,8 +300,8 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE && raytraceresult.entityHit instanceof EntityPlayer){ EntityPlayer entityplayer = (EntityPlayer)raytraceresult.entityHit; - if(entityplayer.capabilities.disableDamage || this.getShootingEntity() instanceof EntityPlayer - && !((EntityPlayer)this.getShootingEntity()).canAttackPlayer(entityplayer)){ + if(entityplayer.capabilities.disableDamage || this.getCaster() instanceof EntityPlayer + && !((EntityPlayer)this.getCaster()).canAttackPlayer(entityplayer)){ raytraceresult = null; } } @@ -359,11 +312,11 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE if(raytraceresult.entityHit != null){ DamageSource damagesource = null; - if(this.getShootingEntity() == null){ + if(this.getCaster() == null){ damagesource = DamageSource.causeThrownDamage(this, this); }else{ damagesource = MagicDamage.causeIndirectMagicDamage(this, - (EntityLivingBase)this.getShootingEntity(), this.getDamageType()).setProjectile(); + (EntityLivingBase)this.getCaster(), this.getDamageType()).setProjectile(); } if(raytraceresult.entityHit.attackEntityFrom(damagesource, @@ -386,17 +339,17 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE } // Thorns enchantment - if(this.getShootingEntity() != null - && this.getShootingEntity() instanceof EntityLivingBase){ - EnchantmentHelper.applyThornEnchantments(entityHit, this.getShootingEntity()); - EnchantmentHelper.applyArthropodEnchantments((EntityLivingBase)this.getShootingEntity(), + if(this.getCaster() != null + && this.getCaster() instanceof EntityLivingBase){ + EnchantmentHelper.applyThornEnchantments(entityHit, this.getCaster()); + EnchantmentHelper.applyArthropodEnchantments((EntityLivingBase)this.getCaster(), entityHit); } - if(this.getShootingEntity() != null && raytraceresult.entityHit != this.getShootingEntity() + if(this.getCaster() != null && raytraceresult.entityHit != this.getCaster() && raytraceresult.entityHit instanceof EntityPlayer - && this.getShootingEntity() instanceof EntityPlayerMP){ - ((EntityPlayerMP)this.getShootingEntity()).connection + && this.getCaster() instanceof EntityPlayerMP){ + ((EntityPlayerMP)this.getCaster()).connection .sendPacket(new SPacketChangeGameState(6, 0.0F)); } } @@ -497,6 +450,51 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE } } + @Override + public void shoot(double x, double y, double z, float speed, float randomness){ + float f2 = MathHelper.sqrt(x * x + y * y + z * z); + x /= (double)f2; + y /= (double)f2; + z /= (double)f2; + x += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)randomness; + y += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)randomness; + z += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)randomness; + x *= (double)speed; + y *= (double)speed; + z *= (double)speed; + this.motionX = x; + this.motionY = y; + this.motionZ = z; + float f3 = MathHelper.sqrt(x * x + z * z); + this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(x, z) * 180.0D / Math.PI); + this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(y, (double)f3) * 180.0D / Math.PI); + this.ticksInGround = 0; + } + + // There was an override for setPositionAndRotationDirect here, but it was exactly the same as the superclass + // method (in Entity), so it was removed since it was redundant. + + /** Sets the velocity to the args. Args: x, y, z. THIS IS CLIENT SIDE ONLY! DO NOT USE IN COMMON OR SERVER CODE! */ + @Override + @SideOnly(Side.CLIENT) + public void setVelocity(double p_70016_1_, double p_70016_3_, double p_70016_5_){ + this.motionX = p_70016_1_; + this.motionY = p_70016_3_; + this.motionZ = p_70016_5_; + + if(this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F){ + float f = MathHelper.sqrt(p_70016_1_ * p_70016_1_ + p_70016_5_ * p_70016_5_); + this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(p_70016_1_, p_70016_5_) * 180.0D / Math.PI); + this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(p_70016_3_, (double)f) * 180.0D / Math.PI); + this.prevRotationPitch = this.rotationPitch; + this.prevRotationYaw = this.rotationYaw; + this.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch); + this.ticksInGround = 0; + } + } + + // Data reading and writing + @Override public void writeEntityToNBT(NBTTagCompound tag){ tag.setShort("xTile", (short)this.blockX); @@ -512,8 +510,8 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE tag.setByte("shake", (byte)this.arrowShake); tag.setByte("inGround", (byte)(this.inGround ? 1 : 0)); tag.setFloat("damageMultiplier", this.damageMultiplier); - if(this.getShootingEntity() != null){ - tag.setUniqueId("casterUUID", this.getShootingEntity().getUniqueID()); + if(this.getCaster() != null){ + tag.setUniqueId("casterUUID", this.getCaster().getUniqueID()); } } @@ -531,58 +529,35 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE this.damageMultiplier = tag.getFloat("damageMultiplier"); casterUUID = tag.getUniqueId("casterUUID"); } + + @Override + public void writeSpawnData(ByteBuf buffer){ + if(this.getCaster() != null) buffer.writeInt(this.getCaster().getEntityId()); + } - /** - * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to - * prevent them from trampling crops - */ + @Override + public void readSpawnData(ByteBuf buffer){ + if(buffer.isReadable()) this.caster = new WeakReference( + (EntityLivingBase)this.world.getEntityByID(buffer.readInt())); + } + + // Miscellaneous overrides + + @Override protected boolean canTriggerWalking(){ return false; } + + @Override + public boolean canBeAttackedWithItem(){ + return false; + } @SideOnly(Side.CLIENT) public float getShadowSize(){ return 0.0F; } - /** - * Sets the amount of knockback the arrow applies when it hits a mob. - */ - public void setKnockbackStrength(int p_70240_1_){ - this.knockbackStrength = p_70240_1_; - } - - /** - * If returns false, the item will not inflict any damage against entities. - */ - public boolean canAttackWithItem(){ - return false; - } - - public void writeSpawnData(ByteBuf buffer){ - if(this.getShootingEntity() != null) buffer.writeInt(this.getShootingEntity().getEntityId()); - } - - public void readSpawnData(ByteBuf buffer){ - if(buffer.isReadable()) this.shootingEntity = new WeakReference( - (EntityLivingBase)this.world.getEntityByID(buffer.readInt())); - } - - /** - * Returns the EntityLivingBase that created this construct, or null if it no longer exists. Cases where the entity - * may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported to - * another dimension, or this construct simply had no caster in the first place. - */ - public EntityLivingBase getShootingEntity(){ - return shootingEntity == null ? null : shootingEntity.get(); - } - - public void setShootingEntity(EntityLivingBase entity){ - shootingEntity = new WeakReference(entity); - } - @Override - protected void entityInit() { - // TODO Auto-generated method stub - } + protected void entityInit(){} } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java index 76ddbda4..e2ccd32b 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java @@ -2,43 +2,22 @@ package electroblob.wizardry.entity.projectile; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; import net.minecraft.world.World; public class EntityMagicMissile extends EntityMagicArrow { - /** Basic shell constructor. Should only be used by the client. */ + /** Creates a new magic missile in the given world. */ public EntityMagicMissile(World world){ super(world); } - /** - * Creates a projectile at position xyz in world, with no motion. Do not create a projectile with this constructor - * and then call setVelocity() as that method is, bizarrely, client-side only. - */ - public EntityMagicMissile(World world, double x, double y, double z){ - super(world, x, y, z); - } + @Override public double getDamage(){ return 4.0d; } - /** - * Creates a projectile at the position of the caster, pointing at the given target. The trajectory seems to be - * altered slightly by a random amount determined by the last parameter. For reference, skeletons set this to 10 on - * easy, 6 on normal and 2 on hard difficulty. - */ - public EntityMagicMissile(World world, EntityLivingBase caster, Entity target, float speed, float aimingError, - float damageMultiplier){ - super(world, caster, target, speed, aimingError, damageMultiplier); - } + @Override public boolean doGravity(){ return false; } - /** - * Creates a projectile pointing in the direction the caster is looking, with the given speed. USE THIS CONSTRUCTOR - * FOR NORMAL SPELLS. - */ - public EntityMagicMissile(World world, EntityLivingBase caster, float speed, float damageMultiplier){ - super(world, caster, speed, damageMultiplier); - } + @Override public boolean doDeceleration(){ return false; } @Override public void onEntityHit(EntityLivingBase entityHit){ @@ -70,23 +49,6 @@ public class EntityMagicMissile extends EntityMagicArrow { } @Override - public double getDamage(){ - return 4.0d; - } - - @Override - public boolean doGravity(){ - return false; - } - - @Override - public boolean doDeceleration(){ - return false; - } - - @Override - protected void entityInit(){ - - } + protected void entityInit(){ } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java index 3aad3978..0045eb34 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java @@ -5,6 +5,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.projectile.EntityThrowable; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; @@ -15,10 +16,7 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; *

* This class purely handles saving of the damage multiplier; EntityThrowable is pretty well suited to my purposes as it * is. Range is done via the velocity when the constructor is called. Caster is already handled by - * EntityThrowable.getThrower(). - * - * Note that this class does not implement {@link IEntityAdditionalSpawnData}; subclasses that need to transfer extra - * data to the client should implement that interface themselves. See {@link EntityBomb} for an example. + * EntityThrowable.getThrower(), though due to a bug in vanilla it has to be synced by this class. * * @since Wizardry 1.0 * @author Electroblob @@ -28,70 +26,52 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I public float damageMultiplier = 1.0f; + /** Creates a new projectile in the given world. */ public EntityMagicProjectile(World world){ super(world); } - public EntityMagicProjectile(World world, EntityLivingBase thrower){ - super(world, thrower); + // Initialiser methods + + /** Sets the shooter of the projectile to the given caster, positions the projctile at the given caster's eyes and + * aims it in the direction they are looking with the given speed. */ + public void aim(EntityLivingBase caster, float speed){ + this.setPosition(caster.posX, caster.posY + (double)caster.getEyeHeight() - 0.1d, caster.posZ); + // This is the standard set of parameters for this method, used by snowballs and ender pearls amongst others. + this.shoot(caster, caster.rotationPitch, caster.rotationYaw, 0.0f, speed, 1.0f); + this.thrower = caster; + // Mojang's 'fix' for the projectile-hitting-thrower bug actually made the problem worse, hence the following line. + this.ignoreEntity = caster; } - public EntityMagicProjectile(World world, EntityLivingBase thrower, float damageMultiplier){ - super(world, thrower); - // This is the standard set of parameters for this method, used by snowballs and ender pearls amongst others. - this.shoot(thrower, thrower.rotationPitch, thrower.rotationYaw, 0.0f, this.getSpeed(), 1.0f); - this.damageMultiplier = damageMultiplier; + /** Sets the shooter of the projectile to the given caster, positions the projctile at the given caster's eyes and + * aims it at the given target with the given speed. The trajectory will be altered slightly by a random amount + * determined by the aimingError parameter. For reference, skeletons set this to 10 on easy, 6 on normal and 2 on hard + * difficulty. */ + public void aim(EntityLivingBase caster, Entity target, float speed, float aimingError){ + + this.thrower = caster; // Mojang's 'fix' for the projectile-hitting-thrower bug actually made the problem worse, hence the following line. this.ignoreEntity = thrower; - } - public EntityMagicProjectile(World world, double x, double y, double z){ - super(world, x, y, z); - } + this.posY = caster.posY + (double)caster.getEyeHeight() - 0.1d; + double dx = target.posX - caster.posX; + double dy = !this.hasNoGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0f) - this.posY + : target.getEntityBoundingBox().minY + (double)(target.height / 2.0f) - this.posY; + double dz = target.posZ - caster.posZ; + double horizontalDistance = (double)MathHelper.sqrt(dx * dx + dz * dz); - /** This got removed at some point since 1.7.10, but I liked it so I thought I'd add it back in again. */ - protected float getSpeed(){ - return 1.5f; - } + if(horizontalDistance >= 1.0E-7D){ + + double dxNormalised = dx / horizontalDistance; + double dzNormalised = dz / horizontalDistance; + this.setPosition(caster.posX + dxNormalised, this.posY, caster.posZ + dzNormalised); - /** Sets this projectile's velocity as a normalised vector towards the target. */ - public void directTowards(Entity target, float velocity){ - - double dx = target.posX - this.posX; - double dy = target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - - (this.posY + (double)(this.height / 2.0F)); - double dz = target.posZ - this.posZ; - - this.motionX = dx / this.getDistance(target) * velocity; - this.motionY = dy / this.getDistance(target) * velocity; - this.motionZ = dz / this.getDistance(target) * velocity; - } - - @Override - public void onUpdate(){ - // This fixes the client-side projectile-hitting-thrower bug. Comparing with 1.10.2, this was caused by a change - // to the line EntityThrowable:215, where a thrower != null check was added. Since the thrower field is not synced, - // this fails and the ignoreEntity field is never set, causing the projectile to hit its thrower client-side. - // The 'proper' way to fix this is to use IEntityAdditionalSpawnData to sync the thrower field, but I don't really - // want to waste packets like that, so, since things worked just fine in 1.10.2 without the thrower != null check, - // it makes sense to just duplicate that block of code and remove the offending check. - // The only side-effect (and probably why the change was made to vanilla) is that if this entity is summoned - // inside a mob using commands, it wouldn't hit that mob. This is so minor that it's not worth sending a packet - // for, though it may become more noticeable if spells firing from blocks are added. - // TODO: Investigate whether this is still necessary in 1.12 -// if(this.world.isRemote){ -// -// List list = this.world.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox().expand(this.motionX, this.motionY, this.motionZ).grow(1.0D)); -// -// for(Entity entity : list){ // Why does vanilla still not use a for-each loop? -// if(entity.canBeCollidedWith() && this.ticksExisted < 2 && this.ignoreEntity == null){ -// this.ignoreEntity = entity; -// } -// } -// // Pretty sure EntityThrowable handles the rest. -// } - - super.onUpdate(); + // Depends on the horizontal distance between the two entities and accounts for bullet drop, + // but of course if gravity is ignored this should be 0 since there is no bullet drop. + float bulletDropCompensation = !this.hasNoGravity() ? (float)horizontalDistance * 0.2f : 0; + this.shoot(dx, dy + (double)bulletDropCompensation, dz, speed, aimingError); + } } @Override @@ -107,15 +87,20 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I } @Override + // For now, we're only writing when the thrower exists, so subclasses MUST CALL SUPER LAST. + // TODO: Figure out whether there's a default value we can write that is never used as an entity id (0? -1? +/-MAX_VALUE?) public void writeSpawnData(ByteBuf data){ - data.writeInt(this.getThrower().getEntityId()); + if(this.getThrower() != null) data.writeInt(this.getThrower().getEntityId()); } @Override + // For now, we're only writing when the thrower exists, so subclasses MUST CALL SUPER LAST. public void readSpawnData(ByteBuf data){ - Entity entity = this.world.getEntityByID(data.readInt()); - if(entity instanceof EntityLivingBase) this.thrower = (EntityLivingBase)entity; - this.ignoreEntity = this.thrower; + if(data.isReadable()){ + Entity entity = this.world.getEntityByID(data.readInt()); + if(entity instanceof EntityLivingBase) this.thrower = (EntityLivingBase)entity; + this.ignoreEntity = this.thrower; + } } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java index 94f739f8..c2ae3d54 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java @@ -18,26 +18,14 @@ import net.minecraft.world.World; public class EntityPoisonBomb extends EntityBomb { - public EntityPoisonBomb(World par1World){ - super(par1World); + public EntityPoisonBomb(World world){ + super(world); } - - public EntityPoisonBomb(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntityPoisonBomb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, - float blastMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); - } - - public EntityPoisonBomb(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); - } - + @Override - protected void onImpact(RayTraceResult par1RayTraceResult){ - Entity entityHit = par1RayTraceResult.entityHit; + protected void onImpact(RayTraceResult rayTrace){ + + Entity entityHit = rayTrace.entityHit; if(entityHit != null){ // This is if the poison bomb gets a direct hit diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java index 5d6a432d..61dcf727 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java @@ -18,25 +18,12 @@ import net.minecraft.world.World; public class EntitySmokeBomb extends EntityBomb { - public EntitySmokeBomb(World par1World){ - super(par1World); - } - - public EntitySmokeBomb(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntitySmokeBomb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, - float blastMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); - } - - public EntitySmokeBomb(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); + public EntitySmokeBomb(World world){ + super(world); } @Override - protected void onImpact(RayTraceResult par1RayTraceResult){ + protected void onImpact(RayTraceResult rayTrace){ // Particle effect if(world.isRemote){ diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java index 8415bbee..f4aed2bc 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java @@ -15,32 +15,14 @@ import net.minecraft.world.World; public class EntitySpark extends EntityMagicProjectile { - public EntitySpark(World par1World){ - super(par1World); + public EntitySpark(World world){ + super(world); } - public EntitySpark(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntitySpark(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier); - } - - public EntitySpark(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); - } - - /** This is the speed */ - protected float getSpeed(){ - return 0.5F; - } - - /** - * Called when this EntityThrowable hits a block or entity. - */ - protected void onImpact(RayTraceResult par1RayTraceResult){ - Entity entityHit = par1RayTraceResult.entityHit; + @Override + protected void onImpact(RayTraceResult rayTrace){ + + Entity entityHit = rayTrace.entityHit; if(entityHit != null){ @@ -98,17 +80,13 @@ public class EntitySpark extends EntityMagicProjectile { this.setDead(); } } - - /** - * Gets the amount of gravity to apply to the thrown entity with each tick. - */ - protected float getGravityVelocity(){ - return 0.0F; + + @Override + public boolean hasNoGravity(){ + return true; } - /** - * Return whether this entity should be rendered as on fire. - */ + @Override public boolean canRenderOnFire(){ return false; } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java index 29421463..6b8a92b1 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java @@ -7,42 +7,26 @@ import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; public class EntitySparkBomb extends EntityBomb { - public EntitySparkBomb(World par1World){ - super(par1World); + public EntitySparkBomb(World world){ + super(world); } - public EntitySparkBomb(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } - - public EntitySparkBomb(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier, - float blastMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier, blastMultiplier); - } - - public EntitySparkBomb(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); - } - - /** - * Called when this EntityThrowable hits a block or entity. - */ - protected void onImpact(RayTraceResult par1RayTraceResult){ + @Override + protected void onImpact(RayTraceResult rayTrace){ + this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST_FAR, 0.5f, 0.5f); - Entity entityHit = par1RayTraceResult.entityHit; + Entity entityHit = rayTrace.entityHit; if(entityHit != null){ // This is if the spark bomb gets a direct hit @@ -58,15 +42,7 @@ public class EntitySparkBomb extends EntityBomb { // Particle effect if(world.isRemote){ - for(int i = 0; i < 8; i++){ - double x = this.posX + rand.nextDouble() - 0.5; - double y = this.posY + this.height / 2 + rand.nextDouble() - 0.5; - double z = this.posZ + rand.nextDouble() - 0.5; - ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + rand.nextFloat() - 0.5, - this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, - 0); - } + ParticleBuilder.spawnShockParticles(world, posX, posY + height/2, posZ); } double seekerRange = 5.0d * blastMultiplier; @@ -102,15 +78,7 @@ public class EntitySparkBomb extends EntityBomb { }else{ // Particle effect - for(int j = 0; j < 8; j++){ - double x = target.posX + rand.nextFloat() - 0.5; - double y = target.getEntityBoundingBox().minY + target.height * rand.nextFloat(); - double z = target.posZ + rand.nextFloat() - 0.5; - ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, target.posX + rand.nextFloat() - 0.5, - target.getEntityBoundingBox().minY + target.height * rand.nextFloat(), - target.posZ + rand.nextFloat() - 0.5, 0, 0, 0); - } + ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); } } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java index d38bcfce..7508b150 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java @@ -5,7 +5,6 @@ import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; @@ -17,26 +16,11 @@ public class EntityThunderbolt extends EntityMagicProjectile { super(par1World); } - public EntityThunderbolt(World par1World, EntityLivingBase par2EntityLivingBase){ - super(par1World, par2EntityLivingBase); - } + @Override public boolean hasNoGravity(){ return true; } - public EntityThunderbolt(World par1World, EntityLivingBase par2EntityLivingBase, float damageMultiplier){ - super(par1World, par2EntityLivingBase, damageMultiplier); - } - - public EntityThunderbolt(World par1World, double par2, double par4, double par6){ - super(par1World, par2, par4, par6); - } - - /** This is the speed */ - protected float getSpeed(){ - return 2.5F; - } - - /** - * Called when this EntityThrowable hits a block or entity. - */ + @Override public boolean canRenderOnFire(){ return false; } + + @Override protected void onImpact(RayTraceResult par1RayTraceResult){ Entity entityHit = par1RayTraceResult.entityHit; @@ -63,6 +47,7 @@ public class EntityThunderbolt extends EntityMagicProjectile { this.setDead(); } + @Override public void onUpdate(){ super.onUpdate(); @@ -80,18 +65,5 @@ public class EntityThunderbolt extends EntityMagicProjectile { this.setDead(); } } - - /** - * Gets the amount of gravity to apply to the thrown entity with each tick. - */ - protected float getGravityVelocity(){ - return 0.0F; - } - - /** - * Return whether this entity should be rendered as on fire. - */ - public boolean canRenderOnFire(){ - return false; - } + } diff --git a/src/main/java/electroblob/wizardry/item/ItemFirebomb.java b/src/main/java/electroblob/wizardry/item/ItemFirebomb.java index 27cb433c..1a3a6097 100644 --- a/src/main/java/electroblob/wizardry/item/ItemFirebomb.java +++ b/src/main/java/electroblob/wizardry/item/ItemFirebomb.java @@ -30,9 +30,8 @@ public class ItemFirebomb extends Item { player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); if(!world.isRemote){ - EntityFirebomb firebomb = new EntityFirebomb(world, player); - // This is the standard set of parameters for this method, used by snowballs and ender pearls. - firebomb.shoot(player, player.rotationPitch, player.rotationYaw, 0.0f, 1.5f, 1.0f); + EntityFirebomb firebomb = new EntityFirebomb(world); + firebomb.aim(player, 1.5f); world.spawnEntity(firebomb); } diff --git a/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java b/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java index 3613e0e7..76a9f12a 100644 --- a/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java +++ b/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java @@ -30,9 +30,8 @@ public class ItemPoisonBomb extends Item { player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); if(!world.isRemote){ - EntityPoisonBomb poisonbomb = new EntityPoisonBomb(world, player); - // This is the standard set of parameters for this method, used by snowballs and ender pearls. - poisonbomb.shoot(player, player.rotationPitch, player.rotationYaw, 0.0f, 1.5f, 1.0f); + EntityPoisonBomb poisonbomb = new EntityPoisonBomb(world); + poisonbomb.aim(player, 1.5f); world.spawnEntity(poisonbomb); } diff --git a/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java b/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java index 023fe59f..880a84c4 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java +++ b/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java @@ -30,9 +30,8 @@ public class ItemSmokeBomb extends Item { player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); if(!world.isRemote){ - EntitySmokeBomb smokebomb = new EntitySmokeBomb(world, player); - // This is the standard set of parameters for this method, used by snowballs and ender pearls. - smokebomb.shoot(player, player.rotationPitch, player.rotationYaw, 0.0f, 1.5f, 1.0f); + EntitySmokeBomb smokebomb = new EntitySmokeBomb(world); + smokebomb.aim(player, 1.5f); world.spawnEntity(smokebomb); } diff --git a/src/main/java/electroblob/wizardry/item/ItemWand.java b/src/main/java/electroblob/wizardry/item/ItemWand.java index 0d146a49..522d819d 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWand.java +++ b/src/main/java/electroblob/wizardry/item/ItemWand.java @@ -375,7 +375,7 @@ public class ItemWand extends Item { // normal mob on full 20 health, but wither 2 for the same duration only deals about 6 hearts of damage in // total. if(this.element == spell.element){ - modifiers.set(SpellModifiers.DAMAGE, 1.0f + (this.tier.level + 1) * Constants.DAMAGE_INCREASE_PER_TIER, + modifiers.set(SpellModifiers.POTENCY, 1.0f + (this.tier.level + 1) * Constants.DAMAGE_INCREASE_PER_TIER, true); } @@ -401,7 +401,7 @@ public class ItemWand extends Item { private boolean selectMinionTarget(EntityPlayer player, World world){ - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, player, 16); + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, player, 16, false); if(rayTrace != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ diff --git a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java index 63484b97..bb356ec8 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java +++ b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java @@ -7,11 +7,11 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryTabs; -import electroblob.wizardry.spell.Petrify; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; @@ -142,7 +142,7 @@ public class ItemWizardArmour extends ItemArmor { // fix, considering how long I spent trying to do this before - a bit of lateral thinking was all it took. // Do note however that a texture pack could override this. if(entity instanceof EntityLivingBase && ((EntityLivingBase)entity).isInvisible() - && !entity.getEntityData().getBoolean(Petrify.NBT_KEY)) + && !entity.getEntityData().getBoolean(BlockStatue.NBT_KEY)) return "ebwizardry:textures/armour/invisible_armour.png"; if(slot == EntityEquipmentSlot.LEGS) diff --git a/src/main/java/electroblob/wizardry/potion/PotionDecay.java b/src/main/java/electroblob/wizardry/potion/PotionDecay.java index c16cb8db..db22ee7e 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionDecay.java +++ b/src/main/java/electroblob/wizardry/potion/PotionDecay.java @@ -68,8 +68,8 @@ public class PotionDecay extends Potion { EntityLivingBase target = event.getEntityLiving(); - if(target.isPotionActive(WizardryPotions.decay) && target.ticksExisted % Constants.DECAY_SPREAD_INTERVAL == 0 - && target.onGround){ + if(!target.world.isRemote && target.isPotionActive(WizardryPotions.decay) && target.onGround + && target.ticksExisted % Constants.DECAY_SPREAD_INTERVAL == 0){ List entities = target.world.getEntitiesWithinAABBExcludingEntity(target, target.getEntityBoundingBox()); @@ -80,7 +80,10 @@ public class PotionDecay extends Potion { // The victim spreading the decay is the 'caster' here, so that it can actually wear off, otherwise it // just gets infected with its own decay and the effect lasts forever. - target.world.spawnEntity(new EntityDecay(target.world, target.posX, target.posY, target.posZ, target)); + EntityDecay decay = new EntityDecay(target.world); + decay.setCaster(target); + decay.setPosition(target.posX, target.posY, target.posZ); + target.world.spawnEntity(decay); } } diff --git a/src/main/java/electroblob/wizardry/registry/Spells.java b/src/main/java/electroblob/wizardry/registry/Spells.java index b573df79..7fcc7da8 100644 --- a/src/main/java/electroblob/wizardry/registry/Spells.java +++ b/src/main/java/electroblob/wizardry/registry/Spells.java @@ -1,7 +1,49 @@ package electroblob.wizardry.registry; +import org.apache.commons.lang3.tuple.Triple; + import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityBlackHole; +import electroblob.wizardry.entity.construct.EntityBlizzard; +import electroblob.wizardry.entity.construct.EntityFireRing; +import electroblob.wizardry.entity.construct.EntityFireSigil; +import electroblob.wizardry.entity.construct.EntityForcefield; +import electroblob.wizardry.entity.construct.EntityFrostSigil; +import electroblob.wizardry.entity.construct.EntityHealAura; +import electroblob.wizardry.entity.construct.EntityLightningSigil; +import electroblob.wizardry.entity.living.EntityBlazeMinion; +import electroblob.wizardry.entity.living.EntityIceGiant; +import electroblob.wizardry.entity.living.EntityIceWraith; +import electroblob.wizardry.entity.living.EntityLightningWraith; +import electroblob.wizardry.entity.living.EntityPhoenix; +import electroblob.wizardry.entity.living.EntitySilverfishMinion; +import electroblob.wizardry.entity.living.EntitySpiderMinion; +import electroblob.wizardry.entity.living.EntityStormElemental; +import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; +import electroblob.wizardry.entity.living.EntityZombieMinion; +import electroblob.wizardry.entity.projectile.EntityDart; +import electroblob.wizardry.entity.projectile.EntityFirebolt; +import electroblob.wizardry.entity.projectile.EntityFirebomb; +import electroblob.wizardry.entity.projectile.EntityForceArrow; +import electroblob.wizardry.entity.projectile.EntityForceOrb; +import electroblob.wizardry.entity.projectile.EntityIceCharge; +import electroblob.wizardry.entity.projectile.EntityIceLance; +import electroblob.wizardry.entity.projectile.EntityIceShard; +import electroblob.wizardry.entity.projectile.EntityLightningArrow; +import electroblob.wizardry.entity.projectile.EntityLightningDisc; +import electroblob.wizardry.entity.projectile.EntityMagicMissile; +import electroblob.wizardry.entity.projectile.EntityPoisonBomb; +import electroblob.wizardry.entity.projectile.EntitySmokeBomb; +import electroblob.wizardry.entity.projectile.EntitySpark; +import electroblob.wizardry.entity.projectile.EntitySparkBomb; +import electroblob.wizardry.entity.projectile.EntityThunderbolt; import electroblob.wizardry.spell.*; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; @@ -198,36 +240,35 @@ public final class Spells { IForgeRegistry registry = event.getRegistry(); - // event.getRegistry should always equal Spell.registry. registry.register(new None()); - registry.register(new MagicMissile()); + registry.register(new SpellArrow("magic_missile", Tier.BASIC, Element.MAGIC, 5, 10, EntityMagicMissile::new, 2, WizardrySounds.SPELL_MAGIC).soundValues(1, 1.4f, 0.4f)); registry.register(new Ignite()); registry.register(new Freeze()); registry.register(new Snowball()); registry.register(new Arc()); - registry.register(new Thunderbolt()); - registry.register(new SummonZombie()); + registry.register(new SpellProjectile("thunderbolt", Tier.BASIC, Element.LIGHTNING, 10, 15, EntityThunderbolt::new, 2.5f, WizardrySounds.SPELL_ICE).soundValues(0.8f, 0.9f, 0.2f)); + registry.register(new SpellMinion<>("summon_zombie", Tier.BASIC, Element.NECROMANCY, 10, 40, EntityZombieMinion::new, 600, WizardrySounds.SPELL_SUMMONING).soundValues(7, 0.6f, 0)); registry.register(new Snare()); - registry.register(new Dart()); + registry.register(new SpellArrow("dart", Tier.BASIC, Element.EARTH, 5, 10, EntityDart::new, 2, SoundEvents.ENTITY_ARROW_SHOOT).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new Light()); registry.register(new Telekinesis()); registry.register(new Heal()); registry.register(new Fireball()); registry.register(new FlameRay()); - registry.register(new Firebomb()); - registry.register(new FireSigil()); - registry.register(new Firebolt()); + registry.register(new SpellProjectile("firebomb", Tier.APPRENTICE, Element.FIRE, 15, 25, EntityFirebomb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellConstructRanged<>("fire_sigil", Tier.APPRENTICE, Element.FIRE, SpellType.CONSTRUCT, 10, 20, EntityFireSigil::new, -1, 10, SoundEvents.ITEM_FLINTANDSTEEL_USE).floor(true)); + registry.register(new SpellProjectile("firebolt", Tier.APPRENTICE, Element.FIRE, 10, 10, EntityFirebolt::new, 2.5f, SoundEvents.ENTITY_BLAZE_SHOOT)); registry.register(new FrostRay()); registry.register(new SummonSnowGolem()); - registry.register(new IceShard()); + registry.register(new SpellArrow("ice_shard", Tier.APPRENTICE, Element.ICE, 10, 10, EntityIceShard::new, 2, WizardrySounds.SPELL_ICE).soundValues(1, 1.6f, 0.4f)); registry.register(new IceStatue()); - registry.register(new FrostSigil()); + registry.register(new SpellConstructRanged<>("frost_sigil", Tier.APPRENTICE, Element.ICE, SpellType.CONSTRUCT, 10, 20, EntityFrostSigil::new, -1, 10, WizardrySounds.SPELL_ICE).floor(true)); registry.register(new LightningRay()); - registry.register(new SparkBomb()); - registry.register(new HomingSpark()); - registry.register(new LightningSigil()); - registry.register(new LightningArrow()); + registry.register(new SpellProjectile("spark_bomb", Tier.APPRENTICE, Element.LIGHTNING, 15, 25, EntitySparkBomb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellProjectile("homing_spark", Tier.APPRENTICE, Element.LIGHTNING, 10, 20, EntitySpark::new, 0.5f, WizardrySounds.SPELL_CONJURATION).soundValues(1.0f, 0.4f, 0.2f)); + registry.register(new SpellConstructRanged<>("lightning_sigil", Tier.APPRENTICE, Element.LIGHTNING, SpellType.CONSTRUCT, 10, 20, EntityLightningSigil::new, -1, 10, WizardrySounds.SPELL_CONJURATION).floor(true)); + registry.register(new SpellArrow("lightning_arrow", Tier.APPRENTICE, Element.LIGHTNING, 15, 20, EntityLightningArrow::new, 2, WizardrySounds.SPELL_LIGHTNING).soundValues(1, 1.45f, 0.3f)); registry.register(new LifeDrain()); registry.register(new SummonSkeleton()); registry.register(new Metamorphosis()); @@ -236,69 +277,69 @@ public final class Spells { registry.register(new GrowthAura()); registry.register(new Bubble()); registry.register(new Whirlwind()); - registry.register(new PoisonBomb()); + registry.register(new SpellProjectile("poison_bomb", Tier.APPRENTICE, Element.EARTH, 15, 25, EntityPoisonBomb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new SummonSpiritWolf()); registry.register(new Blink()); - registry.register(new Agility()); - registry.register(new ConjureSword()); - registry.register(new ConjurePickaxe()); - registry.register(new ConjureBow()); - registry.register(new ForceArrow()); + registry.register(new SpellBuff("agility", Tier.APPRENTICE, Element.SORCERY, SpellType.BUFF, 20, 40, WizardrySounds.SPELL_HEAL, 0.4f, 1.0f, 0.8f, Triple.of(MobEffects.SPEED, 600, 1), Triple.of(MobEffects.JUMP_BOOST, 600, 1)).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellConjuration("conjure_sword", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 25, 50, WizardryItems.spectral_sword, WizardrySounds.SPELL_CONJURATION)); + registry.register(new SpellConjuration("conjure_pickaxe", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 25, 50, WizardryItems.spectral_pickaxe, WizardrySounds.SPELL_CONJURATION)); + registry.register(new SpellConjuration("conjure_bow", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 40, 50, WizardryItems.spectral_bow, WizardrySounds.SPELL_CONJURATION)); + registry.register(new SpellArrow("force_arrow", Tier.APPRENTICE, Element.SORCERY, 15, 20, EntityForceArrow::new, 1, WizardrySounds.SPELL_FORCE).soundValues(1, 1.3f, 0.2f)); registry.register(new Shield()); registry.register(new ReplenishHunger()); registry.register(new CureEffects()); registry.register(new HealAlly()); - registry.register(new SummonBlaze()); - registry.register(new RingOfFire()); + registry.register(new SpellMinion<>("summon_blaze", Tier.ADVANCED, Element.FIRE, 40, 200, EntityBlazeMinion::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.2f)); + registry.register(new SpellConstruct<>("ring_of_fire", Tier.ADVANCED, Element.FIRE, SpellType.CONSTRUCT, 30, 100, EnumAction.BOW, EntityFireRing::new, 600, SoundEvents.ENTITY_BLAZE_SHOOT)); registry.register(new Detonate()); - registry.register(new FireResistance()); - registry.register(new Fireskin()); + registry.register(new SpellBuff("fire_resistance", Tier.ADVANCED, Element.FIRE, SpellType.DEFENCE, 20, 80, WizardrySounds.SPELL_HEAL, 1, 0.5f, 0, Triple.of(MobEffects.FIRE_RESISTANCE, 600, 0)).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("fireskin", Tier.ADVANCED, Element.FIRE, SpellType.DEFENCE, 40, 250, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 0.5f, 0, Triple.of(WizardryPotions.fireskin, 600, 0))); registry.register(new FlamingAxe()); - registry.register(new Blizzard()); - registry.register(new SummonIceWraith()); - registry.register(new IceShroud()); - registry.register(new IceCharge()); + registry.register(new SpellConstructRanged<>("blizzard", Tier.ADVANCED, Element.ICE, SpellType.CONSTRUCT, 40, 100, EntityBlizzard::new, 600, 20, WizardrySounds.SPELL_ICE)); + registry.register(new SpellMinion<>("summon_ice_wraith", Tier.ADVANCED, Element.ICE, 40, 200, EntityIceWraith::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.2f)); + registry.register(new SpellBuff("ice_shroud", Tier.ADVANCED, Element.ICE, SpellType.DEFENCE, 40, 250, WizardrySounds.SPELL_ICE, 0.3f, 0.5f, 1, Triple.of(WizardryPotions.ice_shroud, 600, 0)).soundValues(1, 1.6f, 0.4f)); + registry.register(new SpellProjectile("ice_charge", Tier.ADVANCED, Element.ICE, 20, 30, EntityIceCharge::new, 1.5f, WizardrySounds.SPELL_ICE).soundValues(1, 1.6f, 0.4f)); registry.register(new FrostAxe()); registry.register(new InvokeWeather()); registry.register(new ChainLightning()); registry.register(new LightningBolt()); - registry.register(new SummonLightningWraith()); - registry.register(new StaticAura()); - registry.register(new LightningDisc()); + registry.register(new SpellMinion<>("summon_lightning_wraith", Tier.ADVANCED, Element.LIGHTNING, 40, 200, EntityLightningWraith::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.2f)); + registry.register(new SpellBuff("static_aura", Tier.ADVANCED, Element.LIGHTNING, SpellType.DEFENCE, 40, 250, WizardrySounds.SPELL_SPARK, 0, 0.5f, 0.7f, Triple.of(WizardryPotions.static_aura, 600, 0)).soundValues(1, 1.6f, 0.4f)); + registry.register(new SpellProjectile("lightning_disc", Tier.ADVANCED, Element.LIGHTNING, 25, 60, EntityLightningDisc::new, 1.2f, WizardrySounds.SPELL_LIGHTNING).soundValues(1, 0.95f, 0.3f)); registry.register(new MindControl()); - registry.register(new SummonWitherSkeleton()); + registry.register(new SpellMinion<>("summon_wither_skeleton", Tier.ADVANCED, Element.NECROMANCY, 35, 150, EntityWitherSkeletonMinion::new, 600, WizardrySounds.SPELL_SUMMONING).soundValues(7, 0.6f, 0)); registry.register(new Entrapment()); registry.register(new WitherSkull()); - registry.register(new DarknessOrb()); + registry.register(new SpellProjectile("darkness_orb", Tier.ADVANCED, Element.NECROMANCY, 20, 20, EntityThunderbolt::new, 0.5f, SoundEvents.ENTITY_WITHER_SHOOT).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new ShadowWard()); registry.register(new Decay()); - registry.register(new WaterBreathing()); + registry.register(new SpellBuff("water_breathing", Tier.ADVANCED, Element.EARTH, SpellType.BUFF, 30, 250, WizardrySounds.SPELL_HEAL, 0.3f, 0.3f, 1, Triple.of(MobEffects.WATER_BREATHING, 1200, 0)){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Tornado()); registry.register(new Glide()); registry.register(new SummonSpiritHorse()); - registry.register(new SpiderSwarm()); + registry.register(new SpellMinion<>("spider_swarm", Tier.ADVANCED, Element.EARTH, 45, 200, EntitySpiderMinion::new, 600, SoundEvents.BLOCK_FIRE_EXTINGUISH).soundValues(1, 1.1f, 0.1f).quantity(5).range(3)); registry.register(new Slime()); registry.register(new Petrify()); - registry.register(new Invisibility()); + registry.register(new SpellBuff("invisibility", Tier.ADVANCED, Element.SORCERY, SpellType.BUFF, 35, 200, WizardrySounds.SPELL_HEAL, 0.7f, 1, 1, Triple.of(MobEffects.INVISIBILITY, 600, 0)).soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Levitation()); - registry.register(new ForceOrb()); + registry.register(new SpellProjectile("force_orb", Tier.ADVANCED, Element.SORCERY, 20, 20, EntityForceOrb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new Transportation()); registry.register(new SpectralPathway()); registry.register(new PhaseStep()); registry.register(new VanishingBox()); registry.register(new GreaterHeal()); - registry.register(new HealingAura()); - registry.register(new Forcefield()); - registry.register(new Ironflesh()); + registry.register(new SpellConstruct<>("healing_aura", Tier.ADVANCED, Element.HEALING, SpellType.CONSTRUCT, 35, 150, EnumAction.BOW, EntityHealAura::new, 600, null)); + registry.register(new SpellConstruct<>("forcefield", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 45, 200, EnumAction.BOW, EntityForcefield::new, 600, WizardrySounds.SPELL_CONJURATION_LARGE)); + registry.register(new SpellBuff("ironflesh", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 30, 100, WizardrySounds.SPELL_HEAL, 0.4f, 0.5f, 0.6f, Triple.of(MobEffects.RESISTANCE, 600, 2)).soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Transience()); registry.register(new Meteor()); registry.register(new Firestorm()); - registry.register(new SummonPhoenix()); + registry.register(new SpellMinion<>("summon_phoenix", Tier.MASTER, Element.FIRE, 150, 400, EntityPhoenix::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.1f)); registry.register(new IceAge()); registry.register(new WallOfFrost()); - registry.register(new SummonIceGiant()); + registry.register(new SpellMinion<>("summon_ice_giant", Tier.MASTER, Element.ICE, 100, 400, EntityIceGiant::new, 600, WizardrySounds.SPELL_ICE).soundValues(1, 0.15f, 0.1f)); registry.register(new Thunderstorm()); registry.register(new LightningHammer()); registry.register(new PlagueOfDarkness()); @@ -306,17 +347,17 @@ public final class Spells { registry.register(new SummonShadowWraith()); registry.register(new ForestsCurse()); registry.register(new Flight()); - registry.register(new SilverfishSwarm()); - registry.register(new BlackHole()); + registry.register(new SpellMinion<>("silverfish_swarm", Tier.MASTER, Element.EARTH, 80, 300, EntitySilverfishMinion::new, 600, SoundEvents.BLOCK_FIRE_EXTINGUISH).soundValues(1, 1.1f, 0.1f).quantity(20).range(3)); + registry.register(new SpellConstructRanged<>("black_hole", Tier.MASTER, Element.SORCERY, SpellType.CONSTRUCT, 150, 400, EntityBlackHole::new, 600, 10, SoundEvents.ENTITY_WITHER_SPAWN).soundValues(2, 0.7f, 0)); registry.register(new Shockwave()); registry.register(new SummonIronGolem()); registry.register(new ArrowRain()); - registry.register(new Diamondflesh()); - registry.register(new FontOfVitality()); + registry.register(new SpellBuff("diamondflesh", Tier.MASTER, Element.HEALING, SpellType.DEFENCE, 100, 300, WizardrySounds.SPELL_HEAL, 0.1f, 0.7f, 1, Triple.of(MobEffects.RESISTANCE, 600, 5)).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("font_of_vitality", Tier.MASTER, Element.HEALING, SpellType.DEFENCE, 75, 300, WizardrySounds.SPELL_HEAL, 1, 0.8f, 0.3f, Triple.of(MobEffects.ABSORPTION, 1200, 1), Triple.of(MobEffects.REGENERATION, 300, 1)).soundValues(0.7f, 1.2f, 0.4f)); // Wizardry 1.1 spells - registry.register(new SmokeBomb()); + registry.register(new SpellProjectile("smoke_bomb", Tier.BASIC, Element.FIRE, 10, 20, EntitySmokeBomb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new MindTrick()); registry.register(new Leap()); @@ -324,16 +365,16 @@ public final class Spells { registry.register(new Intimidate()); registry.register(new Banish()); registry.register(new SixthSense()); - registry.register(new Darkvision()); + registry.register(new SpellBuff("darkvision", Tier.APPRENTICE, Element.EARTH, SpellType.BUFF, 20, 40, WizardrySounds.SPELL_HEAL, 0, 0.4f, 0.7f, Triple.of(MobEffects.NIGHT_VISION, 900, 0)){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Clairvoyance()); registry.register(new PocketWorkbench()); registry.register(new ImbueWeapon()); registry.register(new InvigoratingPresence()); - registry.register(new Oakflesh()); + registry.register(new SpellBuff("oakflesh", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 20, 50, WizardrySounds.SPELL_HEAL, 0.6f, 0.5f, 0.4f, Triple.of(MobEffects.RESISTANCE, 600, 1)).soundValues(0.7f, 1.2f, 0.4f)); registry.register(new GreaterFireball()); registry.register(new FlamingWeapon()); - registry.register(new IceLance()); + registry.register(new SpellArrow("ice_lance", Tier.ADVANCED, Element.ICE, 20, 20, EntityIceLance::new, 2, WizardrySounds.SPELL_ICE).soundValues(1, 1, 0.4f)); registry.register(new FreezingWeapon()); registry.register(new IceSpikes()); registry.register(new LightningPulse()); @@ -346,7 +387,7 @@ public final class Spells { registry.register(new Hailstorm()); registry.register(new LightningWeb()); - registry.register(new SummonStormElemental()); + registry.register(new SpellMinion<>("summon_storm_elemental", Tier.MASTER, Element.LIGHTNING, 100, 400, EntityStormElemental::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.1f)); registry.register(new Earthquake()); registry.register(new FontOfMana()); } diff --git a/src/main/java/electroblob/wizardry/spell/Agility.java b/src/main/java/electroblob/wizardry/spell/Agility.java deleted file mode 100644 index dd760919..00000000 --- a/src/main/java/electroblob/wizardry/spell/Agility.java +++ /dev/null @@ -1,51 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Agility extends Spell { - - public Agility(){ - super(Tier.APPRENTICE, 20, Element.SORCERY, "agility", SpellType.UTILITY, 40, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - // 1.10 allows the particles to be completely hidden. - caster.addPotionEffect(new PotionEffect(MobEffects.SPEED, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); - caster.addPotionEffect(new PotionEffect(MobEffects.JUMP_BOOST, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - ParticleBuilder.create(Type.SPARKLE).pos(x1, y1, z1).vel(0, 0.1F, 0) - .lifetime(48 + world.rand.nextInt(12)).colour(0.4f, 1.0f, 0.8f).spawn(world); - } - Wizardry.proxy.spawnEntityParticle(world, caster, 15, 0.4f, 1.0f, 0.8f); - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Arc.java b/src/main/java/electroblob/wizardry/spell/Arc.java index 56335ed2..296b3355 100644 --- a/src/main/java/electroblob/wizardry/spell/Arc.java +++ b/src/main/java/electroblob/wizardry/spell/Arc.java @@ -1,119 +1,68 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.EntityArc; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -// This spell was the 'guinea pig' for damage types, so to speak, so there's a bit of commentary on them here that may -// be useful for future reference. -public class Arc extends Spell { +public class Arc extends SpellRay { + + private static final float BASE_DAMAGE = 3; public Arc(){ - super(Tier.BASIC, 5, Element.LIGHTNING, "arc", SpellType.ATTACK, 15, EnumAction.NONE, false); + super("arc", Tier.BASIC, Element.LIGHTNING, SpellType.ATTACK, 5, 15, false, 8, null); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 8 * modifiers.get(WizardryItems.range_upgrade), 4.0f); - - if(rayTrace != null && rayTrace.entityHit != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - Entity target = rayTrace.entityHit; - + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + if(!world.isRemote){ EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.posY + 1, caster.posZ, target.posX, - target.posY + target.height / 2, target.posZ); + arc.setEndpointCoords(caster.posX, caster.posY + 1, caster.posZ, target.posX, target.posY + target.height / 2, target.posZ); world.spawnEntity(arc); }else{ - for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 0, 0, 0, 3); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, 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, 0, 0, 0); - } + ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); } - + // This is a lot neater than it was, thanks to the damage type system. if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); } - - caster.swingArm(hand); + + // TODO: Does this mean that players hit by the spell hear no sound? target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); return true; } - + return false; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.posY + 1, caster.posZ, target.posX, - target.posY + target.height / 2, target.posZ); - world.spawnEntity(arc); - }else{ - for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 0, 0, 0, 3); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, 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, 0, 0, 0); - } - } - - // What's great about the damage type system is that, because I don't need to know if the creature resisted - // the damage here, I can simply call this without having to check for immunities at all. - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); - - caster.swingArm(hand); - target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); - return true; - } - + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean canBeCastByNPCs(){ - return true; + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; } } diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java index 6316b0f1..650e1966 100644 --- a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java +++ b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -10,105 +9,65 @@ import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber -public class ArcaneJammer extends Spell { +public class ArcaneJammer extends SpellRay { public ArcaneJammer(){ - super(Tier.ADVANCED, 30, Element.HEALING, "arcane_jammer", SpellType.ATTACK, 50, EnumAction.NONE, false); + super("arcane_jammer", Tier.ADVANCED, Element.HEALING, SpellType.ATTACK, 30, 50, false, 10, WizardrySounds.SPELL_DEFLECTION); + this.soundValues(0.7f, 1, 0.4f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - EntityLivingBase entity = (EntityLivingBase)rayTrace.entityHit; - if(entity instanceof EntityWizard) WizardryAdvancementTriggers.jam_wizard.triggerFor(caster); - + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + if(target instanceof EntityWizard && caster instanceof EntityPlayer) + WizardryAdvancementTriggers.jam_wizard.triggerFor((EntityPlayer)caster); + if(!world.isRemote){ - entity.addPotionEffect(new PotionEffect(WizardryPotions.arcane_jammer, + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.arcane_jammer, (int)(300 * modifiers.get(WizardryItems.duration_upgrade)), 0)); } } - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 0.9f, 0.3f, 0.7f); - } - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_DEFLECTION, 0.7F, - world.rand.nextFloat() * 0.4F + 0.8F); + return true; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - if(!world.isRemote){ - target.addPotionEffect(new PotionEffect(WizardryPotions.arcane_jammer, - (int)(300 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - } - - if(world.isRemote){ - - double dx = (target.posX - caster.posX) / caster.getDistance(target); - double dy = (target.posY - caster.posY) / caster.getDistance(target); - double dz = (target.posZ - caster.posZ) / caster.getDistance(target); - - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - - double x1 = caster.posX + dx * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 0.9f, 0.3f, 0.7f); - } - } - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_DEFLECTION, 0.7F, world.rand.nextFloat() * 0.4F + 0.8F); - } - + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean canBeCastByNPCs(){ + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(0.9f, 0.3f, 0.7f) + .spawn(world); + } @SubscribeEvent public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ // Arcane jammer prevents spell casting. - if(event.getEntityLiving().isPotionActive(WizardryPotions.arcane_jammer)) event.setCanceled(true); + if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.arcane_jammer)) event.setCanceled(true); } } diff --git a/src/main/java/electroblob/wizardry/spell/ArrowRain.java b/src/main/java/electroblob/wizardry/spell/ArrowRain.java index b767a523..796641fd 100644 --- a/src/main/java/electroblob/wizardry/spell/ArrowRain.java +++ b/src/main/java/electroblob/wizardry/spell/ArrowRain.java @@ -4,58 +4,38 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityArrowRain; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; -public class ArrowRain extends Spell { +public class ArrowRain extends SpellConstructRanged { public ArrowRain(){ - super(Tier.MASTER, 75, Element.SORCERY, "arrow_rain", SpellType.ATTACK, 300, EnumAction.NONE, false); + super("arrow_rain", Tier.MASTER, Element.SORCERY, SpellType.ATTACK, 75, 300, EntityArrowRain::new, 120, 20, WizardrySounds.SPELL_SUMMONING); + this.floor(true); } - + @Override - public boolean doesSpellRequirePacket(){ - return false; + protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + + // Moves the entity back towards the caster a bit, so the area of effect is better centred on the position. + // 3 is the distance to move the entity back towards the caster. + double dx = caster.posX - x; + double dz = caster.posZ - z; + double distRatio = 3 / Math.sqrt(dx * dx + dz * dz); + x += dx * distRatio; + z += dz * distRatio; + // Moves the entity up 5 blocks so that it is above mobs' heads. + y += 5; + + return super.spawnConstruct(world, x, y, z, caster, modifiers); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(20 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - if(!world.isRemote){ - double x = rayTrace.hitVec.x; - double y = rayTrace.hitVec.y; - double z = rayTrace.hitVec.z; - // Moves the entity back towards the caster a bit, so the area of effect is better centred on the - // position. - // 3.0d is the distance to move the entity back towards the caster. - double dx = caster.posX - x; - double dz = caster.posZ - z; - double distRatio = 3.0d / Math.sqrt(dx * dx + dz * dz); - x += dx * distRatio; - z += dz * distRatio; - - EntityArrowRain arrowrain = new EntityArrowRain(world, x, y + 5, z, caster, - (int)(120 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - arrowrain.rotationYaw = caster.rotationYawHead; - world.spawnEntity(arrowrain); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 1.0F, 1.0F); - return true; - } - return false; + protected void addConstructExtras(EntityArrowRain construct, EntityLivingBase caster, SpellModifiers modifiers){ + // Makes the arrows shoot in the direction the caster was looking when they cast the spell. + construct.rotationYaw = caster.rotationYawHead; } } diff --git a/src/main/java/electroblob/wizardry/spell/Banish.java b/src/main/java/electroblob/wizardry/spell/Banish.java index 01b01c73..efec3bcf 100644 --- a/src/main/java/electroblob/wizardry/spell/Banish.java +++ b/src/main/java/electroblob/wizardry/spell/Banish.java @@ -1,58 +1,48 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -public class Banish extends Spell { +public class Banish extends SpellRay { public Banish(){ - super(Tier.APPRENTICE, 15, Element.NECROMANCY, "banish", SpellType.ATTACK, 40, EnumAction.NONE, false); + super("banish", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 15, 40, false, 10, SoundEvents.ENTITY_ENDERMEN_TELEPORT); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(target instanceof EntityLivingBase){ - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - // Left as EntityLivingBase, since it's reasonable to teleport armour stands around. - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; + EntityLivingBase entity = (EntityLivingBase)target; double radius = (8 + world.rand.nextDouble() * 8) * modifiers.get(WizardryItems.range_upgrade); double angle = world.rand.nextDouble() * Math.PI * 2; - int x = MathHelper.floor(target.posX + Math.sin(angle) * radius); - int z = MathHelper.floor(target.posZ - Math.cos(angle) * radius); + int x = MathHelper.floor(entity.posX + Math.sin(angle) * radius); + int z = MathHelper.floor(entity.posZ - Math.cos(angle) * radius); int y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(x, (int)caster.getEntityBoundingBox().minY, z), (int)radius); if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double dx1 = target.posX; - double dy1 = target.getEntityBoundingBox().minY + target.height * world.rand.nextFloat(); - double dz1 = target.posZ; + for(int i=0; i<10; i++){ + double dx1 = entity.posX; + double dy1 = entity.getEntityBoundingBox().minY + entity.height * world.rand.nextFloat(); + double dz1 = entity.posZ; world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); } @@ -60,7 +50,7 @@ public class Banish extends Spell { if(y > -1){ - // This means stuff like snow layers is ignored, meaning when on snow-covered ground the caster does + // This means stuff like snow layers is ignored, meaning when on snow-covered ground the target does // not teleport 1 block above the ground. if(!world.getBlockState(new BlockPos(x, y, z)).getMaterial().blocksMovement()){ y--; @@ -72,101 +62,30 @@ public class Banish extends Spell { } if(!world.isRemote){ - target.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); + entity.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); } - target.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + entity.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); } } - - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, - 0.2f, 0.0f, 0.2f); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); - caster.swingArm(hand); + return true; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - double radius = (8 + world.rand.nextDouble() * 8) * modifiers.get(WizardryItems.range_upgrade); - double angle = world.rand.nextDouble() * Math.PI * 2; - - int x = MathHelper.floor(target.posX + Math.sin(angle) * radius); - int z = MathHelper.floor(target.posZ - Math.cos(angle) * radius); - int y = WizardryUtilities.getNearestFloorLevel(world, - new BlockPos(x, (int)caster.getEntityBoundingBox().minY, z), (int)radius); - - if(world.isRemote){ - - double dx = (target.posX - caster.posX) / caster.getDistance(target); - double dy = (target.posY - caster.posY) / caster.getDistance(target); - double dz = (target.posZ - caster.posZ) / caster.getDistance(target); - - for(int i = 1; i < 25; i += 2){ - - double x1 = caster.posX + dx * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 0, 0.2f, 0.0f, 0.2f); - } - - for(int i = 0; i < 10; i++){ - double dx1 = target.posX; - double dy1 = target.getEntityBoundingBox().minY + target.height * world.rand.nextFloat(); - double dz1 = target.posZ; - world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, - world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); - } - } - - if(y > -1){ - - // This means stuff like snow layers is ignored, meaning when on snow-covered ground the caster does - // not teleport 1 block above the ground. - if(!world.getBlockState(new BlockPos(x, y, z)).getMaterial().blocksMovement()){ - y--; - } - - if(world.getBlockState(new BlockPos(x, y + 1, z)).getMaterial().blocksMovement() - || world.getBlockState(new BlockPos(x, y + 2, z)).getMaterial().blocksMovement()){ - return false; - } - - if(!world.isRemote){ - target.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); - } - - target.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); - } - } - - caster.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); - caster.swingArm(hand); - return true; + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; } @Override - public boolean canBeCastByNPCs(){ + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + world.spawnParticle(EnumParticleTypes.PORTAL, x, y - 0.5, z, 0, 0, 0); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.2f, 0, 0.2f).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/BlackHole.java b/src/main/java/electroblob/wizardry/spell/BlackHole.java deleted file mode 100644 index f8c15034..00000000 --- a/src/main/java/electroblob/wizardry/spell/BlackHole.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityBlackHole; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.world.World; - -public class BlackHole extends Spell { - - public BlackHole(){ - super(Tier.MASTER, 150, Element.SORCERY, "black_hole", SpellType.ATTACK, 400, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(10 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - // This demonstrates beautifully the elegance of BlockPos. In 1.7.10 this required a 50-line long switch - // statement and a flag variable; now it only needs a few lines. - BlockPos pos = new BlockPos(rayTrace.hitVec).offset(rayTrace.sideHit); - - if(world.isAirBlock(pos)){ - - if(!world.isRemote){ - world.spawnEntity(new EntityBlackHole(world, pos.getX() + 0.5, pos.getY() - 1 + 0.5, - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE))); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 2.0f, 0.7f); - return true; - } - - }else{ - int x = (int)(Math.floor(caster.posX) + caster.getLookVec().x * 8); - int y = (int)(Math.floor(caster.posY) + caster.eyeHeight + caster.getLookVec().y * 8); - int z = (int)(Math.floor(caster.posZ) + caster.getLookVec().z * 8); - if(!world.isRemote){ - world.spawnEntity(new EntityBlackHole(world, x, y, z, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE))); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 2.0f, 0.7f); - return true; - } - return false; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Blink.java b/src/main/java/electroblob/wizardry/spell/Blink.java index 85fee81c..1668f32b 100644 --- a/src/main/java/electroblob/wizardry/spell/Blink.java +++ b/src/main/java/electroblob/wizardry/spell/Blink.java @@ -22,14 +22,14 @@ import net.minecraft.world.World; public class Blink extends Spell { public Blink(){ - super(Tier.APPRENTICE, 15, Element.SORCERY, "blink", SpellType.UTILITY, 25, EnumAction.NONE, false); + super("blink", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 15, 25, EnumAction.NONE, false); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - RayTraceResult rayTrace = WizardryUtilities.rayTrace(25 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); + RayTraceResult rayTrace = WizardryUtilities.standardBlockRayTrace(world, caster, + 25 * modifiers.get(WizardryItems.range_upgrade), false); // It's worth noting that on the client side, the cast() method only gets called if the server side // cast method succeeded, so you need not check any conditions for spawning particles. diff --git a/src/main/java/electroblob/wizardry/spell/Blizzard.java b/src/main/java/electroblob/wizardry/spell/Blizzard.java deleted file mode 100644 index 38a1b4b8..00000000 --- a/src/main/java/electroblob/wizardry/spell/Blizzard.java +++ /dev/null @@ -1,81 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityBlizzard; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.world.World; - -public class Blizzard extends Spell { - - public Blizzard(){ - super(Tier.ADVANCED, 40, Element.ICE, "blizzard", SpellType.ATTACK, 100, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(20 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - if(!world.isRemote){ - double x = rayTrace.hitVec.x; - double y = rayTrace.hitVec.y; - double z = rayTrace.hitVec.z; - EntityBlizzard blizzard = new EntityBlizzard(world, x, y + 0.5, z, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(blizzard); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - return true; - } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - double x = target.posX; - double y = target.posY; - double z = target.posZ; - EntityBlizzard blizzard = new EntityBlizzard(world, x, y + 0.5, z, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(blizzard); - } - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Bubble.java b/src/main/java/electroblob/wizardry/spell/Bubble.java index 7a9c5ff2..34b1698f 100644 --- a/src/main/java/electroblob/wizardry/spell/Bubble.java +++ b/src/main/java/electroblob/wizardry/spell/Bubble.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -9,115 +8,81 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public class Bubble extends Spell { +public class Bubble extends SpellRay { public Bubble(){ - super(Tier.APPRENTICE, 15, Element.EARTH, "bubble", SpellType.ATTACK, 20, EnumAction.NONE, false); + super("bubble", Tier.APPRENTICE, Element.EARTH, SpellType.ATTACK, 15, 20, false, 10, WizardrySounds.SPELL_ICE); + this.soundValues(0.5f, 1.1f, 0.2f); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + // This spell uses more than one sound, so this is required... + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_GENERIC_SWIM, 1, 1 + 0.2f * world.rand.nextFloat()); + return flag; + } - Vec3d look = caster.getLookVec(); + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag) caster.playSound(SoundEvents.ENTITY_GENERIC_SWIM, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return flag; + } - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - EntityLivingBase entity = (EntityLivingBase)rayTrace.entityHit; + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + if(!world.isRemote){ - entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), - 1.0f * modifiers.get(SpellModifiers.DAMAGE)); - // Deprecated in favour of entity riding method - // entity.addPotionEffect(new PotionEffect(Wizardry.bubblePotion, 200, 0)); - EntityBubble entitybubble = new EntityBubble(world, entity.posX, entity.posY, entity.posZ, caster, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), false, - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(entitybubble); - entity.startRiding(entitybubble); + // Deals a small amount damage so the target counts as being hit by the caster + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), 1); + + EntityBubble bubble = new EntityBubble(world); + bubble.setPosition(target.posX, target.posY, target.posZ); + bubble.setCaster(caster); + bubble.lifetime = ((int)(200 * modifiers.get(WizardryItems.duration_upgrade))); + bubble.isDarkOrb = false; + bubble.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + + world.spawnEntity(bubble); + target.startRiding(bubble); } } - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - world.spawnParticle(EnumParticleTypes.WATER_SPLASH, x1, y1, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(Type.MAGIC_BUBBLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0); - } - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_GENERIC_SWIM, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5F, - world.rand.nextFloat() * 0.2F + 1.0F); + return true; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), - 1.0f * modifiers.get(SpellModifiers.DAMAGE)); - // Deprecated in favour of entity riding method - // entity.addPotionEffect(new PotionEffect(Wizardry.bubblePotion, 200, 0)); - EntityBubble entitybubble = new EntityBubble(world, target.posX, target.posY, target.posZ, caster, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), false, - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(entitybubble); - target.startRiding(entitybubble); - - } - if(world.isRemote){ - - double dx = (target.posX - caster.posX) / caster.getDistance(target); - double dy = (target.posY - caster.posY) / caster.getDistance(target); - double dz = (target.posZ - caster.posZ) / caster.getDistance(target); - - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - - double x1 = caster.posX + dx * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - world.spawnParticle(EnumParticleTypes.WATER_SPLASH, x1, y1, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(Type.MAGIC_BUBBLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 0); - } - } - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_GENERIC_SWIM, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); - caster.playSound(WizardrySounds.SPELL_ICE, 0.5F, world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean canBeCastByNPCs(){ + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + world.spawnParticle(EnumParticleTypes.WATER_SPLASH, x, y, z, 0, 0, 0); + ParticleBuilder.create(Type.MAGIC_BUBBLE).pos(x, y, z).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/ChainLightning.java b/src/main/java/electroblob/wizardry/spell/ChainLightning.java index 78422b25..ca23af59 100644 --- a/src/main/java/electroblob/wizardry/spell/ChainLightning.java +++ b/src/main/java/electroblob/wizardry/spell/ChainLightning.java @@ -2,181 +2,116 @@ package electroblob.wizardry.spell; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.EntityArc; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.item.EntityArmorStand; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class ChainLightning extends Spell { +public class ChainLightning extends SpellRay { + + private static final float PRIMARY_DAMAGE = 10; + private static final float SECONDARY_DAMAGE = 8; + private static final float TERTIARY_DAMAGE = 6; + + private static final double PRIMARY_RANGE = 10; + private static final double SECONDARY_RANGE = 5; + private static final double TERTIARY_RANGE = 5; + + private static final int SECONDARY_MAX_TARGETS = 5; + private static final int TERTIARY_MAX_TARGETS = 2; // This is per secondary target, giving 10 in total public ChainLightning(){ - super(Tier.ADVANCED, 25, Element.LIGHTNING, "chain_lightning", SpellType.ATTACK, 50, EnumAction.NONE, false); + super("chain_lightning", Tier.ADVANCED, Element.LIGHTNING, SpellType.ATTACK, 25, 50, false, PRIMARY_RANGE, null); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - // First shot has range 10 (this is the only range affected by upgrades) and does 5 hearts of damage. - // Chains to up to 5 secondary targets within a range of 5 of the primary target, and then to up to 2 - // tertiary targets per secondary target within a range of 5 of that. Secondary targets are dealt 4 hearts - // of damage; tertiary targets are dealt 3 hearts of damage. - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade), 8.0f); + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ // Anything can be attacked with the initial arc, because the player has control over where it goes. If they // hit a minion or an ally, it's their problem! - if(rayTrace != null && rayTrace.entityHit != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ + if(WizardryUtilities.isLiving(target)){ - Entity target = rayTrace.entityHit; - - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.posY + caster.height / 2, caster.posZ, target.posX, - target.posY + target.height / 2, target.posZ); - world.spawnEntity(arc); - }else{ - for(int i = 0; i < 8; i++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 0, 0, 0, 3); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, 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, 0, 0, 0); - } - } - - target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); - - if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); - }else{ - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 10.0f * modifiers.get(SpellModifiers.DAMAGE)); - } + electrocute(world, caster, caster, target, PRIMARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); // Secondary chaining effect - double seekerRange = 5.0d; - - List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(SECONDARY_RANGE, target.posX, target.posY + target.height / 2, target.posZ, world); - - secondaryTargets.removeIf(e -> e instanceof EntityArmorStand); - for(int i = 0; i < Math.min(secondaryTargets.size(), 5); i++){ + secondaryTargets.remove(target); + secondaryTargets.removeIf(e -> !WizardryUtilities.isLiving(e)); + secondaryTargets.removeIf(e -> !WizardryUtilities.isValidTarget(caster, e)); + if(secondaryTargets.size() > SECONDARY_MAX_TARGETS) secondaryTargets = secondaryTargets.subList(0, SECONDARY_MAX_TARGETS); - EntityLivingBase secondaryTarget = secondaryTargets.get(i); + for(EntityLivingBase secondaryTarget : secondaryTargets){ - if(secondaryTarget != target && WizardryUtilities.isValidTarget(caster, secondaryTarget)){ + electrocute(world, caster, target, secondaryTarget, + SECONDARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(target.posX, target.posY + target.height / 2, target.posZ, - secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, - secondaryTarget.posZ); - world.spawnEntity(arc); - }else{ - for(int j = 0; j < 8; j++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 3); - 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); - } - } + // Tertiary chaining effect - secondaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(TERTIARY_RANGE, + secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, + secondaryTarget.posZ, world); - if(MagicDamage.isEntityImmune(DamageType.SHOCK, secondaryTarget)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", - secondaryTarget.getName(), this.getNameForTranslationFormatted())); - }else{ - secondaryTarget.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 8.0f * modifiers.get(SpellModifiers.DAMAGE)); - } + tertiaryTargets.remove(target); + tertiaryTargets.removeAll(secondaryTargets); + tertiaryTargets.removeIf(e -> !WizardryUtilities.isLiving(e)); + tertiaryTargets.removeIf(e -> !WizardryUtilities.isValidTarget(caster, e)); + if(tertiaryTargets.size() > TERTIARY_MAX_TARGETS) tertiaryTargets = tertiaryTargets.subList(0, TERTIARY_MAX_TARGETS); - // Tertiary chaining effect - - List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, - secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, - secondaryTarget.posZ, world); - - tertiaryTargets.removeIf(e -> e instanceof EntityArmorStand); - - for(int j = 0; j < Math.min(tertiaryTargets.size(), 2); j++){ - - EntityLivingBase tertiaryTarget = (EntityLivingBase)tertiaryTargets.get(j); - - if(tertiaryTarget != target && !secondaryTargets.contains(tertiaryTarget) - && WizardryUtilities.isValidTarget(caster, tertiaryTarget)){ - - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(secondaryTarget.posX, - secondaryTarget.posY + secondaryTarget.height / 2, secondaryTarget.posZ, - tertiaryTarget.posX, tertiaryTarget.posY + tertiaryTarget.height / 2, - tertiaryTarget.posZ); - world.spawnEntity(arc); - }else{ - for(int k = 0; k < 8; k++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - tertiaryTarget.posX + world.rand.nextFloat() - 0.5, - tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2 - + world.rand.nextFloat() * 2 - 1, - tertiaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, - tertiaryTarget.posX + world.rand.nextFloat() - 0.5, - tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2 - + world.rand.nextFloat() * 2 - 1, - tertiaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); - } - } - - tertiaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, - world.rand.nextFloat() * 0.4F + 1.5F); - - if(MagicDamage.isEntityImmune(DamageType.SHOCK, tertiaryTarget)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", - tertiaryTarget.getName(), this.getNameForTranslationFormatted())); - }else{ - tertiaryTarget.attackEntityFrom( - MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 6.0f * modifiers.get(SpellModifiers.DAMAGE)); - } - } - } + for(EntityLivingBase tertiaryTarget : tertiaryTargets){ + electrocute(world, caster, secondaryTarget, tertiaryTarget, + TERTIARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); } } - caster.swingArm(hand); return true; } + return false; } + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + private void electrocute(World world, Entity caster, Entity origin, Entity target, float damage){ + + if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ + if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted())); + }else{ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage); + } + + if(!world.isRemote){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(caster.posX, caster.getEntityBoundingBox().minY + caster.height / 2, caster.posZ, + target.posX, target.getEntityBoundingBox().minY + target.height / 2, target.posZ); + world.spawnEntity(arc); + }else{ + ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); + } + + target.playSound(WizardrySounds.SPELL_SPARK, 1, 1.5f + 0.4f * world.rand.nextFloat()); + } + } diff --git a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java index 5f648b1c..6f74e00a 100644 --- a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java +++ b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java @@ -1,7 +1,6 @@ package electroblob.wizardry.spell; import electroblob.wizardry.WizardData; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -11,9 +10,10 @@ import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryPathFinder; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.SharedMonsterAttributes; @@ -40,7 +40,7 @@ public class Clairvoyance extends Spell { public static final int PARTICLE_MOVEMENT_INTERVAL = 45; public Clairvoyance(){ - super(Tier.APPRENTICE, 20, Element.SORCERY, "clairvoyance", SpellType.UTILITY, 100, EnumAction.BOW, false); + super("clairvoyance", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 20, 100, EnumAction.BOW, false); } @Override @@ -123,9 +123,11 @@ public class Clairvoyance extends Spell { nextPoint = path.getCurrentPathLength() - path.getCurrentPathIndex() <= 2 ? path.getFinalPathPoint() : path.getPathPointFromIndex(path.getCurrentPathIndex() + 2); - Wizardry.proxy.spawnParticle(Type.PATH, world, point.x + 0.5, point.y + 0.5, point.z + 0.5, - (nextPoint.x - point.x) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.y - point.y) / (float)PARTICLE_MOVEMENT_INTERVAL, - (nextPoint.z - point.z) / (float)PARTICLE_MOVEMENT_INTERVAL, (int)(1800 * durationMultiplier), 0, 1, 0.3f); + ParticleBuilder.create(Type.PATH).pos(point.x + 0.5, point.y + 0.5, point.z + 0.5).vel( + (nextPoint.x - point.x) / (float)PARTICLE_MOVEMENT_INTERVAL, + (nextPoint.y - point.y) / (float)PARTICLE_MOVEMENT_INTERVAL, + (nextPoint.z - point.z) / (float)PARTICLE_MOVEMENT_INTERVAL) + .lifetime((int)(1800 * durationMultiplier)).colour(0, 1, 0.3f).spawn(world); path.incrementPathIndex(); path.incrementPathIndex(); @@ -133,8 +135,8 @@ public class Clairvoyance extends Spell { point = path.getFinalPathPoint(); - Wizardry.proxy.spawnParticle(Type.PATH, world, point.x + 0.5, point.y + 0.5, point.z + 0.5, 0, 0, 0, - (int)(1800 * durationMultiplier), 1, 1, 1); + 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); } @SubscribeEvent diff --git a/src/main/java/electroblob/wizardry/spell/Cobwebs.java b/src/main/java/electroblob/wizardry/spell/Cobwebs.java index 460576ee..1e78ac2d 100644 --- a/src/main/java/electroblob/wizardry/spell/Cobwebs.java +++ b/src/main/java/electroblob/wizardry/spell/Cobwebs.java @@ -7,133 +7,69 @@ import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.tileentity.TileEntityTimer; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class Cobwebs extends Spell { +public class Cobwebs extends SpellRay { - private static final int baseDuration = 400; + private static final int BASE_DURATION = 400; public Cobwebs(){ - super(Tier.ADVANCED, 30, Element.EARTH, "cobwebs", SpellType.ATTACK, 70, EnumAction.NONE, false); + super("cobwebs", Tier.ADVANCED, Element.EARTH, SpellType.ATTACK, 30, 70, false, 12, SoundEvents.BLOCK_LAVA_EXTINGUISH); + this.ignoreEntities(true); } + @Override public boolean doesSpellRequirePacket(){ return false; } + @Override - public boolean doesSpellRequirePacket(){ + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + boolean flag = false; + + pos = pos.offset(side); - RayTraceResult rayTrace = WizardryUtilities.rayTrace(12 * modifiers.get(WizardryItems.range_upgrade), world, - caster, true); + if(world.isAirBlock(pos)){ + if(!world.isRemote){ + world.setBlockState(pos, WizardryBlocks.vanishing_cobweb.getDefaultState()); + if(world.getTileEntity(pos) instanceof TileEntityTimer){ + ((TileEntityTimer)world.getTileEntity(pos)) + .setLifetime((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); + } + } + flag = true; + } - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + for(EnumFacing facing : EnumFacing.values()){ - boolean flag = false; + BlockPos pos1 = pos.offset(facing); - BlockPos pos = rayTrace.getBlockPos().offset(rayTrace.sideHit); - - if(world.isAirBlock(pos)){ + if(world.isAirBlock(pos1)){ if(!world.isRemote){ - world.setBlockState(pos, WizardryBlocks.vanishing_cobweb.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityTimer){ - ((TileEntityTimer)world.getTileEntity(pos)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); + world.setBlockState(pos1, WizardryBlocks.vanishing_cobweb.getDefaultState()); + if(world.getTileEntity(pos1) instanceof TileEntityTimer){ + ((TileEntityTimer)world.getTileEntity(pos1)) + .setLifetime((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); } } flag = true; } - - for(EnumFacing side : EnumFacing.values()){ - - BlockPos pos1 = pos.offset(side); - - if(world.isAirBlock(pos1)){ - if(!world.isRemote){ - world.setBlockState(pos1, WizardryBlocks.vanishing_cobweb.getDefaultState()); - if(world.getTileEntity(pos1) instanceof TileEntityTimer){ - ((TileEntityTimer)world.getTileEntity(pos1)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - } - flag = true; - } - } - - if(flag){ - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_LAVA_EXTINGUISH, 1.0f, 1.0f); - return true; - } } - return false; + + return flag; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - int x = MathHelper.floor(target.posX); - int y = (int)target.getEntityBoundingBox().minY; - int z = MathHelper.floor(target.posZ); - - boolean flag = false; - - BlockPos pos = new BlockPos(x, y, z); - - if(world.isAirBlock(pos)){ - if(!world.isRemote){ - world.setBlockState(pos, WizardryBlocks.vanishing_cobweb.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityTimer){ - ((TileEntityTimer)world.getTileEntity(pos)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - } - flag = true; - } - - for(EnumFacing side : EnumFacing.values()){ - - BlockPos pos1 = pos.offset(side); - - if(world.isAirBlock(pos1)){ - if(!world.isRemote){ - world.setBlockState(pos1, WizardryBlocks.vanishing_cobweb.getDefaultState()); - if(world.getTileEntity(pos1) instanceof TileEntityTimer){ - ((TileEntityTimer)world.getTileEntity(pos1)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - } - flag = true; - } - } - - if(flag){ - caster.swingArm(hand); - caster.playSound(SoundEvents.BLOCK_LAVA_EXTINGUISH, 1.0f, 1.0f); - return true; - } - } + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } - @Override - public boolean canBeCastByNPCs(){ - return true; - } - } diff --git a/src/main/java/electroblob/wizardry/spell/ConjureArmour.java b/src/main/java/electroblob/wizardry/spell/ConjureArmour.java index 7a9f14a1..9ae9ce91 100644 --- a/src/main/java/electroblob/wizardry/spell/ConjureArmour.java +++ b/src/main/java/electroblob/wizardry/spell/ConjureArmour.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -8,31 +7,25 @@ import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; -import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagList; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; -public class ConjureArmour extends Spell { +public class ConjureArmour extends SpellConjuration { public ConjureArmour(){ - super(Tier.ADVANCED, 45, Element.HEALING, "conjure_armour", SpellType.DEFENCE, 50, EnumAction.BOW, false); + super("conjure_armour", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 45, 50, null, WizardrySounds.SPELL_CONJURATION); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - + protected boolean conjureItem(EntityPlayer caster, SpellModifiers modifiers){ + ItemStack armour; boolean flag = false; - // A blank "ench" tag is set to trick the renderer into showing the enchantment effect on the actual armour model. - - // Used this rather than getArmorInventoryList because I need to access the slot itself. + // Used this rather than getArmorInventoryList because I need to access the slot itself for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ if(caster.getItemStackFromSlot(slot).isEmpty() && @@ -40,28 +33,13 @@ public class ConjureArmour extends Spell { armour = new ItemStack(WizardryItems.SPECTRAL_ARMOUR_MAP.get(slot)); IConjuredItem.setDurationMultiplier(armour, modifiers.get(WizardryItems.duration_upgrade)); + // Sets a blank "ench" tag to trick the renderer into showing the enchantment effect on the armour model armour.getTagCompound().setTag("ench", new NBTTagList()); caster.setItemStackToSlot(slot, armour); flag = true; } } - - if(flag){ - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.7f, 0.9f, 1.0f); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); - } - + return flag; } diff --git a/src/main/java/electroblob/wizardry/spell/ConjureBow.java b/src/main/java/electroblob/wizardry/spell/ConjureBow.java deleted file mode 100644 index 488327bd..00000000 --- a/src/main/java/electroblob/wizardry/spell/ConjureBow.java +++ /dev/null @@ -1,60 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.item.IConjuredItem; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class ConjureBow extends Spell { - - public ConjureBow(){ - super(Tier.APPRENTICE, 40, Element.SORCERY, "conjure_bow", SpellType.UTILITY, 50, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - ItemStack bow = new ItemStack(WizardryItems.spectral_bow); - - IConjuredItem.setDurationMultiplier(bow, modifiers.get(WizardryItems.duration_upgrade)); - - if(!WizardryUtilities.doesPlayerHaveItem(caster, WizardryItems.spectral_bow) - && conjureItemInInventory(caster, bow)){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - if(world.isRemote){ - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.7f, 0.9f, 1.0f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); - return true; - } - return false; - } - - // TODO: When spells get superclassed, this method needs to be in the conjuration superclass. - /** Adds the given item to the given player's inventory, placing it in the main hand if the main hand is empty. */ - public static boolean conjureItemInInventory(EntityPlayer caster, ItemStack item){ - if(caster.getHeldItemMainhand().isEmpty()){ - caster.setHeldItem(EnumHand.MAIN_HAND, item); - return true; - }else{ - return caster.inventory.addItemStackToInventory(item); - } - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java b/src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java deleted file mode 100644 index 9e51ef3a..00000000 --- a/src/main/java/electroblob/wizardry/spell/ConjurePickaxe.java +++ /dev/null @@ -1,50 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.item.IConjuredItem; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class ConjurePickaxe extends Spell { - - public ConjurePickaxe(){ - super(Tier.APPRENTICE, 25, Element.SORCERY, "conjure_pickaxe", SpellType.UTILITY, 50, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - ItemStack pickaxe = new ItemStack(WizardryItems.spectral_pickaxe); - - IConjuredItem.setDurationMultiplier(pickaxe, modifiers.get(WizardryItems.duration_upgrade)); - - if(!WizardryUtilities.doesPlayerHaveItem(caster, WizardryItems.spectral_pickaxe) - && ConjureBow.conjureItemInInventory(caster, pickaxe)){ - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.7f, 0.9f, 1.0f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); - return true; - } - return false; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/ConjureSword.java b/src/main/java/electroblob/wizardry/spell/ConjureSword.java deleted file mode 100644 index a9876cfa..00000000 --- a/src/main/java/electroblob/wizardry/spell/ConjureSword.java +++ /dev/null @@ -1,49 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.item.IConjuredItem; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class ConjureSword extends Spell { - - public ConjureSword(){ - super(Tier.APPRENTICE, 25, Element.SORCERY, "conjure_sword", SpellType.UTILITY, 50, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - ItemStack sword = new ItemStack(WizardryItems.spectral_sword); - - IConjuredItem.setDurationMultiplier(sword, modifiers.get(WizardryItems.duration_upgrade)); - - if(!WizardryUtilities.doesPlayerHaveItem(caster, WizardryItems.spectral_sword) - && ConjureBow.conjureItemInInventory(caster, sword)){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - if(world.isRemote){ - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.7f, 0.9f, 1.0f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); - return true; - } - return false; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/CureEffects.java b/src/main/java/electroblob/wizardry/spell/CureEffects.java index 6597a7a6..d0f4a372 100644 --- a/src/main/java/electroblob/wizardry/spell/CureEffects.java +++ b/src/main/java/electroblob/wizardry/spell/CureEffects.java @@ -1,77 +1,28 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; -public class CureEffects extends Spell { +public class CureEffects extends SpellBuff { public CureEffects(){ - super(Tier.APPRENTICE, 25, Element.HEALING, "cure_effects", SpellType.DEFENCE, 40, EnumAction.BOW, false); + super("cure_effects", Tier.APPRENTICE, Element.HEALING, SpellType.DEFENCE, 25, 40, WizardrySounds.SPELL_HEAL, 0.8f, 0.8f, 1); + this.soundValues(0.7f, 1.2f, 0.4f); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); - } - } - + protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ + if(!caster.getActivePotionEffects().isEmpty()){ caster.clearActivePotions(); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); return true; } - // Fixes the sound not playing in first person. - if(world.isRemote) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - + return false; } - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!caster.getActivePotionEffects().isEmpty()){ - caster.clearActivePotions(); - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); - } - } - caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - } diff --git a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java index 8baa67aa..4936395a 100644 --- a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java +++ b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java @@ -1,71 +1,63 @@ package electroblob.wizardry.spell; import electroblob.wizardry.WizardData; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.IElementalDamage; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber -public class CurseOfSoulbinding extends Spell { +public class CurseOfSoulbinding extends SpellRay { public CurseOfSoulbinding(){ - super(Tier.ADVANCED, 35, Element.NECROMANCY, "curse_of_soulbinding", SpellType.ATTACK, 100, EnumAction.NONE, - false); + super("curse_of_soulbinding", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 35, 100, false, 10, SoundEvents.ENTITY_WITHER_SPAWN); + this.soundValues(1, 1.1f, 0.2f); + } + + @Override public boolean canBeCastByNPCs() { return false; } + + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target) && caster instanceof EntityPlayer + && WizardData.get((EntityPlayer)caster) != null){ + // Return false if soulbinding failed (e.g. if the target is already soulbound) + if(!WizardData.get((EntityPlayer)caster).soulbind((EntityLivingBase)target)) return false; + } + + return true; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY - && WizardryUtilities.isLiving(rayTrace.entityHit) && WizardData.get(caster) != null){ - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - if(!WizardData.get(caster).soulbind(target)) return false; - } - - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, - 0.4f, 0.0f, 0.0f); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, - 0.1f, 0.0f, 0.0f); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 1.0f, 0.8f, 1.0f); - } - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.4f, 0, 0).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(1, 0.8f, 1).spawn(world); + } @SubscribeEvent public static void onLivingHurtEvent(LivingHurtEvent event){ diff --git a/src/main/java/electroblob/wizardry/spell/DarknessOrb.java b/src/main/java/electroblob/wizardry/spell/DarknessOrb.java deleted file mode 100644 index df098a99..00000000 --- a/src/main/java/electroblob/wizardry/spell/DarknessOrb.java +++ /dev/null @@ -1,68 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityDarknessOrb; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class DarknessOrb extends Spell { - - public DarknessOrb(){ - super(Tier.ADVANCED, 20, Element.NECROMANCY, "darkness_orb", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityDarknessOrb darknessorb = new EntityDarknessOrb(world, caster, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(darknessorb); - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - caster.swingArm(hand); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityDarknessOrb darknessorb = new EntityDarknessOrb(world, caster, - modifiers.get(SpellModifiers.DAMAGE)); - darknessorb.directTowards(target, 0.5f); - world.spawnEntity(darknessorb); - } - - caster.playSound(SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - caster.swingArm(hand); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Darkvision.java b/src/main/java/electroblob/wizardry/spell/Darkvision.java deleted file mode 100644 index 40b829e8..00000000 --- a/src/main/java/electroblob/wizardry/spell/Darkvision.java +++ /dev/null @@ -1,45 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Darkvision extends Spell { - - public Darkvision(){ - super(Tier.APPRENTICE, 20, Element.EARTH, "darkvision", SpellType.UTILITY, 40, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - caster.addPotionEffect(new PotionEffect(MobEffects.NIGHT_VISION, - (int)(900 * modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.0f, 0.4f, 0.7f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Dart.java b/src/main/java/electroblob/wizardry/spell/Dart.java deleted file mode 100644 index fd74e549..00000000 --- a/src/main/java/electroblob/wizardry/spell/Dart.java +++ /dev/null @@ -1,67 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityDart; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Dart extends Spell { - - public Dart(){ - super(Tier.BASIC, 5, Element.EARTH, "dart", SpellType.ATTACK, 10, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityDart dart = new EntityDart(world, caster, 2 * modifiers.get(WizardryItems.range_upgrade), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(dart); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ARROW_SHOOT, 0.5F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityDart dart = new EntityDart(world, caster, target, 2 * modifiers.get(WizardryItems.range_upgrade), - 2, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(dart); - } - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_ARROW_SHOOT, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Decay.java b/src/main/java/electroblob/wizardry/spell/Decay.java index eca8d586..598a09c6 100644 --- a/src/main/java/electroblob/wizardry/spell/Decay.java +++ b/src/main/java/electroblob/wizardry/spell/Decay.java @@ -7,94 +7,39 @@ import electroblob.wizardry.entity.construct.EntityDecay; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class Decay extends Spell { +public class Decay extends SpellConstructRanged { + + private static final int BASE_SPAWN_COUNT = 5; public Decay(){ - super(Tier.ADVANCED, 50, Element.NECROMANCY, "decay", SpellType.ATTACK, 200, EnumAction.NONE, false); + super("decay", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 50, 200, EntityDecay::new, 400, 12, SoundEvents.ENTITY_WITHER_SHOOT); + this.soundValues(1, 1.1f, 0.1f); + this.floor(true); + this.overlap(true); } @Override - public boolean doesSpellRequirePacket(){ - return false; - } + protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + + if(world.getBlockState(new BlockPos(x, y, z)).isNormalCube()) return false; + + super.spawnConstruct(world, x, y, z, caster, modifiers); + + int quantity = (int)(BASE_SPAWN_COUNT * modifiers.get(WizardryItems.blast_upgrade)); + int horizontalRange = (int)(2 * modifiers.get(WizardryItems.blast_upgrade)); + int verticalRange = (int)(6 * modifiers.get(WizardryItems.blast_upgrade)); - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(12 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = rayTrace.getBlockPos(); - - if(world.getBlockState(pos.up()).isNormalCube()) return false; - - if(!world.isRemote){ - - world.spawnEntity(new EntityDecay(world, pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5, caster)); - - for(int i = 0; i < 5; i++){ - BlockPos pos1 = WizardryUtilities.findNearbyFloorSpace(caster, 2, 6); - if(pos1 == null) break; - world.spawnEntity( - new EntityDecay(world, pos1.getX() + 0.5, pos1.getY(), pos1.getZ() + 0.5, caster)); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - caster.swingArm(hand); - return true; + for(int i=0; i targets = WizardryUtilities.getEntitiesWithinRadius( - 3.0d * modifiers.get(WizardryItems.blast_upgrade), (rayTrace.hitVec.x + 0.5), - (rayTrace.hitVec.y + 0.5), (rayTrace.hitVec.z + 0.5), world); - for(int i = 0; i < targets.size(); i++){ - targets.get(i).attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST), - // Damage decreases with distance but cannot be less than 0, naturally. - Math.max(12.0f - (float)((EntityLivingBase)targets.get(i)).getDistance( - (rayTrace.hitVec.x + 0.5), (rayTrace.hitVec.y + 0.5), - (rayTrace.hitVec.z + 0.5)) * 4, 0) * modifiers.get(SpellModifiers.DAMAGE)); - - } - } - if(world.isRemote){ - double dx = (rayTrace.hitVec.x + 0.5) - caster.posX; - double dy = (rayTrace.hitVec.y + 0.5) - WizardryUtilities.getPlayerEyesPos(caster); - double dz = (rayTrace.hitVec.z + 0.5) - caster.posZ; - world.spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, (rayTrace.hitVec.x + 0.5), - (rayTrace.hitVec.y + 0.5), (rayTrace.hitVec.z + 0.5), 0, 0, 0); - for(int i = 1; i < 5; i++){ - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - } - } - world.playSound(caster, (rayTrace.hitVec.x + 0.5), (rayTrace.hitVec.y + 0.5), - (rayTrace.hitVec.z + 0.5), SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.BLOCKS, 4.0F, - (1.0F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.2F) * 0.7F); - caster.swingArm(hand); - return true; - } + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - if(!world.isRemote){ - List targets = WizardryUtilities.getEntitiesWithinRadius(3.0d, target.posX, - target.posY, target.posZ, world); - for(int i = 0; i < targets.size(); i++){ - targets.get(i).attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST), - // Damage decreases with distance but cannot be less than 0, naturally. - Math.max(12.0f - (float)((EntityLivingBase)targets.get(i)).getDistance(target.posX, - target.posY, target.posZ) * 4, 0) * modifiers.get(SpellModifiers.DAMAGE)); - - } + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(!world.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius( + BASE_RADIUS * modifiers.get(WizardryItems.blast_upgrade), pos.getX(), pos.getY(), pos.getZ(), world); + + for(EntityLivingBase target : targets){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST), + // Damage decreases with distance but cannot be less than 0, naturally. + Math.max(12.0f - (float)target.getDistance(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5) + * 4, 0) * modifiers.get(SpellModifiers.POTENCY)); } - if(world.isRemote){ - double dx = target.posX - caster.posX; - double dy = target.posY - (caster.posY + caster.getEyeHeight()); - double dz = target.posZ - caster.posZ; - world.spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, target.posX, target.posY, target.posZ, 0, 0, 0); - for(int i = 1; i < 5; i++){ - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - caster.posY + caster.getEyeHeight() + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - caster.posY + caster.getEyeHeight() + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - } - } - // Player is null here because the sound was not caused by a player. - world.playSound(null, target.posX, target.posY, target.posZ, SoundEvents.ENTITY_GENERIC_EXPLODE, - SoundCategory.BLOCKS, 4.0F, - (1.0F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.2F) * 0.7F); - caster.swingArm(hand); - return true; + + }else{ + world.spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 0, 0, 0); } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ + return true; } + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0); + } + } diff --git a/src/main/java/electroblob/wizardry/spell/Diamondflesh.java b/src/main/java/electroblob/wizardry/spell/Diamondflesh.java deleted file mode 100644 index 848f4a68..00000000 --- a/src/main/java/electroblob/wizardry/spell/Diamondflesh.java +++ /dev/null @@ -1,53 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Diamondflesh extends Spell { - - public Diamondflesh(){ - super(Tier.MASTER, 100, Element.HEALING, "diamondflesh", SpellType.DEFENCE, 300, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 4, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.0f, 0.5f, 1.0f); - - x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.7f, 0.9f); - - } - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Earthquake.java b/src/main/java/electroblob/wizardry/spell/Earthquake.java index b712f6ac..344b3d52 100644 --- a/src/main/java/electroblob/wizardry/spell/Earthquake.java +++ b/src/main/java/electroblob/wizardry/spell/Earthquake.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.spell; + package electroblob.wizardry.spell; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; @@ -10,54 +10,54 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; -public class Earthquake extends Spell { +public class Earthquake extends SpellConstruct { public Earthquake(){ - super(Tier.MASTER, 75, Element.EARTH, "earthquake", SpellType.ATTACK, 250, EnumAction.NONE, false); + super("earthquake", Tier.MASTER, Element.EARTH, SpellType.ATTACK, 75, 250, EnumAction.NONE, EntityEarthquake::new, -1, WizardrySounds.SPELL_EARTHQUAKE); + this.soundValues(2, 1, 0); + this.overlap(true); + this.floor(true); } - + + // This one spawns particles + @Override public boolean doesSpellRequirePacket(){ return true; } + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + protected void addConstructExtras(EntityEarthquake construct, EntityLivingBase caster, SpellModifiers modifiers){ + construct.lifetime = (int)(20 * modifiers.get(WizardryItems.blast_upgrade)); + } + + @Override + protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + + // TODO: Couldn't this be moved to EntityEarthquake? + if(world.isRemote){ - if(caster.onGround){ + world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX, + caster.getEntityBoundingBox().minY + 0.1, caster.posZ, 0, 0, 0); - if(!world.isRemote){ - world.spawnEntity(new EntityEarthquake(world, caster.posX, caster.getEntityBoundingBox().minY, - caster.posZ, caster, (int)(20 * modifiers.get(WizardryItems.blast_upgrade)), - modifiers.get(SpellModifiers.DAMAGE))); - }else{ + double particleX, particleZ; - world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX, - caster.getEntityBoundingBox().minY + 0.1, caster.posZ, 0, 0, 0); + for(int i=0; i<40; i++){ - double particleX, particleZ; + particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); + particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - for(int i = 0; i < 40; i++){ - - particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); - particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - - IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); - if(block != null){ - world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY, - particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, - Block.getStateId(block)); - } + IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); + if(block != null){ + world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY, + particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, + Block.getStateId(block)); } } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_EARTHQUAKE, 2, 1); - caster.swingArm(hand); - - return true; } - return false; + + return super.spawnConstruct(world, x, y, z, caster, modifiers); } } diff --git a/src/main/java/electroblob/wizardry/spell/Entrapment.java b/src/main/java/electroblob/wizardry/spell/Entrapment.java index db7503a0..2b7f8c30 100644 --- a/src/main/java/electroblob/wizardry/spell/Entrapment.java +++ b/src/main/java/electroblob/wizardry/spell/Entrapment.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -8,112 +7,63 @@ import electroblob.wizardry.entity.construct.EntityBubble; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public class Entrapment extends Spell { +public class Entrapment extends SpellRay { public Entrapment(){ - super(Tier.ADVANCED, 35, Element.NECROMANCY, "entrapment", SpellType.ATTACK, 75, EnumAction.NONE, false); + super("entrapment", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 35, 75, false, 10, SoundEvents.ENTITY_WITHER_SHOOT); + this.soundValues(1, 0.85f, 0.3f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - EntityLivingBase entity = (EntityLivingBase)rayTrace.entityHit; + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + if(!world.isRemote){ - entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), - 1.0f * modifiers.get(SpellModifiers.DAMAGE)); - - EntityBubble entitybubble = new EntityBubble(world, entity.posX, entity.posY, entity.posZ, caster, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), true, - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(entitybubble); - entity.startRiding(entitybubble); + // Deals a small amount damage so the target counts as being hit by the caster + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), 1); + + EntityBubble bubble = new EntityBubble(world); + bubble.setPosition(target.posX, target.posY, target.posZ); + bubble.setCaster(caster); + bubble.lifetime = ((int)(200 * modifiers.get(WizardryItems.duration_upgrade))); + bubble.isDarkOrb = true; + bubble.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + + world.spawnEntity(bubble); + target.startRiding(bubble); } } - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, - 0.1f, 0.0f, 0.0f); - } - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, - world.rand.nextFloat() * 0.3F + 0.7F); + return true; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), - 1.0f * modifiers.get(SpellModifiers.DAMAGE)); - // Deprecated in favour of entity riding method - // entity.addPotionEffect(new PotionEffect(Wizardry.bubblePotion, 200, 0)); - EntityBubble entitybubble = new EntityBubble(world, target.posX, target.posY, target.posZ, caster, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), true, - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(entitybubble); - target.startRiding(entitybubble); - - } - if(world.isRemote){ - - double dx = (target.posX - caster.posX) / caster.getDistance(target); - double dy = (target.posY - caster.posY) / caster.getDistance(target); - double dz = (target.posZ - caster.posZ) / caster.getDistance(target); - - for(int i = 1; i < 25; i += 2){ - - double x1 = caster.posX + dx * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - world.spawnParticle(EnumParticleTypes.PORTAL, x1, y1 - 0.5, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 0, 0.1f, 0.0f, 0.0f); - } - } - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, world.rand.nextFloat() * 0.3F + 0.7F); - return true; - } - + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean canBeCastByNPCs(){ + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + world.spawnParticle(EnumParticleTypes.PORTAL, x, y - 0.5, z, 0, 0, 0); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0, 0).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/FireResistance.java b/src/main/java/electroblob/wizardry/spell/FireResistance.java deleted file mode 100644 index 42596b3b..00000000 --- a/src/main/java/electroblob/wizardry/spell/FireResistance.java +++ /dev/null @@ -1,78 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class FireResistance extends Spell { - - public FireResistance(){ - super(Tier.ADVANCED, 20, Element.FIRE, "fire_resistance", SpellType.DEFENCE, 80, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - caster.addPotionEffect(new PotionEffect(MobEffects.FIRE_RESISTANCE, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 0.5f, 0.0f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - // Like witches, wizards who have this spell will only cast it if they are on fire. - if(caster.isBurning() && !caster.isPotionActive(MobEffects.FIRE_RESISTANCE)){ - - caster.addPotionEffect(new PotionEffect(MobEffects.FIRE_RESISTANCE, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 0.5f, 0.0f); - } - } - caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/FireSigil.java b/src/main/java/electroblob/wizardry/spell/FireSigil.java deleted file mode 100644 index 7d4d0b0f..00000000 --- a/src/main/java/electroblob/wizardry/spell/FireSigil.java +++ /dev/null @@ -1,51 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityFireSigil; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.world.World; - -public class FireSigil extends Spell { - - public FireSigil(){ - super(Tier.APPRENTICE, 10, Element.FIRE, "fire_sigil", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(10 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && rayTrace.sideHit == EnumFacing.UP){ - if(!world.isRemote){ - double x = rayTrace.hitVec.x; - double y = rayTrace.hitVec.y; - double z = rayTrace.hitVec.z; - EntityFireSigil firesigil = new EntityFireSigil(world, x, y, z, caster, - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(firesigil); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ITEM_FLINTANDSTEEL_USE, 1.0F, 1.0F); - return true; - } - return false; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Fireball.java b/src/main/java/electroblob/wizardry/spell/Fireball.java index 83e680b2..08ecb170 100644 --- a/src/main/java/electroblob/wizardry/spell/Fireball.java +++ b/src/main/java/electroblob/wizardry/spell/Fireball.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; public class Fireball extends Spell { public Fireball(){ - super(Tier.APPRENTICE, 10, Element.FIRE, "fireball", SpellType.ATTACK, 15, EnumAction.NONE, false); + super("fireball", Tier.APPRENTICE, Element.FIRE, SpellType.ATTACK, 10, 15, EnumAction.NONE, false); // Does 2.5 hearts of damage and 5 seconds of fire, for reference. } diff --git a/src/main/java/electroblob/wizardry/spell/Firebolt.java b/src/main/java/electroblob/wizardry/spell/Firebolt.java deleted file mode 100644 index f81804b1..00000000 --- a/src/main/java/electroblob/wizardry/spell/Firebolt.java +++ /dev/null @@ -1,69 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityFirebolt; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Firebolt extends Spell { - - public Firebolt(){ - super(Tier.APPRENTICE, 10, Element.FIRE, "firebolt", SpellType.ATTACK, 10, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityFirebolt firebolt = new EntityFirebolt(world, caster, modifiers.get(SpellModifiers.DAMAGE)); - firebolt.motionX *= 2.5; - firebolt.motionY *= 2.5; - firebolt.motionZ *= 2.5; - world.spawnEntity(firebolt); - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - caster.swingArm(hand); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityFirebolt firebolt = new EntityFirebolt(world, caster, modifiers.get(SpellModifiers.DAMAGE)); - firebolt.directTowards(target, 2.5f); - world.spawnEntity(firebolt); - } - - caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - caster.swingArm(hand); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Firebomb.java b/src/main/java/electroblob/wizardry/spell/Firebomb.java deleted file mode 100644 index 6a95a583..00000000 --- a/src/main/java/electroblob/wizardry/spell/Firebomb.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityFirebomb; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Firebomb extends Spell { - - public Firebomb(){ - super(Tier.APPRENTICE, 15, Element.FIRE, "firebomb", SpellType.ATTACK, 25, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityFirebomb firebomb = new EntityFirebomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - world.spawnEntity(firebomb); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityFirebomb firebomb = new EntityFirebomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - firebomb.directTowards(target, 1.5f); - world.spawnEntity(firebomb); - } - - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Fireskin.java b/src/main/java/electroblob/wizardry/spell/Fireskin.java deleted file mode 100644 index 20f4497f..00000000 --- a/src/main/java/electroblob/wizardry/spell/Fireskin.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Fireskin extends Spell { - - public Fireskin(){ - super(Tier.ADVANCED, 40, Element.FIRE, "fireskin", SpellType.DEFENCE, 250, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - // Cannot be cast when it has already been cast - if(!caster.isPotionActive(WizardryPotions.fireskin)){ - if(!world.isRemote){ - caster.addPotionEffect(new PotionEffect(WizardryPotions.fireskin, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - return true; - } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - // Cannot be cast when it has already been cast - if(!caster.isPotionActive(WizardryPotions.fireskin)){ - if(!world.isRemote){ - caster.addPotionEffect(new PotionEffect(WizardryPotions.fireskin, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - } - caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - return true; - } - return false; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Firestorm.java b/src/main/java/electroblob/wizardry/spell/Firestorm.java index baf1d219..55bdd341 100644 --- a/src/main/java/electroblob/wizardry/spell/Firestorm.java +++ b/src/main/java/electroblob/wizardry/spell/Firestorm.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -8,83 +7,103 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class Firestorm extends Spell { +public class Firestorm extends SpellRay { + + private static final float BASE_DAMAGE = 6; + /** The base duration for which entities are set on fire by this spell. */ + private static final int BASE_DURATION = 10; public Firestorm(){ - super(Tier.MASTER, 15, Element.FIRE, "firestorm", SpellType.ATTACK, 0, EnumAction.NONE, true); + super("firestorm", Tier.MASTER, Element.FIRE, SpellType.ATTACK, 15, 0, true, 10, null); + this.particleVelocity(1); + this.particleDither(0.3); + this.particleSpacing(0.25); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + // Temporary solution until I implement a better continuous sound system + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag){ + if(ticksInUse % 16 == 0){ + if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_FIRE, 0.5f, 1.0f); + } + } + return flag; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag){ + if(ticksInUse % 16 == 0){ + if(ticksInUse == 0) caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + caster.playSound(WizardrySounds.SPELL_LOOP_FIRE, 0.5f, 1.0f); + } + } + return flag; + } - Vec3d look = caster.getLookVec(); + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + // Fire can damage armour stands + if(target instanceof EntityLivingBase){ - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - // Fire can damage armour stands. - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - - if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)){ - target.setFire(10); - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), - 6.0f * modifiers.get(SpellModifiers.DAMAGE)); - }else{ + if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ if(!world.isRemote && ticksInUse == 1) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); + }else{ + target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); + WizardryUtilities.attackEntityWithoutKnockback(target, + MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); } - - }else if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = rayTrace.getBlockPos().offset(rayTrace.sideHit); - - if(world.isAirBlock(pos)){ - if(!world.isRemote){ - world.setBlockState(pos, Blocks.FIRE.getDefaultState()); - } - } + + return true; } + + return false; + } - if(world.isRemote){ - for(int i = 0; i < 40; i++){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() * 0.6f - 0.3f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() * 0.4f - 0.2f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() * 0.6f - 0.3f; - Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, - look.x * modifiers.get(WizardryItems.range_upgrade), - look.y * modifiers.get(WizardryItems.range_upgrade), - look.z * modifiers.get(WizardryItems.range_upgrade), 0, 3 + world.rand.nextFloat(), 0, 0); - Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, - look.x * modifiers.get(WizardryItems.range_upgrade), - look.y * modifiers.get(WizardryItems.range_upgrade), - look.z * modifiers.get(WizardryItems.range_upgrade), 0, 3 + world.rand.nextFloat(), 0, 0); - } - } - if(ticksInUse % 16 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_FIRE, 0.5F, 1.0f); + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + pos = pos.offset(side); + + if(world.isAirBlock(pos)){ + if(!world.isRemote) world.setBlockState(pos, Blocks.FIRE.getDefaultState()); + return true; } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).scale(3 + world.rand.nextFloat()).spawn(world); + ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).scale(3 + world.rand.nextFloat()).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/FlameRay.java b/src/main/java/electroblob/wizardry/spell/FlameRay.java index c6d6d47c..71e686fd 100644 --- a/src/main/java/electroblob/wizardry/spell/FlameRay.java +++ b/src/main/java/electroblob/wizardry/spell/FlameRay.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -8,106 +7,71 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class FlameRay extends Spell { +public class FlameRay extends SpellRay { + + private static final float BASE_DAMAGE = 3; + /** The base duration for which entities are set on fire by this spell. */ + private static final int BASE_DURATION = 10; public FlameRay(){ - super(Tier.APPRENTICE, 5, Element.FIRE, "flame_ray", SpellType.ATTACK, 0, EnumAction.NONE, true); + super("flame_ray", Tier.APPRENTICE, Element.FIRE, SpellType.ATTACK, 5, 0, true, 10, null); + this.particleVelocity(1); + this.particleSpacing(0.5); } - + @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - // Fire can damage armour stands - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - - if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)){ - target.setFire(10); - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); - }else{ - if(!world.isRemote && ticksInUse == 1) caster.sendMessage(new TextComponentTranslation("spell.resist", - target.getName(), this.getNameForTranslationFormatted())); + // TODO: Temporary solution until I implement a better continuous sound system + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag){ + if(ticksInUse % 16 == 0){ + if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_FIRE, 0.5f, 1.0f); } } - if(world.isRemote){ - for(int i = 0; i < 20; i++){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, - look.x * modifiers.get(WizardryItems.range_upgrade), - look.y * modifiers.get(WizardryItems.range_upgrade), - look.z * modifiers.get(WizardryItems.range_upgrade), 0); - Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, - look.x * modifiers.get(WizardryItems.range_upgrade), - look.y * modifiers.get(WizardryItems.range_upgrade), - look.z * modifiers.get(WizardryItems.range_upgrade), 0); - } - } - if(ticksInUse % 16 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_FIRE, 0.5F, 1.0f); - } - return true; + return flag; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - Vec3d vec = new Vec3d(target.posX - caster.posX, target.posY - caster.posY, target.posZ - caster.posZ).normalize(); - - target.setFire(10); - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); - - if(world.isRemote){ - for(int i = 0; i < 20; i++){ - double x1 = caster.posX + vec.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.y * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + vec.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, - vec.x * modifiers.get(WizardryItems.range_upgrade), - vec.y * modifiers.get(WizardryItems.range_upgrade), - vec.z * modifiers.get(WizardryItems.range_upgrade), 0); - Wizardry.proxy.spawnParticle(Type.MAGIC_FIRE, world, x1, y1, z1, - vec.x * modifiers.get(WizardryItems.range_upgrade), - vec.y * modifiers.get(WizardryItems.range_upgrade), - vec.z * modifiers.get(WizardryItems.range_upgrade), 0); - } - } - + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag){ if(ticksInUse % 16 == 0){ if(ticksInUse == 0) caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - caster.playSound(WizardrySounds.SPELL_LOOP_FIRE, 0.5F, 1.0f); + caster.playSound(WizardrySounds.SPELL_LOOP_FIRE, 0.5f, 1.0f); + } + } + return flag; + } + + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + // Fire can damage armour stands + if(target instanceof EntityLivingBase){ + + if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ + if(!world.isRemote && ticksInUse == 1) caster.sendMessage(new TextComponentTranslation("spell.resist", + target.getName(), this.getNameForTranslationFormatted())); + }else { + target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); + WizardryUtilities.attackEntityWithoutKnockback(target, + MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); } return true; @@ -117,8 +81,19 @@ public class FlameRay extends Spell { } @Override - public boolean canBeCastByNPCs(){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).spawn(world); + ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/FlamingAxe.java b/src/main/java/electroblob/wizardry/spell/FlamingAxe.java index b320de52..33498792 100644 --- a/src/main/java/electroblob/wizardry/spell/FlamingAxe.java +++ b/src/main/java/electroblob/wizardry/spell/FlamingAxe.java @@ -3,48 +3,28 @@ package electroblob.wizardry.spell; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; -public class FlamingAxe extends Spell { +public class FlamingAxe extends SpellConjuration { public FlamingAxe(){ - super(Tier.ADVANCED, 45, Element.FIRE, "flaming_axe", SpellType.UTILITY, 50, EnumAction.BOW, false); + super("flaming_axe", Tier.ADVANCED, Element.FIRE, SpellType.UTILITY, 45, 50, WizardryItems.flaming_axe, SoundEvents.ENTITY_BLAZE_SHOOT); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - ItemStack flamingaxe = new ItemStack(WizardryItems.flaming_axe); - - IConjuredItem.setDurationMultiplier(flamingaxe, modifiers.get(WizardryItems.duration_upgrade)); - - if(!WizardryUtilities.doesPlayerHaveItem(caster, WizardryItems.flaming_axe) - && ConjureBow.conjureItemInInventory(caster, flamingaxe)){ - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - world.spawnParticle(EnumParticleTypes.FLAME, x1, y1, z1, 0, 0, 0); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - return true; + protected void spawnParticles(World world, EntityLivingBase caster, SpellModifiers modifiers){ + + for(int i=0; i<10; i++){ + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0); } - return false; } } diff --git a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java index b70f491a..f157a8c2 100644 --- a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java @@ -1,7 +1,6 @@ package electroblob.wizardry.spell; import electroblob.wizardry.WizardData; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; @@ -9,8 +8,9 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; @@ -24,7 +24,7 @@ import net.minecraft.world.World; public class FlamingWeapon extends Spell { public FlamingWeapon(){ - super(Tier.ADVANCED, 35, Element.FIRE, "flaming_weapon", SpellType.UTILITY, 70, EnumAction.BOW, false); + super("flaming_weapon", Tier.ADVANCED, Element.FIRE, SpellType.UTILITY, 35, 70, EnumAction.BOW, false); } @Override @@ -41,21 +41,19 @@ public class FlamingWeapon extends Spell { // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. stack.addEnchantment(WizardryEnchantments.flaming_weapon, - modifiers.get(SpellModifiers.DAMAGE) == 1.0f ? 1 - : (int)((modifiers.get(SpellModifiers.DAMAGE) - 1.0f) + modifiers.get(SpellModifiers.POTENCY) == 1.0f ? 1 + : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) / Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); WizardData.get(caster).setImbuementDuration(WizardryEnchantments.flaming_weapon, (int)(900 * modifiers.get(WizardryItems.duration_upgrade))); if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.9f, 0.7f, 1.0f); + for(int i=0; i<10; i++){ + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.9f, 0.7f, 1).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Flight.java b/src/main/java/electroblob/wizardry/spell/Flight.java index 97db2f9c..70183b00 100644 --- a/src/main/java/electroblob/wizardry/spell/Flight.java +++ b/src/main/java/electroblob/wizardry/spell/Flight.java @@ -1,11 +1,11 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; @@ -16,7 +16,7 @@ import net.minecraft.world.World; public class Flight extends Spell { public Flight(){ - super(Tier.MASTER, 10, Element.EARTH, "flight", SpellType.UTILITY, 0, EnumAction.NONE, true); + super("flight", Tier.MASTER, Element.EARTH, SpellType.UTILITY, 10, 0, EnumAction.NONE, true); } @Override @@ -36,19 +36,22 @@ public class Flight extends Spell { } caster.fallDistance = 0.0f; } + if(world.isRemote){ - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX - 1 + world.rand.nextDouble() * 2, - WizardryUtilities.getPlayerEyesPos(caster) - 0.5f + world.rand.nextDouble(), - caster.posZ - 1 + world.rand.nextDouble() * 2, 0, -0.1F, 0, 15, 0.8f, 1.0f, 0.5f); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX - 1 + world.rand.nextDouble() * 2, - WizardryUtilities.getPlayerEyesPos(caster) - 0.5f + world.rand.nextDouble(), - caster.posZ - 1 + world.rand.nextDouble() * 2, 0, -0.1F, 0, 15, 1.0f, 1.0f, 1.0f); + double x = caster.posX - 1 + world.rand.nextDouble() * 2; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ - 1 + world.rand.nextDouble() * 2; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).lifetime(15).colour(0.8f, 1, 0.5f).spawn(world); + x = caster.posX - 1 + world.rand.nextDouble() * 2; + y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + z = caster.posZ - 1 + world.rand.nextDouble() * 2; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).lifetime(15).colour(1, 1, 1).spawn(world); } + if(ticksInUse % 24 == 0){ WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERDRAGON_FLAP, 0.5F, 1.0f); } + return true; } diff --git a/src/main/java/electroblob/wizardry/spell/FontOfMana.java b/src/main/java/electroblob/wizardry/spell/FontOfMana.java index 3915ae6d..df6f46af 100644 --- a/src/main/java/electroblob/wizardry/spell/FontOfMana.java +++ b/src/main/java/electroblob/wizardry/spell/FontOfMana.java @@ -2,15 +2,15 @@ package electroblob.wizardry.spell; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -21,7 +21,7 @@ import net.minecraft.world.World; public class FontOfMana extends Spell { public FontOfMana(){ - super(Tier.MASTER, 100, Element.HEALING, "font_of_mana", SpellType.UTILITY, 250, EnumAction.BOW, false); + super("font_of_mana", Tier.MASTER, Element.HEALING, SpellType.UTILITY, 100, 250, EnumAction.BOW, false); } @Override @@ -37,19 +37,23 @@ public class FontOfMana extends Spell { // calculating this. target.addPotionEffect(new PotionEffect(WizardryPotions.font_of_mana, (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE) > 1 ? 1 : 0)); + modifiers.get(SpellModifiers.POTENCY) > 1 ? 1 : 0)); } } if(world.isRemote){ for(int i = 0; i < 100 * modifiers.get(WizardryItems.blast_upgrade); i++){ + double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); double angle = world.rand.nextDouble() * Math.PI * 2; float hue = world.rand.nextFloat() * 0.4f; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX + radius * Math.cos(angle), caster.getEntityBoundingBox().minY, - caster.posZ + radius * Math.sin(angle), 0, 0.03, 0, 50, 1, 1 - hue, 0.6f + hue); - + + double x = caster.posX + radius * Math.cos(angle); + double y = caster.getEntityBoundingBox().minY; + double z = caster.posZ + radius * Math.sin(angle); + + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).lifetime(50) + .colour(1, 1 - hue, 0.6f + hue).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/FontOfVitality.java b/src/main/java/electroblob/wizardry/spell/FontOfVitality.java deleted file mode 100644 index 88f4cec7..00000000 --- a/src/main/java/electroblob/wizardry/spell/FontOfVitality.java +++ /dev/null @@ -1,57 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class FontOfVitality extends Spell { - - public FontOfVitality(){ - super(Tier.MASTER, 75, Element.HEALING, "font_of_vitality", SpellType.DEFENCE, 300, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - caster.addPotionEffect(new PotionEffect(MobEffects.ABSORPTION, - (int)(1200 * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); - caster.addPotionEffect(new PotionEffect(MobEffects.REGENERATION, - (int)(300 * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 0.6f, 0.7f); - - x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 0.8f, 0.3f); - - } - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/ForceArrow.java b/src/main/java/electroblob/wizardry/spell/ForceArrow.java deleted file mode 100644 index f052b43f..00000000 --- a/src/main/java/electroblob/wizardry/spell/ForceArrow.java +++ /dev/null @@ -1,69 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityForceArrow; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class ForceArrow extends Spell { - - public ForceArrow(){ - super(Tier.APPRENTICE, 15, Element.SORCERY, "force_arrow", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityForceArrow forceArrow = new EntityForceArrow(world, caster, - 1 * modifiers.get(WizardryItems.range_upgrade), modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(forceArrow); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_FORCE, 1.0f, - 1.2f + world.rand.nextFloat() * 0.2f); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityForceArrow forceArrow = new EntityForceArrow(world, caster, target, - 1 * modifiers.get(WizardryItems.range_upgrade), 2, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(forceArrow); - } - - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_FORCE, 1.0f, 1.2f + world.rand.nextFloat() * 0.2f); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/ForceOrb.java b/src/main/java/electroblob/wizardry/spell/ForceOrb.java deleted file mode 100644 index 5db4e5fa..00000000 --- a/src/main/java/electroblob/wizardry/spell/ForceOrb.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityForceOrb; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class ForceOrb extends Spell { - - public ForceOrb(){ - super(Tier.ADVANCED, 20, Element.SORCERY, "force_orb", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityForceOrb forceOrb = new EntityForceOrb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - world.spawnEntity(forceOrb); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityForceOrb forceOrb = new EntityForceOrb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - forceOrb.directTowards(target, 1.5f); - world.spawnEntity(forceOrb); - } - - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Forcefield.java b/src/main/java/electroblob/wizardry/spell/Forcefield.java deleted file mode 100644 index eea373b9..00000000 --- a/src/main/java/electroblob/wizardry/spell/Forcefield.java +++ /dev/null @@ -1,73 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityForcefield; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Forcefield extends Spell { - - public Forcefield(){ - super(Tier.ADVANCED, 45, Element.HEALING, "forcefield", SpellType.DEFENCE, 200, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(caster.onGround){ - if(!world.isRemote){ - EntityForcefield forcefield = new EntityForcefield(world, caster.posX, caster.posY, caster.posZ, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(forcefield); - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION_LARGE, 1.0f, 1.0f); - return true; - } - - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - // Wizards can no longer cast forcefield when they are inside one - if(caster.onGround - && world.getEntitiesWithinAABB(EntityForcefield.class, caster.getEntityBoundingBox()).isEmpty()){ - if(!world.isRemote){ - EntityForcefield forcefield = new EntityForcefield(world, caster.posX, caster.posY, caster.posZ, - caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(forcefield); - } - caster.playSound(WizardrySounds.SPELL_CONJURATION_LARGE, 1.0f, 1.0f); - return true; - } - - return false; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java index 44b7a30e..e08bd145 100644 --- a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java +++ b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java @@ -1,76 +1,62 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; import net.minecraft.world.World; -public class ForestsCurse extends Spell { +public class ForestsCurse extends SpellAreaEffect { + + private static final int BASE_DAMAGE = 4; + private static final int BASE_DURATION = 140; public ForestsCurse(){ - super(Tier.MASTER, 75, Element.EARTH, "forests_curse", SpellType.ATTACK, 200, EnumAction.BOW, false); + super("forests_curse", Tier.MASTER, Element.EARTH, SpellType.ATTACK, 75, 200, EnumAction.BOW, 5, SoundEvents.ENTITY_WITHER_SPAWN); + this.soundValues(1, 1.1f, 0.2f); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - List targets = WizardryUtilities.getEntitiesWithinRadius( - 5.0d * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); - - for(EntityLivingBase target : targets){ - if(WizardryUtilities.isValidTarget(caster, target) - && !MagicDamage.isEntityImmune(DamageType.POISON, target)){ - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), - 4.0f * modifiers.get(SpellModifiers.DAMAGE)); - target.addPotionEffect(new PotionEffect(MobEffects.POISON, - (int)(140 * modifiers.get(WizardryItems.duration_upgrade)), 2)); - target.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, - (int)(140 * modifiers.get(WizardryItems.duration_upgrade)), 2)); - target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, - (int)(140 * modifiers.get(WizardryItems.duration_upgrade)), 2)); - } + protected void affectEntity(World world, EntityLivingBase caster, EntityLivingBase target, SpellModifiers modifiers){ + + if(!MagicDamage.isEntityImmune(DamageType.POISON, target) && WizardryUtilities.isLiving(target)){ + + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + + int duration = (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)); + + target.addPotionEffect(new PotionEffect(MobEffects.POISON, duration, 2)); + target.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, duration, 2)); + target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, duration, 2)); } - - if(world.isRemote){ - for(int i = 0; i < 50 * modifiers.get(WizardryItems.blast_upgrade); i++){ - double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); - double angle = world.rand.nextDouble() * Math.PI * 2; - float brightness = world.rand.nextFloat() / 4; - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, - caster.posX + radius * Math.cos(angle), WizardryUtilities.getPlayerEyesPos(caster) + 0.5, - caster.posZ + radius * Math.sin(angle), 0, -0.2, 0, 0, 0.05f + brightness, 0.2f + brightness, - 0.0f); - brightness = world.rand.nextFloat() / 4; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX + radius * Math.cos(angle), WizardryUtilities.getPlayerEyesPos(caster) + 0.5, - caster.posZ + radius * Math.sin(angle), 0, -0.05, 0, 50, 0.1f + brightness, 0.2f + brightness, - 0.0f); - Wizardry.proxy.spawnParticle(Type.LEAF, world, caster.posX + radius * Math.cos(angle), - WizardryUtilities.getPlayerEyesPos(caster) + 0.5, caster.posZ + radius * Math.sin(angle), 0, - -0.01, 0, 40 + world.rand.nextInt(12)); - - } - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z){ + + y += 2; // Moves the particles up to the caster's head level + + float brightness = world.rand.nextFloat() / 4; + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).vel(0, -0.2, 0) + .colour(0.05f + brightness, 0.2f + brightness, 0).spawn(world); + + brightness = world.rand.nextFloat() / 4; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.05, 0).lifetime(50) + .colour(0.1f + brightness, 0.2f + brightness, 0).spawn(world); + + ParticleBuilder.create(Type.LEAF).pos(x, y, z).vel(0, -0.01, 0).lifetime(40 + world.rand.nextInt(12)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Freeze.java b/src/main/java/electroblob/wizardry/spell/Freeze.java index 2f9a2790..48f19bb0 100644 --- a/src/main/java/electroblob/wizardry/spell/Freeze.java +++ b/src/main/java/electroblob/wizardry/spell/Freeze.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -10,189 +9,87 @@ import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntityBlaze; import net.minecraft.entity.monster.EntityMagmaCube; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; -import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class Freeze extends Spell { +public class Freeze extends SpellRay { + + /** The base duration of the frostbite effect appled by this spell. */ + private static final int BASE_DURATION = 200; + /** The base damage dealt to entities vulnerable to frost. */ + private static final float BASE_DAMAGE = 3; public Freeze(){ - super(Tier.BASIC, 5, Element.ICE, "freeze", SpellType.ATTACK, 10, EnumAction.NONE, false); + super("freeze", Tier.BASIC, Element.ICE, SpellType.ATTACK, 5, 10, false, 10, WizardrySounds.SPELL_ICE); + this.soundValues(1, 1.4f, 0.4f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ - // Entity ray trace is done first because block ray trace passes through entities; if it was the other - // way round, entities would only be hit when there were no blocks in range behind them. - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - - if(target instanceof EntityBlaze || target instanceof EntityMagmaCube - || target instanceof EntityBlazeMinion){ + if(target instanceof EntityBlaze || target instanceof EntityMagmaCube || target instanceof EntityBlazeMinion){ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); } if(MagicDamage.isEntityImmune(DamageType.FROST, target)){ if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); }else{ - target.addPotionEffect(new PotionEffect(WizardryPotions.frost, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), 1)); + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1)); } - if(target.isBurning()){ - target.extinguish(); - } - - if(world.isRemote){ - double dx = target.posX - caster.posX; - double dy = (target.getEntityBoundingBox().minY + target.height / 2) - - WizardryUtilities.getPlayerEyesPos(caster); - double dz = target.posZ - caster.posZ; - for(int i = 1; i < 5; i++){ - float brightness = 0.5f + (world.rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); - Wizardry.proxy.spawnParticle(Type.SNOW, world, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, -0.02, 0, - 40 + world.rand.nextInt(10)); - } - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.4F + 1.2F); + if(target.isBurning()) target.extinguish(); + return true; - - }else{ - rayTrace = WizardryUtilities.rayTrace(10 * modifiers.get(WizardryItems.range_upgrade), world, caster, true); - // Gets block the player is looking at and sets to ice or covers with snow as necessary - // Note how the block is set on the server side only (kinda obvious really) but the particles are - // spawned on the client side only. - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = rayTrace.getBlockPos(); - - if(world.getBlockState(pos).getBlock() == Blocks.WATER && !world.isRemote){ - world.setBlockState(pos, Blocks.ICE.getDefaultState()); - }else if(world.getBlockState(pos).getBlock() == Blocks.LAVA && !world.isRemote){ - world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState()); - }else if(world.getBlockState(pos).getBlock() == Blocks.FLOWING_LAVA && !world.isRemote){ - world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); - }else if(rayTrace.sideHit == EnumFacing.UP && !world.isRemote && world.isSideSolid(pos, EnumFacing.UP) - && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ - world.setBlockState(pos.up(), Blocks.SNOW_LAYER.getDefaultState()); - } - - if(world.isRemote){ - - double dx = pos.getX() + 0.5 - caster.posX; - double dy = pos.getY() + 0.5 - WizardryUtilities.getPlayerEyesPos(caster); - double dz = pos.getZ() + 0.5 - caster.posZ; - - for(int i = 1; i < 5; i++){ - float brightness = 0.5f + (world.rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) - + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0.0d, 0.0d, 0.0d, - 20 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) - + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0, - 20 + world.rand.nextInt(8), 1.0f, 1.0f, 1.0f); - } - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.4F + 1.2F); - return true; - } } - return false; + + return false; // If the spell hit a non-living entity } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(target instanceof EntityBlaze || target instanceof EntityMagmaCube - || target instanceof EntityBlazeMinion){ - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); - } - - if(!world.isRemote && !MagicDamage.isEntityImmune(DamageType.FROST, target)){ - target.addPotionEffect(new PotionEffect(WizardryPotions.frost, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), 1)); - } - - if(target.isBurning()){ - target.extinguish(); - } - - if(world.isRemote){ - double dx = target.posX - caster.posX; - double dy = (target.getEntityBoundingBox().minY + target.height / 2) - - (caster.posY + caster.getEyeHeight()); - double dz = target.posZ - caster.posZ; - for(int i = 1; i < 5; i++){ - float brightness = 0.5f + (world.rand.nextFloat() / 2); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - caster.posY + caster.getEyeHeight() + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); - Wizardry.proxy.spawnParticle(Type.SNOW, world, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - caster.posY + caster.getEyeHeight() + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, -0.02, 0, - 40 + world.rand.nextInt(10)); - } - } - - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); - return true; + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(world.getBlockState(pos).getBlock() == Blocks.WATER && !world.isRemote){ + world.setBlockState(pos, Blocks.ICE.getDefaultState()); + }else if(world.getBlockState(pos).getBlock() == Blocks.LAVA && !world.isRemote){ + world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState()); + }else if(world.getBlockState(pos).getBlock() == Blocks.FLOWING_LAVA && !world.isRemote){ + world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); + }else if(side == EnumFacing.UP && !world.isRemote && world.isSideSolid(pos, EnumFacing.UP) + && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + world.setBlockState(pos.up(), Blocks.SNOW_LAYER.getDefaultState()); } - - return false; + + return true; // Always succeeds if it hits a block } @Override - public boolean canBeCastByNPCs(){ - return true; + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + float brightness = 0.5f + (world.rand.nextFloat() / 2); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)) + .colour(brightness, brightness + 0.1f, 1).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java index 765d8df6..e2792eb9 100644 --- a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java @@ -1,7 +1,6 @@ package electroblob.wizardry.spell; import electroblob.wizardry.WizardData; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; @@ -9,8 +8,9 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; @@ -30,7 +30,7 @@ public class FreezingWeapon extends Spell { public static final String FREEZING_ARROW_NBT_KEY = "frostLevel"; public FreezingWeapon(){ - super(Tier.ADVANCED, 35, Element.ICE, "freezing_weapon", SpellType.UTILITY, 70, EnumAction.BOW, false); + super("freezing_weapon", Tier.ADVANCED, Element.ICE, SpellType.UTILITY, 35, 70, EnumAction.BOW, false); } @Override @@ -47,25 +47,23 @@ public class FreezingWeapon extends Spell { // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. stack.addEnchantment(WizardryEnchantments.freezing_weapon, - modifiers.get(SpellModifiers.DAMAGE) == 1.0f ? 1 - : (int)((modifiers.get(SpellModifiers.DAMAGE) - 1.0f) + modifiers.get(SpellModifiers.POTENCY) == 1.0f ? 1 + : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) / Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); WizardData.get(caster).setImbuementDuration(WizardryEnchantments.freezing_weapon, (int)(900 * modifiers.get(WizardryItems.duration_upgrade))); if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.9f, 0.7f, 1.0f); + for(int i=0; i<10; i++){ + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.9f, 0.7f, 1).spawn(world); } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/FrostAxe.java b/src/main/java/electroblob/wizardry/spell/FrostAxe.java index 0daffc81..e9b15a57 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostAxe.java +++ b/src/main/java/electroblob/wizardry/spell/FrostAxe.java @@ -1,52 +1,31 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; -public class FrostAxe extends Spell { +public class FrostAxe extends SpellConjuration { public FrostAxe(){ - super(Tier.ADVANCED, 45, Element.ICE, "frost_axe", SpellType.UTILITY, 50, EnumAction.BOW, false); + super("frost_axe", Tier.ADVANCED, Element.ICE, SpellType.UTILITY, 45, 50, WizardryItems.frost_axe, WizardrySounds.SPELL_ICE); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - ItemStack frostaxe = new ItemStack(WizardryItems.frost_axe); - - IConjuredItem.setDurationMultiplier(frostaxe, modifiers.get(WizardryItems.duration_upgrade)); - - if(!WizardryUtilities.doesPlayerHaveItem(caster, WizardryItems.frost_axe) - && ConjureBow.conjureItemInInventory(caster, frostaxe)){ - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SNOW, world, x1, y1, z1, 0, -0.02d, 0, - 40 + world.rand.nextInt(10)); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0f, 1.0f); - return true; + protected void spawnParticles(World world, EntityLivingBase caster, SpellModifiers modifiers){ + + for(int i=0; i<10; i++){ + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SNOW).pos(x, y, z).spawn(world); } - return false; } } diff --git a/src/main/java/electroblob/wizardry/spell/FrostRay.java b/src/main/java/electroblob/wizardry/spell/FrostRay.java index 4f560b6e..1a360880 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostRay.java +++ b/src/main/java/electroblob/wizardry/spell/FrostRay.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -9,154 +8,105 @@ import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntityBlaze; import net.minecraft.entity.monster.EntityMagmaCube; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class FrostRay extends Spell { +public class FrostRay extends SpellRay { + + private static final float BASE_DAMAGE = 3; + /** The base duration of the forstbite effect applied by this spell. */ + private static final int BASE_DURATION = 200; public FrostRay(){ - super(Tier.APPRENTICE, 5, Element.ICE, "frost_ray", SpellType.ATTACK, 0, EnumAction.NONE, true); + super("frost_ray", Tier.APPRENTICE, Element.ICE, SpellType.ATTACK, 5, 0, true, 10, null); + this.particleVelocity(1); + this.particleSpacing(0.5); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + // TODO: Temporary solution until I implement a better continuous sound system + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag){ + if(ticksInUse % 12 == 0){ + if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5f, 1); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_ICE, 0.5f, 1); + } + } + return flag; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - - if(target.isBurning()){ - target.extinguish(); + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag){ + if(ticksInUse % 12 == 0){ + if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_ICE, 0.5f, 1); + caster.playSound(WizardrySounds.SPELL_LOOP_ICE, 0.5f, 1); } + } + return flag; + } + + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + if(target.isBurning()) target.extinguish(); if(MagicDamage.isEntityImmune(DamageType.FROST, target)){ if(!world.isRemote && ticksInUse == 1) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); }else{ - // For frost ray the entity can move slightly, unlike freeze. - target.addPotionEffect(new PotionEffect(WizardryPotions.frost, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), 0)); + // For frost ray the entity can move slightly, unlike freeze + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); - float baseDamage = target instanceof EntityBlaze || target instanceof EntityMagmaCube ? 6.0f : 3.0f; - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), - baseDamage * modifiers.get(SpellModifiers.DAMAGE)); + float damage = BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY); + if(target instanceof EntityBlaze || target instanceof EntityMagmaCube) damage *= 2; + + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, + DamageType.FROST), damage); } - } - - if(world.isRemote){ - for(int i = 0; i < 20; i++){ - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, - look.x * modifiers.get(WizardryItems.range_upgrade), - look.y * modifiers.get(WizardryItems.range_upgrade), - look.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, - 0.6f, 1.0f); - - x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, - look.x * modifiers.get(WizardryItems.range_upgrade), - look.y * modifiers.get(WizardryItems.range_upgrade), - look.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, - 1.0f, 1.0f); - } - } - - if(ticksInUse % 12 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5F, 1.0f); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_ICE, 0.5F, 1.0f); - } - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - Vec3d vec = new Vec3d(target.posX - caster.posX, target.posY - caster.posY, target.posZ - caster.posZ) - .normalize(); - - if(target.isBurning()){ - target.extinguish(); - } - - if(!MagicDamage.isEntityImmune(DamageType.FROST, target)){ - // For frost ray the entity can move slightly, unlike freeze. - target.addPotionEffect(new PotionEffect(WizardryPotions.frost, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - - float baseDamage = target instanceof EntityBlaze || target instanceof EntityMagmaCube ? 6.0f : 3.0f; - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), - baseDamage * modifiers.get(SpellModifiers.DAMAGE)); - - } - - if(world.isRemote){ - for(int i = 0; i < 20; i++){ - double x1 = caster.posX + vec.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + vec.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, - vec.x * modifiers.get(WizardryItems.range_upgrade), - vec.y * modifiers.get(WizardryItems.range_upgrade), - vec.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, - 0.6f, 1.0f); - - x1 = caster.posX + vec.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.y * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - z1 = caster.posZ + vec.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, - vec.x * modifiers.get(WizardryItems.range_upgrade), - vec.y * modifiers.get(WizardryItems.range_upgrade), - vec.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, - 1.0f, 1.0f); - } - } - - if(ticksInUse % 12 == 0){ - if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_ICE, 0.5F, 1.0f); - caster.playSound(WizardrySounds.SPELL_LOOP_ICE, 0.5F, 1.0f); - } - + return true; } - + return false; } @Override - public boolean canBeCastByNPCs(){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + float brightness = world.rand.nextFloat(); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)) + .colour(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/FrostSigil.java b/src/main/java/electroblob/wizardry/spell/FrostSigil.java deleted file mode 100644 index 5e2ec592..00000000 --- a/src/main/java/electroblob/wizardry/spell/FrostSigil.java +++ /dev/null @@ -1,51 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityFrostSigil; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.world.World; - -public class FrostSigil extends Spell { - - public FrostSigil(){ - super(Tier.APPRENTICE, 10, Element.ICE, "frost_sigil", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(10 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && rayTrace.sideHit == EnumFacing.UP){ - if(!world.isRemote){ - double x = rayTrace.hitVec.x; - double y = rayTrace.hitVec.y; - double z = rayTrace.hitVec.z; - EntityFrostSigil frostsigil = new EntityFrostSigil(world, x, y, z, caster, - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(frostsigil); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - return true; - } - return false; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Glide.java b/src/main/java/electroblob/wizardry/spell/Glide.java index 9878e3ac..0db03cca 100644 --- a/src/main/java/electroblob/wizardry/spell/Glide.java +++ b/src/main/java/electroblob/wizardry/spell/Glide.java @@ -1,11 +1,11 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; @@ -16,7 +16,7 @@ import net.minecraft.world.World; public class Glide extends Spell { public Glide(){ - super(Tier.ADVANCED, 5, Element.EARTH, "glide", SpellType.UTILITY, 0, EnumAction.NONE, true); + super("glide", Tier.ADVANCED, Element.EARTH, SpellType.UTILITY, 5, 0, EnumAction.NONE, true); } @Override @@ -32,19 +32,20 @@ public class Glide extends Spell { } if(world.isRemote){ - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX - 0.25d + world.rand.nextDouble() / 2, - WizardryUtilities.getPlayerEyesPos(caster) - 1.5f + world.rand.nextDouble(), - caster.posZ - 0.25d + world.rand.nextDouble() / 2, 0, -0.1F, 0, 15, 1.0f, 1.0f, 1.0f); - Wizardry.proxy.spawnParticle(Type.LEAF, world, - caster.posX - 0.25d + world.rand.nextDouble() / 2, - WizardryUtilities.getPlayerEyesPos(caster) - 1.5f + world.rand.nextDouble(), - caster.posZ - 0.25d + world.rand.nextDouble() / 2, 0, -0.03, 0, 20); + double x = caster.posX - 0.25 + world.rand.nextDouble() / 2; + double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble(); + double z = caster.posZ - 0.25 + world.rand.nextDouble() / 2; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).lifetime(15).colour(1, 1, 1).spawn(world); + x = caster.posX - 0.25 + world.rand.nextDouble() / 2; + y = caster.getEntityBoundingBox().minY + world.rand.nextDouble(); + z = caster.posZ - 0.25 + world.rand.nextDouble() / 2; + ParticleBuilder.create(Type.LEAF).pos(x, y, z).lifetime(20).spawn(world); } if(ticksInUse % 24 == 0){ WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ITEM_ELYTRA_FLYING, 0.5F, 1.0f); } + return true; } diff --git a/src/main/java/electroblob/wizardry/spell/GreaterFireball.java b/src/main/java/electroblob/wizardry/spell/GreaterFireball.java index d1d83f98..84db6989 100644 --- a/src/main/java/electroblob/wizardry/spell/GreaterFireball.java +++ b/src/main/java/electroblob/wizardry/spell/GreaterFireball.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; public class GreaterFireball extends Spell { public GreaterFireball(){ - super(Tier.ADVANCED, 20, Element.FIRE, "greater_fireball", SpellType.ATTACK, 30, EnumAction.NONE, false); + super("greater_fireball", Tier.ADVANCED, Element.FIRE, SpellType.ATTACK, 20, 30, EnumAction.NONE, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/GreaterHeal.java b/src/main/java/electroblob/wizardry/spell/GreaterHeal.java index 1173dc11..52452809 100644 --- a/src/main/java/electroblob/wizardry/spell/GreaterHeal.java +++ b/src/main/java/electroblob/wizardry/spell/GreaterHeal.java @@ -1,68 +1,28 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; -public class GreaterHeal extends Spell { +public class GreaterHeal extends SpellBuff { public GreaterHeal(){ - super(Tier.ADVANCED, 15, Element.HEALING, "greater_heal", SpellType.DEFENCE, 40, EnumAction.BOW, false); + super("greater_heal", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 15, 40, WizardrySounds.SPELL_HEAL, 1, 1, 0.3f); + this.soundValues(0.7f, 1.2f, 0.4f); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(caster.shouldHeal()){ - caster.heal((int)(8 * modifiers.get(SpellModifiers.DAMAGE))); - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double dx = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double dy = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double dz = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); + protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ + + if(caster.getHealth() < caster.getMaxHealth() && caster.getHealth() > 0){ + caster.heal(8 * modifiers.get(SpellModifiers.POTENCY)); return true; } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(caster.getHealth() < caster.getMaxHealth()){ - caster.heal((int)(8 * modifiers.get(SpellModifiers.DAMAGE))); - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double dx = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double dy = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); - double dz = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); - } - } - caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - return false; + + return false; } } diff --git a/src/main/java/electroblob/wizardry/spell/GroupHeal.java b/src/main/java/electroblob/wizardry/spell/GroupHeal.java index fe25fbff..58030155 100644 --- a/src/main/java/electroblob/wizardry/spell/GroupHeal.java +++ b/src/main/java/electroblob/wizardry/spell/GroupHeal.java @@ -9,8 +9,9 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -21,7 +22,7 @@ import net.minecraft.world.World; public class GroupHeal extends Spell { public GroupHeal(){ - super(Tier.ADVANCED, 35, Element.HEALING, "group_heal", SpellType.DEFENCE, 150, EnumAction.BOW, false); + super("group_heal", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 35, 150, EnumAction.BOW, false); } @Override @@ -40,17 +41,18 @@ public class GroupHeal extends Spell { if(((EntityPlayer)target).shouldHeal()){ - target.heal((int)(6 * modifiers.get(SpellModifiers.DAMAGE))); + target.heal(6 * modifiers.get(SpellModifiers.POTENCY)); if(world.isRemote){ + for(int i = 0; i < 10; i++){ - double d0 = (double)((float)target.posX + world.rand.nextFloat() * 2 - 1.0F); - double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos((EntityPlayer)target) - - 0.5F + world.rand.nextFloat()); - double d2 = (double)((float)target.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, - 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(1, 1, 0.3f).spawn(world); } + + Wizardry.proxy.spawnEntityParticle(world, caster, 15, 1, 1, 0.3f); } WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, @@ -59,7 +61,7 @@ public class GroupHeal extends Spell { } } - // Now also works on summoned creatures + // Now also works on summoned creatures }else if(target instanceof ISummonedCreature){ EntityLivingBase summoner = ((ISummonedCreature)target).getCaster(); @@ -67,19 +69,19 @@ public class GroupHeal extends Spell { if(summoner == caster || (summoner instanceof EntityPlayer && WizardryUtilities.isPlayerAlly(caster, (EntityPlayer)summoner))){ - if(target.getHealth() < target.getMaxHealth()){ + if(target.getHealth() < target.getMaxHealth() && target.getHealth() > 0){ - target.heal((int)(6 * modifiers.get(SpellModifiers.DAMAGE))); + target.heal(6 * modifiers.get(SpellModifiers.POTENCY)); if(world.isRemote){ for(int i = 0; i < 10; i++){ - double d0 = (double)((float)target.posX + world.rand.nextFloat() * 2 - 1.0F); - double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos((EntityPlayer)target) - - 0.5F + world.rand.nextFloat()); - double d2 = (double)((float)target.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, - 0, 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(1, 1, 0.3f).spawn(world); } + + Wizardry.proxy.spawnEntityParticle(world, caster, 15, 1, 1, 0.3f); } WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, diff --git a/src/main/java/electroblob/wizardry/spell/GrowthAura.java b/src/main/java/electroblob/wizardry/spell/GrowthAura.java index 390c6603..c873ba80 100644 --- a/src/main/java/electroblob/wizardry/spell/GrowthAura.java +++ b/src/main/java/electroblob/wizardry/spell/GrowthAura.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; public class GrowthAura extends Spell { public GrowthAura(){ - super(Tier.APPRENTICE, 20, Element.EARTH, "growth_aura", SpellType.UTILITY, 50, EnumAction.NONE, false); + super("growth_aura", Tier.APPRENTICE, Element.EARTH, SpellType.UTILITY, 20, 50, EnumAction.NONE, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Hailstorm.java b/src/main/java/electroblob/wizardry/spell/Hailstorm.java index 481848ca..b054517e 100644 --- a/src/main/java/electroblob/wizardry/spell/Hailstorm.java +++ b/src/main/java/electroblob/wizardry/spell/Hailstorm.java @@ -4,58 +4,38 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityHailstorm; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; -public class Hailstorm extends Spell { +public class Hailstorm extends SpellConstructRanged { public Hailstorm(){ - super(Tier.MASTER, 75, Element.ICE, "hailstorm", SpellType.ATTACK, 300, EnumAction.NONE, false); + super("hailstorm", Tier.MASTER, Element.ICE, SpellType.ATTACK, 75, 300, EntityHailstorm::new, 120, 20, WizardrySounds.SPELL_ICE); + this.floor(true); } @Override - public boolean doesSpellRequirePacket(){ - return false; + protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + + // Moves the entity back towards the caster a bit, so the area of effect is better centred on the position. + // 3 is the distance to move the entity back towards the caster. + double dx = caster.posX - x; + double dz = caster.posZ - z; + double distRatio = 3 / Math.sqrt(dx * dx + dz * dz); + x += dx * distRatio; + z += dz * distRatio; + // Moves the entity up 5 blocks so that it is above mobs' heads. + y += 5; + + return super.spawnConstruct(world, x, y, z, caster, modifiers); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(20 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - if(!world.isRemote){ - double x = rayTrace.hitVec.x; - double y = rayTrace.hitVec.y; - double z = rayTrace.hitVec.z; - // Moves the entity back towards the caster a bit, so the area of effect is better centred on the - // position. - // 3.0d is the distance to move the entity back towards the caster. - double dx = caster.posX - x; - double dz = caster.posZ - z; - double distRatio = 3.0d / Math.sqrt(dx * dx + dz * dz); - x += dx * distRatio; - z += dz * distRatio; - - EntityHailstorm hailstorm = new EntityHailstorm(world, x, y + 5, z, caster, - (int)(120 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - hailstorm.rotationYaw = caster.rotationYawHead; - world.spawnEntity(hailstorm); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - return true; - } - return false; + protected void addConstructExtras(EntityHailstorm construct, EntityLivingBase caster, SpellModifiers modifiers){ + // Makes the arrows shoot in the direction the caster was looking when they cast the spell. + construct.rotationYaw = caster.rotationYawHead; } } diff --git a/src/main/java/electroblob/wizardry/spell/Heal.java b/src/main/java/electroblob/wizardry/spell/Heal.java index 3b9977f4..46055d50 100644 --- a/src/main/java/electroblob/wizardry/spell/Heal.java +++ b/src/main/java/electroblob/wizardry/spell/Heal.java @@ -1,72 +1,27 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; -public class Heal extends Spell { +public class Heal extends SpellBuff { public Heal(){ - super(Tier.BASIC, 5, Element.HEALING, "heal", SpellType.DEFENCE, 20, EnumAction.BOW, false); + super("heal", Tier.BASIC, Element.HEALING, SpellType.DEFENCE, 5, 20, WizardrySounds.SPELL_HEAL, 1, 1, 0.3f); + this.soundValues(0.7f, 1.2f, 0.4f); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(caster.shouldHeal()){ - - caster.heal((int)(4 * modifiers.get(SpellModifiers.DAMAGE))); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double d0 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - // Apparently the client side spawns the particles 1 block higher than it should... hence the -0.5F. - double d1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double d2 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); - } - Wizardry.proxy.spawnEntityParticle(world, caster, 15, 1.0f, 1.0f, 0.3f); - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); + protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ + + if(caster.getHealth() < caster.getMaxHealth() && caster.getHealth() > 0){ + caster.heal(4 * modifiers.get(SpellModifiers.POTENCY)); return true; } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(caster.getHealth() < caster.getMaxHealth()){ - caster.heal((int)(4 * modifiers.get(SpellModifiers.DAMAGE))); - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double dx = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double dy = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); - double dz = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, dx, dy, dz, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); - } - } - caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - + return false; } diff --git a/src/main/java/electroblob/wizardry/spell/HealAlly.java b/src/main/java/electroblob/wizardry/spell/HealAlly.java index d8f3edc4..f6ccdb65 100644 --- a/src/main/java/electroblob/wizardry/spell/HealAlly.java +++ b/src/main/java/electroblob/wizardry/spell/HealAlly.java @@ -4,53 +4,63 @@ import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public class HealAlly extends Spell { +public class HealAlly extends SpellRay { public HealAlly(){ - super(Tier.APPRENTICE, 10, Element.HEALING, "heal_ally", SpellType.DEFENCE, 20, EnumAction.NONE, false); + super("heal_ally", Tier.APPRENTICE, Element.HEALING, SpellType.DEFENCE, 10, 20, false, 10, WizardrySounds.SPELL_HEAL); + this.soundValues(0.7f, 1.2f, 0.4f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade), 8.0f); - - if(rayTrace != null && rayTrace.entityHit != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - if(target.getHealth() < target.getMaxHealth()){ - target.heal((int)(5 * modifiers.get(SpellModifiers.DAMAGE))); + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + EntityLivingBase entity = (EntityLivingBase)target; + + if(entity.getHealth() < entity.getMaxHealth() && entity.getHealth() > 0){ + + entity.heal((int)(5 * modifiers.get(SpellModifiers.POTENCY))); if(world.isRemote){ + + float r = 1; float g = 1; float b = 0.3f; + for(int i = 0; i < 10; i++){ - double d0 = (double)((float)target.posX + world.rand.nextFloat() * 2 - 1.0F); - // Apparently the client side spawns the particles 1 block higher than it should... hence the - - // 0.5F. - double d1 = (double)((float)target.getEntityBoundingBox().minY + target.height - 0.5f - + world.rand.nextFloat()); - double d2 = (double)((float)target.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, d0, d1, d2, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 1.0f, 0.3f); + double x1 = (double)((float)entity.posX + world.rand.nextFloat() * 2 - 1.0f); + double y1 = (double)((float)entity.getEntityBoundingBox().minY + entity.getEyeHeight() - 0.5f + world.rand.nextFloat()); + double z1 = (double)((float)entity.posZ + world.rand.nextFloat() * 2 - 1.0f); + ParticleBuilder.create(Type.SPARKLE).pos(x1, y1, z1).vel(0, 0.1F, 0).colour(r, g, b).spawn(world); } + + Wizardry.proxy.spawnEntityParticle(world, entity, 15, r, g, b); } - - caster.swingArm(hand); - target.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); - return true; } + + return true; } + + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/HealingAura.java b/src/main/java/electroblob/wizardry/spell/HealingAura.java deleted file mode 100644 index d3a9844e..00000000 --- a/src/main/java/electroblob/wizardry/spell/HealingAura.java +++ /dev/null @@ -1,68 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityHealAura; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class HealingAura extends Spell { - - public HealingAura(){ - super(Tier.ADVANCED, 35, Element.HEALING, "healing_aura", SpellType.DEFENCE, 150, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(caster.onGround){ - if(!world.isRemote){ - EntityHealAura healaura = new EntityHealAura(world, caster.posX, caster.posY, caster.posZ, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(healaura); - } - return true; - } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - if(caster.onGround - && world.getEntitiesWithinAABB(EntityHealAura.class, caster.getEntityBoundingBox()).isEmpty()){ - if(!world.isRemote){ - EntityHealAura healaura = new EntityHealAura(world, caster.posX, caster.posY, caster.posZ, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(healaura); - } - return true; - } - return false; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/HomingSpark.java b/src/main/java/electroblob/wizardry/spell/HomingSpark.java deleted file mode 100644 index 074658e2..00000000 --- a/src/main/java/electroblob/wizardry/spell/HomingSpark.java +++ /dev/null @@ -1,65 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntitySpark; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class HomingSpark extends Spell { - - public HomingSpark(){ - super(Tier.APPRENTICE, 10, Element.LIGHTNING, "homing_spark", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntitySpark spark = new EntitySpark(world, caster, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(spark); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - } - caster.swingArm(hand); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntitySpark spark = new EntitySpark(world, caster, modifiers.get(SpellModifiers.DAMAGE)); - spark.directTowards(target, 0.5f); - world.spawnEntity(spark); - caster.playSound(WizardrySounds.SPELL_CONJURATION, 1.0F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - } - caster.swingArm(hand); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/IceAge.java b/src/main/java/electroblob/wizardry/spell/IceAge.java index 6c72c2b9..1f21e3cc 100644 --- a/src/main/java/electroblob/wizardry/spell/IceAge.java +++ b/src/main/java/electroblob/wizardry/spell/IceAge.java @@ -28,7 +28,7 @@ public class IceAge extends Spell { private static final int baseDuration = 1200; public IceAge(){ - super(Tier.MASTER, 70, Element.ICE, "ice_age", SpellType.ATTACK, 250, EnumAction.BOW, false); + super("ice_age", Tier.MASTER, Element.ICE, SpellType.ATTACK, 70, 250, EnumAction.BOW, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/IceCharge.java b/src/main/java/electroblob/wizardry/spell/IceCharge.java deleted file mode 100644 index 231d78b7..00000000 --- a/src/main/java/electroblob/wizardry/spell/IceCharge.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityIceCharge; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class IceCharge extends Spell { - - public IceCharge(){ - super(Tier.ADVANCED, 20, Element.ICE, "ice_charge", SpellType.ATTACK, 30, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityIceCharge icecharge = new EntityIceCharge(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - world.spawnEntity(icecharge); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.4F + 1.4F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityIceCharge icecharge = new EntityIceCharge(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - icecharge.directTowards(target, 1.5f); - world.spawnEntity(icecharge); - } - - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/IceLance.java b/src/main/java/electroblob/wizardry/spell/IceLance.java deleted file mode 100644 index 88c36745..00000000 --- a/src/main/java/electroblob/wizardry/spell/IceLance.java +++ /dev/null @@ -1,67 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityIceLance; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class IceLance extends Spell { - - public IceLance(){ - super(Tier.ADVANCED, 20, Element.ICE, "ice_lance", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityIceLance iceLance = new EntityIceLance(world, caster, 2 * modifiers.get(WizardryItems.range_upgrade), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(iceLance); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.4F + 0.8F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityIceLance iceLance = new EntityIceLance(world, caster, target, - 2 * modifiers.get(WizardryItems.range_upgrade), 4, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(iceLance); - } - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/IceShard.java b/src/main/java/electroblob/wizardry/spell/IceShard.java deleted file mode 100644 index 79c4f1b7..00000000 --- a/src/main/java/electroblob/wizardry/spell/IceShard.java +++ /dev/null @@ -1,67 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityIceShard; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class IceShard extends Spell { - - public IceShard(){ - super(Tier.APPRENTICE, 10, Element.ICE, "ice_shard", SpellType.ATTACK, 10, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityIceShard iceShard = new EntityIceShard(world, caster, 2 * modifiers.get(WizardryItems.range_upgrade), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(iceShard); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.4F + 1.4F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityIceShard iceShard = new EntityIceShard(world, caster, target, - 2 * modifiers.get(WizardryItems.range_upgrade), 4, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(iceShard); - } - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/IceShroud.java b/src/main/java/electroblob/wizardry/spell/IceShroud.java deleted file mode 100644 index 88a933d9..00000000 --- a/src/main/java/electroblob/wizardry/spell/IceShroud.java +++ /dev/null @@ -1,71 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class IceShroud extends Spell { - - public IceShroud(){ - super(Tier.ADVANCED, 40, Element.ICE, "ice_shroud", SpellType.DEFENCE, 250, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - // Cannot be cast when it has already been cast - if(!caster.isPotionActive(WizardryPotions.ice_shroud)){ - if(!world.isRemote){ - caster.addPotionEffect(new PotionEffect(WizardryPotions.ice_shroud, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.4F + 1.4F); - return true; - } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - // Cannot be cast when it has already been cast - if(!caster.isPotionActive(WizardryPotions.ice_shroud)){ - if(!world.isRemote){ - caster.addPotionEffect(new PotionEffect(WizardryPotions.ice_shroud, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - } - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); - return true; - } - return false; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/IceSpikes.java b/src/main/java/electroblob/wizardry/spell/IceSpikes.java index c00590b2..7a07adc7 100644 --- a/src/main/java/electroblob/wizardry/spell/IceSpikes.java +++ b/src/main/java/electroblob/wizardry/spell/IceSpikes.java @@ -8,107 +8,52 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class IceSpikes extends Spell { +public class IceSpikes extends SpellConstructRanged { + + private static final int BASE_SPAWN_COUNT = 17; // Was 18, reduced to 17 to account for the extra one in the middle. public IceSpikes(){ - super(Tier.ADVANCED, 30, Element.ICE, "ice_spikes", SpellType.ATTACK, 75, EnumAction.NONE, false); + // Base duration is set to -1 so that the superclass doesn't waste time retrieving the duration multiplier + super("ice_spikes", Tier.ADVANCED, Element.ICE, SpellType.ATTACK, 30, 75, EntityIceSpike::new, -1, 20, WizardrySounds.SPELL_ICE); } - + @Override - public boolean doesSpellRequirePacket(){ - return false; - } + protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + + if(world.getBlockState(new BlockPos(x, y, z)).isNormalCube()) return false; + + // Now always spawns a spike exactly at the position aimed at + super.spawnConstruct(world, x, y-1, z, caster, modifiers); + + int quantity = (int)(BASE_SPAWN_COUNT * modifiers.get(WizardryItems.blast_upgrade)); - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + for(int i=0; i -1){ - EntityIceSpike icespike = new EntityIceSpike(world, x1, y1, z1, caster, - 30 + world.rand.nextInt(15), modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(icespike); - } - } + if(y1 > -1){ + super.spawnConstruct(world, x1, y1, z1, caster, modifiers); } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - return true; } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - - double x = target.posX; - double y = target.posY; - double z = target.posZ; - - for(int i = 0; i < (int)(18 * modifiers.get(WizardryItems.blast_upgrade)); i++){ - - float angle = (float)(world.rand.nextFloat() * Math.PI * 2); - double radius = 0.5 + world.rand.nextDouble() * 2 * modifiers.get(WizardryItems.blast_upgrade); - - double x1 = x + radius * MathHelper.sin(angle); - double z1 = z + radius * MathHelper.cos(angle); - double y1 = WizardryUtilities.getNearestFloorLevel(world, - new BlockPos(MathHelper.floor(x1), (int)y, MathHelper.floor(z1)), 2) - 1; - - if(y1 > -1){ - EntityIceSpike icespike = new EntityIceSpike(world, x1, y1, z1, caster, - 30 + world.rand.nextInt(15), modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(icespike); - } - } - } - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ + return true; } + + @Override + protected void addConstructExtras(EntityIceSpike construct, EntityLivingBase caster, SpellModifiers modifiers){ + // In this particular case, lifetime is implemented as a delay instead so is treated differently. + construct.lifetime = 30 + construct.world.rand.nextInt(15); + } } diff --git a/src/main/java/electroblob/wizardry/spell/IceStatue.java b/src/main/java/electroblob/wizardry/spell/IceStatue.java index c32cfc6d..2132ef16 100644 --- a/src/main/java/electroblob/wizardry/spell/IceStatue.java +++ b/src/main/java/electroblob/wizardry/spell/IceStatue.java @@ -1,131 +1,63 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.tileentity.TileEntityStatue; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.monster.EntityBlaze; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -public class IceStatue extends Spell { +public class IceStatue extends SpellRay { - private static final int baseDuration = 400; + private static final int BASE_DURATION = 400; public IceStatue(){ - super(Tier.APPRENTICE, 15, Element.ICE, "ice_statue", SpellType.ATTACK, 40, EnumAction.NONE, false); + super("ice_statue", Tier.APPRENTICE, Element.ICE, SpellType.ATTACK, 15, 40, false, 10, WizardrySounds.SPELL_ICE); + this.soundValues(1, 1.4f, 0.4f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY - && rayTrace.entityHit instanceof EntityLiving && !world.isRemote){ - - EntityLiving target = (EntityLiving)rayTrace.entityHit; - - BlockPos pos = new BlockPos(target); - - if(target.isBurning()){ - target.extinguish(); - } - - // Stops the entity looking red while frozen and the resulting z-fighting - target.hurtTime = 0; - - if(target instanceof EntityBlaze) WizardryAdvancementTriggers.freeze_blaze.triggerFor(caster); - - // Short mobs such as spiders and pigs - if((target.height < 1.2 || target.isChild()) && WizardryUtilities.canBlockBeReplaced(world, pos)){ - world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 1); - ((TileEntityStatue)world.getTileEntity(pos)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - target.setDead(); - target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); - } - // Normal sized mobs like zombies and skeletons - else if(target.height < 2.5 && WizardryUtilities.canBlockBeReplaced(world, pos) - && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ - world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 2); - ((TileEntityStatue)world.getTileEntity(pos)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - - world.setBlockState(pos.up(), WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 2); - } - target.setDead(); - target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); - } - // Tall mobs like endermen and iron golems - else if(WizardryUtilities.canBlockBeReplaced(world, pos) - && WizardryUtilities.canBlockBeReplaced(world, pos.up()) - && WizardryUtilities.canBlockBeReplaced(world, pos.up(2))){ - world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 3); - ((TileEntityStatue)world.getTileEntity(pos)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - - world.setBlockState(pos.up(), WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 3); - } - - world.setBlockState(pos.up(2), WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(target, 3, 3); - } - target.setDead(); + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(target instanceof EntityLiving && !world.isRemote){ + // Unchecked cast is fine because the block is a static final field + if(((BlockStatue)WizardryBlocks.ice_statue).convertToStatue((EntityLiving)target, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)))){ + target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + return true; } } - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - float brightness = 0.5f + (world.rand.nextFloat() / 2); + + return false; + } - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), brightness, brightness + 0.1f, 1.0f); - Wizardry.proxy.spawnParticle(Type.SNOW, world, x1, y1, z1, 0.0d, -0.02d, 0.0d, - 20 + world.rand.nextInt(10)); - - } - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.4F + 1.2F); + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + float brightness = 0.5f + world.rand.nextFloat() * 0.5f; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)) + .colour(brightness, brightness + 0.1f, 1.0f).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).lifetime(20 + world.rand.nextInt(10)).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/Ignite.java b/src/main/java/electroblob/wizardry/spell/Ignite.java index bb5f8705..145607f3 100644 --- a/src/main/java/electroblob/wizardry/spell/Ignite.java +++ b/src/main/java/electroblob/wizardry/spell/Ignite.java @@ -7,168 +7,69 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class Ignite extends Spell { +public class Ignite extends SpellRay { + /** The base duration for which entities are set on fire by this spell. */ + private static final int BASE_DURATION = 10; + public Ignite(){ - super(Tier.BASIC, 5, Element.FIRE, "ignite", SpellType.ATTACK, 10, EnumAction.NONE, false); + super("ignite", Tier.BASIC, Element.FIRE, SpellType.ATTACK, 5, 10, false, 10, SoundEvents.ITEM_FLINTANDSTEEL_USE); + this.soundValues(1, 1, 0.4f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - // Entity ray trace is done first because block ray trace passes through entities; if it was the other - // way round, entities would only be hit when there were no blocks in range behind them. - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - // Fire can damage armour stands - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && rayTrace.entityHit instanceof EntityLivingBase){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + // Fire can damage armour stands, so this includes them + if(target instanceof EntityLivingBase) { + if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); }else{ - target.setFire((int)(10 * modifiers.get(WizardryItems.duration_upgrade))); + target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); } - - if(world.isRemote){ - double dx = target.posX - caster.posX; - double dy = (target.getEntityBoundingBox().minY + target.height / 2) - - WizardryUtilities.getPlayerEyesPos(caster); - double dz = target.posZ - caster.posZ; - // i starts at 1 so that particles are not spawned in the player's head. - for(int i = 1; i < 5; i++){ - // WizardryUtilities.spawnParticleAndNotify(world, EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) - // + world.rand.nextFloat()/5, caster.posY + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + - // (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 0, 0, 0, 0); - // WizardryUtilities.spawnParticleAndNotify(world, EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) - // + world.rand.nextFloat()/5, caster.posY + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + - // (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 0, 0, 0, 0); - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - } - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ITEM_FLINTANDSTEEL_USE, 1.0F, - world.rand.nextFloat() * 0.4F + 0.8F); - + return true; - - }else{ - - rayTrace = WizardryUtilities.rayTrace(10 * modifiers.get(WizardryItems.range_upgrade), world, caster, - false); - - // Gets block the player is looking at and sets the appropriate surrounding air block to fire. - // Note how the block is set on the server side only (kinda obvious really) but the particles are - // spawned on the client side only. - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = rayTrace.getBlockPos().offset(rayTrace.sideHit); - - if(world.isAirBlock(pos)){ - if(!world.isRemote){ - world.setBlockState(pos, Blocks.FIRE.getDefaultState()); - } - - if(world.isRemote){ - - double dx = pos.getX() + 0.5 - caster.posX; - double dy = pos.getY() + 0.5 - WizardryUtilities.getPlayerEyesPos(caster); - double dz = pos.getZ() + 0.5 - caster.posZ; - - for(int i = 1; i < 5; i++){ - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) - + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) - + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - } - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ITEM_FLINTANDSTEEL_USE, 1.0F, - world.rand.nextFloat() * 0.4F + 0.8F); - return true; - } - } } + return false; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)) - target.setFire((int)(10 * modifiers.get(WizardryItems.duration_upgrade))); - - if(world.isRemote){ - double dx = target.posX - caster.posX; - double dy = (target.getEntityBoundingBox().minY + target.height / 2) - - (caster.posY + caster.getEyeHeight()); - double dz = target.posZ - caster.posZ; - // i starts at 1 so that particles are not spawned in the player's head. - for(int i = 1; i < 5; i++){ - // WizardryUtilities.spawnParticleAndNotify(world, EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) - // + world.rand.nextFloat()/5, caster.posY + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + - // (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 0, 0, 0, 0); - // WizardryUtilities.spawnParticleAndNotify(world, EnumParticleTypes.FLAME, caster.posX + (i*(dx/5)) - // + world.rand.nextFloat()/5, caster.posY + (i*(dy/5)) + world.rand.nextFloat()/5, caster.posZ + - // (i*(dz/5)) + world.rand.nextFloat()/5, 0, 0, 0, 0, 0, 0, 0); - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - caster.posY + caster.getEyeHeight() + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - world.spawnParticle(EnumParticleTypes.FLAME, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - caster.posY + caster.getEyeHeight() + (i * (dy / 5)) + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, 0, 0); - } + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + pos = pos.offset(side); + + if(world.isAirBlock(pos)){ + + if(!world.isRemote){ + world.setBlockState(pos, Blocks.FIRE.getDefaultState()); } - - caster.swingArm(hand); - caster.playSound(SoundEvents.ITEM_FLINTANDSTEEL_USE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); - + return true; } - + return false; } @Override - public boolean canBeCastByNPCs(){ - return true; + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0); } } diff --git a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java index 66f7ea82..caf3f92e 100644 --- a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java @@ -1,7 +1,6 @@ package electroblob.wizardry.spell; import electroblob.wizardry.WizardData; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; @@ -9,8 +8,9 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; @@ -24,7 +24,7 @@ import net.minecraft.world.World; public class ImbueWeapon extends Spell { public ImbueWeapon(){ - super(Tier.APPRENTICE, 20, Element.SORCERY, "imbue_weapon", SpellType.UTILITY, 50, EnumAction.BOW, false); + super("imbue_weapon", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 20, 50, EnumAction.BOW, false); } @Override @@ -40,9 +40,9 @@ public class ImbueWeapon extends Spell { && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.magic_sword) <= 0){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. - stack.addEnchantment(WizardryEnchantments.magic_sword, modifiers.get(SpellModifiers.DAMAGE) == 1.0f + stack.addEnchantment(WizardryEnchantments.magic_sword, modifiers.get(SpellModifiers.POTENCY) == 1.0f ? 1 - : (int)((modifiers.get(SpellModifiers.DAMAGE) - 1.0f) / Constants.DAMAGE_INCREASE_PER_TIER + : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) / Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); WizardData.get(caster).setImbuementDuration(WizardryEnchantments.magic_sword, (int)(900 * modifiers.get(WizardryItems.duration_upgrade))); @@ -52,9 +52,9 @@ public class ImbueWeapon extends Spell { && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.magic_bow) <= 0){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. - stack.addEnchantment(WizardryEnchantments.magic_bow, modifiers.get(SpellModifiers.DAMAGE) == 1.0f + stack.addEnchantment(WizardryEnchantments.magic_bow, modifiers.get(SpellModifiers.POTENCY) == 1.0f ? 1 - : (int)((modifiers.get(SpellModifiers.DAMAGE) - 1.0f) / Constants.DAMAGE_INCREASE_PER_TIER + : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) / Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); WizardData.get(caster).setImbuementDuration(WizardryEnchantments.magic_bow, (int)(900 * modifiers.get(WizardryItems.duration_upgrade))); @@ -64,17 +64,15 @@ public class ImbueWeapon extends Spell { } if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.9f, 0.7f, 1.0f); + for(int i=0; i<10; i++){ + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.9f, 0.7f, 1).spawn(world); } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1); return true; } } diff --git a/src/main/java/electroblob/wizardry/spell/Intimidate.java b/src/main/java/electroblob/wizardry/spell/Intimidate.java index 5cbabdff..2d8f6aa4 100644 --- a/src/main/java/electroblob/wizardry/spell/Intimidate.java +++ b/src/main/java/electroblob/wizardry/spell/Intimidate.java @@ -2,14 +2,14 @@ package electroblob.wizardry.spell; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityCreature; @@ -34,9 +34,12 @@ public class Intimidate extends Spell { /** The NBT tag name for storing the feared entity's UUID in the target's tag compound. */ public static final String NBT_KEY = "fearedEntity"; + + private static final double BASE_RANGE = 8; + private static final int BASE_DURATION = 600; public Intimidate(){ - super(Tier.APPRENTICE, 20, Element.NECROMANCY, "intimidate", SpellType.ATTACK, 100, EnumAction.BOW, false); + super("intimidate", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 20, 100, EnumAction.BOW, false); } @Override @@ -45,8 +48,8 @@ public class Intimidate extends Spell { if(!world.isRemote){ List entities = WizardryUtilities.getEntitiesWithinRadius( - 8 * modifiers.get(WizardryItems.range_upgrade), caster.posX, caster.posY, caster.posZ, world, - EntityCreature.class); + BASE_RANGE * modifiers.get(WizardryItems.range_upgrade), caster.posX, caster.posY, caster.posZ, + world, EntityCreature.class); for(EntityCreature target : entities){ @@ -56,16 +59,16 @@ public class Intimidate extends Spell { if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); ((EntityLiving)target).addPotionEffect(new PotionEffect(WizardryPotions.fear, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); } }else{ for(int i = 0; i < 30; i++){ - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, - caster.posX - 1 + world.rand.nextDouble() * 2, - caster.getEntityBoundingBox().minY + 1.5 + world.rand.nextDouble() * 0.5, - caster.posZ - 1 + world.rand.nextDouble() * 2, 0, 0, 0, 0, 0.9f, 0.1f, 0.0f); + double x = caster.posX - 1 + world.rand.nextDouble() * 2; + double y = caster.getEntityBoundingBox().minY + 1.5 + world.rand.nextDouble() * 0.5; + double z = caster.posZ - 1 + world.rand.nextDouble() * 2; + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.9f, 0.1f, 0).spawn(world); } } WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERDRAGON_GROWL, 1.0f, 1.0f); diff --git a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java index a8ede484..859a5a90 100644 --- a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java +++ b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java @@ -2,14 +2,14 @@ package electroblob.wizardry.spell; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -19,40 +19,46 @@ import net.minecraft.util.EnumHand; import net.minecraft.world.World; public class InvigoratingPresence extends Spell { + + private static final double BASE_RANGE = 5; + private static final int BASE_DURATION = 900; public InvigoratingPresence(){ - super(Tier.APPRENTICE, 30, Element.HEALING, "invigorating_presence", SpellType.UTILITY, 60, EnumAction.BOW, - false); + super("invigorating_presence", Tier.APPRENTICE, Element.HEALING, SpellType.UTILITY, 30, 60, EnumAction.BOW, false); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ List targets = WizardryUtilities.getEntitiesWithinRadius( - 5 * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world, + BASE_RANGE * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class); for(EntityPlayer target : targets){ if(WizardryUtilities.isPlayerAlly(caster, target) || target == caster){ // Strength 2 for 45 seconds. target.addPotionEffect(new PotionEffect(MobEffects.STRENGTH, - (int)(900 * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); } } if(world.isRemote){ + for(int i = 0; i < 50 * modifiers.get(WizardryItems.blast_upgrade); i++){ + double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); double angle = world.rand.nextDouble() * Math.PI * 2; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX + radius * Math.cos(angle), caster.getEntityBoundingBox().minY, - caster.posZ + radius * Math.sin(angle), 0, 0.03, 0, 50, 1, 0.2f, 0.2f); + + double x = caster.posX + radius * Math.cos(angle); + double y = caster.getEntityBoundingBox().minY; + double z = caster.posZ + radius * Math.sin(angle); + + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).lifetime(50).colour(1, 0.2f, 0.2f).spawn(world); } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1 + 0.2f * world.rand.nextFloat()); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Invisibility.java b/src/main/java/electroblob/wizardry/spell/Invisibility.java deleted file mode 100644 index 0fe1caba..00000000 --- a/src/main/java/electroblob/wizardry/spell/Invisibility.java +++ /dev/null @@ -1,78 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Invisibility extends Spell { - - public Invisibility(){ - super(Tier.ADVANCED, 35, Element.SORCERY, "invisibility", SpellType.UTILITY, 200, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - caster.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.7f, 1.0f, 1.0f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!caster.isPotionActive(MobEffects.INVISIBILITY)){ - - caster.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.7f, 1.0f, 1.0f); - } - } - caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); - return true; - - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java index 9046e787..e2773b79 100644 --- a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java +++ b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java @@ -2,12 +2,12 @@ package electroblob.wizardry.spell; import java.util.Random; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; @@ -19,7 +19,7 @@ import net.minecraft.world.World; public class InvokeWeather extends Spell { public InvokeWeather(){ - super(Tier.ADVANCED, 30, Element.LIGHTNING, "invoke_weather", SpellType.UTILITY, 100, EnumAction.BOW, false); + super("invoke_weather", Tier.ADVANCED, Element.LIGHTNING, SpellType.UTILITY, 30, 100, EnumAction.BOW, false); } @Override @@ -28,8 +28,9 @@ public class InvokeWeather extends Spell { if(caster.dimension == 0){ if(!world.isRemote){ - // TODO: Backport these changes. + int standardWeatherTime = (300 + (new Random()).nextInt(600)) * 20; + if(world.isRaining()){ caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".sun")); world.getWorldInfo().setCleanWeatherTime(standardWeatherTime); @@ -50,18 +51,17 @@ public class InvokeWeather extends Spell { if(world.isRemote){ for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.5f, 0.7f, 1.0f); + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.5f, 0.7f, 1).spawn(world); } } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_LIGHTNING_THUNDER, 0.5F, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_LIGHTNING_THUNDER, 0.5f, 1.0f); return true; } + return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Ironflesh.java b/src/main/java/electroblob/wizardry/spell/Ironflesh.java deleted file mode 100644 index 7828b4d0..00000000 --- a/src/main/java/electroblob/wizardry/spell/Ironflesh.java +++ /dev/null @@ -1,79 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Ironflesh extends Spell { - - public Ironflesh(){ - super(Tier.ADVANCED, 30, Element.HEALING, "ironflesh", SpellType.DEFENCE, 100, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 2, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.4f, 0.5f, 0.6f); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!caster.isPotionActive(MobEffects.RESISTANCE)){ - - caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 2, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.4f, 0.5f, 0.6f); - } - } - - caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Leap.java b/src/main/java/electroblob/wizardry/spell/Leap.java index dc426c65..2bb1263b 100644 --- a/src/main/java/electroblob/wizardry/spell/Leap.java +++ b/src/main/java/electroblob/wizardry/spell/Leap.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; public class Leap extends Spell { public Leap(){ - super(Tier.BASIC, 10, Element.EARTH, "leap", SpellType.UTILITY, 20, EnumAction.NONE, false); + super("leap", Tier.BASIC, Element.EARTH, SpellType.UTILITY, 10, 20, EnumAction.NONE, false); } @Override @@ -23,7 +23,7 @@ public class Leap extends Spell { if(caster.onGround){ - caster.motionY = 0.65 * modifiers.get(SpellModifiers.DAMAGE); + caster.motionY = 0.65 * modifiers.get(SpellModifiers.POTENCY); caster.addVelocity(caster.getLookVec().x * 0.3, 0, caster.getLookVec().z * 0.3); if(world.isRemote){ diff --git a/src/main/java/electroblob/wizardry/spell/Levitation.java b/src/main/java/electroblob/wizardry/spell/Levitation.java index 1879e9bc..34779ce6 100644 --- a/src/main/java/electroblob/wizardry/spell/Levitation.java +++ b/src/main/java/electroblob/wizardry/spell/Levitation.java @@ -5,9 +5,9 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; @@ -16,7 +16,7 @@ import net.minecraft.world.World; public class Levitation extends Spell { public Levitation(){ - super(Tier.ADVANCED, 10, Element.SORCERY, "levitation", SpellType.UTILITY, 0, EnumAction.BOW, true); + super("levitation", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 10, 0, EnumAction.BOW, true); } @Override @@ -24,16 +24,16 @@ public class Levitation extends Spell { caster.fallDistance = 0; - caster.motionY = caster.motionY < 0.5d ? caster.motionY + 0.1d : caster.motionY; + caster.motionY = caster.motionY < 0.5 ? caster.motionY + 0.1 : caster.motionY; if(world.isRemote){ - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX - 0.25d + world.rand.nextDouble() / 2, - WizardryUtilities.getPlayerEyesPos(caster) - 1.5f, - caster.posZ - 0.25d + world.rand.nextDouble() / 2, 0, -0.1F, 0, 15, 0.5f, 1.0f, 0.7f); + double x = caster.posX - 0.25 + world.rand.nextDouble() * 0.5; + double y = caster.getEntityBoundingBox().minY; + double z = caster.posZ - 0.25 + world.rand.nextDouble() * 0.5; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).lifetime(15).colour(0.5f, 1, 0.7f).spawn(world); } if(ticksInUse % 24 == 0 && world.isRemote){ - Wizardry.proxy.playMovingSound(caster, WizardrySounds.SPELL_LOOP_SPARKLE, 0.5F, 1.0f, false); + Wizardry.proxy.playMovingSound(caster, WizardrySounds.SPELL_LOOP_SPARKLE, 0.5f, 1, false); } return true; } diff --git a/src/main/java/electroblob/wizardry/spell/LifeDrain.java b/src/main/java/electroblob/wizardry/spell/LifeDrain.java index 77d314bb..364b5890 100644 --- a/src/main/java/electroblob/wizardry/spell/LifeDrain.java +++ b/src/main/java/electroblob/wizardry/spell/LifeDrain.java @@ -1,110 +1,76 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public class LifeDrain extends Spell { +public class LifeDrain extends SpellRay { + + private static final float BASE_DAMAGE = 2; + /** The fraction of the damage dealt that is transferred to the caster as healing. */ + private static final float HEAL_FACTOR = 0.35f; public LifeDrain(){ - super(Tier.APPRENTICE, 10, Element.NECROMANCY, "life_drain", SpellType.ATTACK, 0, EnumAction.NONE, true); + super("life_drain", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 10, 0, true, 10, null); + this.particleVelocity(-0.5); + this.particleSpacing(0.4); } - + @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - - if(ticksInUse % 12 == 0){ - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), - 2.0f * modifiers.get(SpellModifiers.DAMAGE)); - caster.heal(1); + // TODO: Temporary solution until I implement a better continuous sound system + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag){ + if(ticksInUse % 18 == 0){ + if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 1, 0.6f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_CRACKLE, 2, 1); } } - if(world.isRemote){ - for(int i = 5; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - if(i % 5 == 0){ - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 0, 0.1f, 0.0f, 0.0f); - } - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, -0.05 * look.x * i, - -0.05 * look.y * i, -0.05 * look.z * i, 8 + world.rand.nextInt(6), 0.5f, 0.0f, 0.0f); - } - } - if(ticksInUse % 18 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 1.0F, 0.6f); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_CRACKLE, 2.0F, 1.0f); - } - return true; + return flag; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - Vec3d vec = new Vec3d(target.posX - caster.posX, target.posY - caster.posY, target.posZ - caster.posZ).normalize(); - - if(ticksInUse % 12 == 0){ - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), - 2.0f * modifiers.get(SpellModifiers.DAMAGE)); - caster.heal(1); - } - - if(world.isRemote){ - for(int i = 5; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - double x1 = caster.posX + vec.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + vec.y * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + vec.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - if(i % 5 == 0){ - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 0, 0.1f, 0.0f, 0.0f); - } - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, -0.05 * vec.x * i, - -0.05 * vec.y * i, -0.05 * vec.z * i, 8 + world.rand.nextInt(6), 0.5f, 0.0f, 0.0f); - } - } - + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag){ if(ticksInUse % 18 == 0){ - if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_SUMMONING, 1.0F, 0.6f); - caster.playSound(WizardrySounds.SPELL_LOOP_CRACKLE, 2.0F, 1.0f); + if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_SUMMONING, 1, 0.6f); + caster.playSound(WizardrySounds.SPELL_LOOP_CRACKLE, 2, 1); } + } + return flag; + } + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + if(ticksInUse % 12 == 0){ + + float damage = BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY); + + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, + DamageType.MAGIC), damage); + + caster.heal(damage * HEAL_FACTOR); + } + return true; } @@ -112,8 +78,21 @@ public class LifeDrain extends Spell { } @Override - public boolean canBeCastByNPCs(){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + if(world.rand.nextInt(5) == 0) ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0, 0).spawn(world); + // This used to multiply the velocity by the distance from the caster + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(6)) + .colour(0.5f, 0, 0).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/Light.java b/src/main/java/electroblob/wizardry/spell/Light.java index 453c2865..b97cf15b 100644 --- a/src/main/java/electroblob/wizardry/spell/Light.java +++ b/src/main/java/electroblob/wizardry/spell/Light.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; public class Light extends Spell { public Light(){ - super(Tier.BASIC, 5, Element.SORCERY, "light", SpellType.UTILITY, 15, EnumAction.NONE, false); + super("light", Tier.BASIC, Element.SORCERY, SpellType.UTILITY, 5, 15, EnumAction.NONE, false); } @Override @@ -30,7 +30,7 @@ public class Light extends Spell { @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - RayTraceResult rayTrace = WizardryUtilities.rayTrace(4, world, caster, false); + RayTraceResult rayTrace = WizardryUtilities.standardBlockRayTrace(world, caster, 4, false); if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ diff --git a/src/main/java/electroblob/wizardry/spell/LightningArrow.java b/src/main/java/electroblob/wizardry/spell/LightningArrow.java deleted file mode 100644 index 0940bc3b..00000000 --- a/src/main/java/electroblob/wizardry/spell/LightningArrow.java +++ /dev/null @@ -1,69 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityLightningArrow; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class LightningArrow extends Spell { - - public LightningArrow(){ - super(Tier.APPRENTICE, 15, Element.LIGHTNING, "lightning_arrow", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityLightningArrow lightningArrow = new EntityLightningArrow(world, caster, - 2 * modifiers.get(WizardryItems.range_upgrade), modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(lightningArrow); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, - world.rand.nextFloat() * 0.3F + 1.3F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityLightningArrow lightningArrow = new EntityLightningArrow(world, caster, target, - 2 * modifiers.get(WizardryItems.range_upgrade), 4, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(lightningArrow); - } - - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1.0F, world.rand.nextFloat() * 0.3F + 1.3F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/LightningBolt.java b/src/main/java/electroblob/wizardry/spell/LightningBolt.java index 85567859..49c854d3 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningBolt.java +++ b/src/main/java/electroblob/wizardry/spell/LightningBolt.java @@ -6,100 +6,66 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.effect.EntityLightningBolt; import net.minecraft.entity.monster.EntityCreeper; import net.minecraft.entity.passive.EntityPig; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraftforge.event.entity.EntityStruckByLightningEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber -public class LightningBolt extends Spell { +public class LightningBolt extends SpellRay { /** The NBT key used to store the UUID of the player that summoned the lightning bolt. Used for achievements. */ public static final String NBT_KEY = "summoningPlayer"; public LightningBolt(){ - super(Tier.ADVANCED, 40, Element.LIGHTNING, "lightning_bolt", SpellType.ATTACK, 80, EnumAction.NONE, false); + super("lightning_bolt", Tier.ADVANCED, Element.LIGHTNING, SpellType.ATTACK, 40, 80, false, 200, null); + this.ignoreEntities(true); } + @Override public boolean doesSpellRequirePacket(){ return false; } + @Override - public boolean doesSpellRequirePacket(){ + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(world.canBlockSeeSky(pos.up())){ - RayTraceResult rayTrace = WizardryUtilities.rayTrace(200, world, caster, false); + if(!world.isRemote){ + EntityLightningBolt entitylightning = new EntityLightningBolt(world, pos.getX(), pos.getY(), + pos.getZ(), false); + world.addWeatherEffect(entitylightning); - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = rayTrace.getBlockPos(); - - // Not sure why it is up 1 but it has to be for canBlockSeeSky to work properly. - // TODO: Remove this requirement? - if(world.canBlockSeeSky(pos.up())){ - - if(!world.isRemote){ - EntityLightningBolt entitylightning = new EntityLightningBolt(world, pos.getX(), pos.getY(), - pos.getZ(), false); - world.addWeatherEffect(entitylightning); - - // Code for eventhandler recognition; for achievements and such like. Left in for future use. + // Code for eventhandler recognition for achievements + if(caster instanceof EntityPlayer){ NBTTagCompound entityNBT = entitylightning.getEntityData(); entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); } - - caster.swingArm(hand); - return true; } - } + return true; + } + return false; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - int x = (int)target.posX; - int y = (int)target.posY; - int z = (int)target.posZ; - - // Not sure why it is up 1 but it has to be for canBlockSeeSky to work properly. - // TODO: Remove this requirement? - if(world.canBlockSeeSky(new BlockPos(x, y, z))){ - - if(!world.isRemote){ - EntityLightningBolt entitylightning = new EntityLightningBolt(world, x, y, z, false); - world.addWeatherEffect(entitylightning); - } - - caster.swingArm(hand); - return true; - } - } - + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } - @Override - public boolean canBeCastByNPCs(){ - return true; - } - @SubscribeEvent public static void onEntityStruckByLightningEvent(EntityStruckByLightningEvent event){ @@ -116,6 +82,6 @@ public class LightningBolt extends Spell { WizardryAdvancementTriggers.frankenstein.triggerFor(player); } } - } + } diff --git a/src/main/java/electroblob/wizardry/spell/LightningDisc.java b/src/main/java/electroblob/wizardry/spell/LightningDisc.java deleted file mode 100644 index ef01f4f3..00000000 --- a/src/main/java/electroblob/wizardry/spell/LightningDisc.java +++ /dev/null @@ -1,69 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityLightningDisc; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class LightningDisc extends Spell { - - public LightningDisc(){ - super(Tier.ADVANCED, 25, Element.LIGHTNING, "lightning_disc", SpellType.ATTACK, 60, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityLightningDisc lightningdisc = new EntityLightningDisc(world, caster, - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(lightningdisc); - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, - world.rand.nextFloat() * 0.3F + 0.8F); - caster.swingArm(hand); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityLightningDisc lightningdisc = new EntityLightningDisc(world, caster, - modifiers.get(SpellModifiers.DAMAGE)); - lightningdisc.directTowards(target, 1.2f); - world.spawnEntity(lightningdisc); - } - - caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1.0F, world.rand.nextFloat() * 0.3F + 0.8F); - caster.swingArm(hand); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/LightningHammer.java b/src/main/java/electroblob/wizardry/spell/LightningHammer.java index 6bf29e29..e31c283e 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningHammer.java +++ b/src/main/java/electroblob/wizardry/spell/LightningHammer.java @@ -4,60 +4,31 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityHammer; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class LightningHammer extends Spell { +public class LightningHammer extends SpellConstructRanged { public LightningHammer(){ - super(Tier.MASTER, 100, Element.LIGHTNING, "lightning_hammer", SpellType.ATTACK, 300, EnumAction.BOW, false); + super("lightning_hammer", Tier.MASTER, Element.LIGHTNING, SpellType.ATTACK, 100, 300, EntityHammer::new, 600, 40, WizardrySounds.SPELL_SUMMONING); + this.soundValues(3, 1, 0); + this.floor(true); + this.overlap(true); } @Override - public boolean doesSpellRequirePacket(){ - return false; + protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + // TESTME: Does this need to be one block higher? + if(!world.canBlockSeeSky(new BlockPos(x, y, z))) return false; + return super.spawnConstruct(world, x, y + 50, z, caster, modifiers); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(40 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = rayTrace.getBlockPos(); - - // Not sure why it is +1 but it has to be to work properly. - if(world.canBlockSeeSky(pos.up())){ - - if(!world.isRemote){ - - EntityHammer hammer = new EntityHammer(world, pos.getX() + 0.5, pos.getY() + 50, pos.getZ() + 0.5, - caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - - hammer.motionX = 0; - hammer.motionY = -2; - hammer.motionZ = 0; - - world.spawnEntity(hammer); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 3.0f, 1.0f); - return true; - } - } - return false; + protected void addConstructExtras(EntityHammer construct, EntityLivingBase caster, SpellModifiers modifiers){ + construct.motionY = -2; } } diff --git a/src/main/java/electroblob/wizardry/spell/LightningPulse.java b/src/main/java/electroblob/wizardry/spell/LightningPulse.java index 85fb7b49..acd809d4 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningPulse.java +++ b/src/main/java/electroblob/wizardry/spell/LightningPulse.java @@ -22,15 +22,20 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; public class LightningPulse extends Spell { + + private static final double BASE_RADIUS = 3; + private static final float BASE_DAMAGE = 8; public LightningPulse(){ - super(Tier.ADVANCED, 25, Element.LIGHTNING, "lightning_pulse", SpellType.ATTACK, 75, EnumAction.NONE, false); + super("lightning_pulse", Tier.ADVANCED, Element.LIGHTNING, SpellType.ATTACK, 25, 75, EnumAction.NONE, false); } @Override public boolean doesSpellRequirePacket(){ return false; } + + // TODO: NPC casting support @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ @@ -38,13 +43,13 @@ public class LightningPulse extends Spell { if(caster.onGround){ List targets = WizardryUtilities.getEntitiesWithinRadius( - 3.0d * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + BASE_RADIUS * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); for(EntityLivingBase target : targets){ if(WizardryUtilities.isValidTarget(caster, target)){ - // Damage is 4 hearts no matter where the target is. + // Base damage is 4 hearts no matter where the target is. target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 8 * modifiers.get(SpellModifiers.DAMAGE)); + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); if(!world.isRemote){ @@ -66,15 +71,20 @@ public class LightningPulse extends Spell { } } } + if(!world.isRemote){ - EntityLightningPulse lightningpulse = new EntityLightningPulse(world, caster.posX, - caster.getEntityBoundingBox().minY, caster.posZ, caster, 7, - modifiers.get(SpellModifiers.DAMAGE)); + // Surely neither of the commented lines would have done anything? + EntityLightningPulse lightningpulse = new EntityLightningPulse(world); + lightningpulse.setPosition(caster.posX, caster.getEntityBoundingBox().minY, caster.posZ); + //lightningpulse.setCaster(caster); + lightningpulse.lifetime = 7; + //lightningpulse.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); world.spawnEntity(lightningpulse); } + caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0f, 1.0f); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 2.0f, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1, 1); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 2, 1); return true; } return false; diff --git a/src/main/java/electroblob/wizardry/spell/LightningRay.java b/src/main/java/electroblob/wizardry/spell/LightningRay.java index 0d7236b2..c2eb74a6 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningRay.java +++ b/src/main/java/electroblob/wizardry/spell/LightningRay.java @@ -1,158 +1,123 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.EntityArc; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class LightningRay extends Spell { +public class LightningRay extends SpellRay { + + private static final float BASE_DAMAGE = 3; public LightningRay(){ - super(Tier.APPRENTICE, 5, Element.LIGHTNING, "lightning_ray", SpellType.ATTACK, 0, EnumAction.NONE, true); + super("lightning_ray", Tier.APPRENTICE, Element.LIGHTNING, SpellType.ATTACK, 5, 0, true, 10, null); } - + @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade), 2.0f); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - Entity target = rayTrace.entityHit; - if(!world.isRemote){ - // This statement means the arc only spawns every other tick. - if(ticksInUse % 2 == 0){ - - EntityArc arc = new EntityArc(world); - // The look vec stuff performs a translation on the start point to line it up with the wand. - // EDIT: removed due to 1st/3rd person render differences. - 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); - } - - if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ - if(!world.isRemote && ticksInUse == 1) - caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); - }else{ - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); - } - - }else{ - for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 0, 0, 0, 3); - } - } - + // TODO: Temporary solution until I implement a better continuous sound system + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag){ if(ticksInUse == 1){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1, 1); }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1, 1); } - - return true; - - }else{ - if(!world.isRemote){ - // This statement means the arc only spawns every other tick. - if(ticksInUse % 2 == 0){ - - EntityArc arc = new EntityArc(world); - - arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, - caster.posX + caster.getLookVec().x * 8, - caster.posY + caster.eyeHeight + caster.getLookVec().y * 8, - caster.posZ + caster.getLookVec().z * 8); - - arc.lifetime = 1; - - world.spawnEntity(arc); - } - } - - if(ticksInUse == 1){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); - }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); - } - - return true; } + return flag; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag){ + if(ticksInUse == 1){ + caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1, 1); + }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ + caster.playSound(WizardrySounds.SPELL_LOOP_LIGHTNING, 1, 1); + } + } + return flag; + } - if(target != null){ + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ + if(!world.isRemote && ticksInUse == 1) + caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted())); + }else{ + WizardryUtilities.attackEntityWithoutKnockback(target, + MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + } + if(!world.isRemote){ - // This statement means the arc only spawns every other tick. + if(ticksInUse % 2 == 0){ EntityArc arc = new EntityArc(world); - // The look vec stuff performs a translation on the start point to line it up with the wand. - // EDIT: removed due to 1st/3rd person render differences. 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); } - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); - }else{ - for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 0, 0, 0, 3); + // Particle effect + for(int i=0; i<5; i++){ + ParticleBuilder.create(Type.SPARK, target); } } - - if(ticksInUse == 1){ - caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); - }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - caster.playSound(WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); - } - - return true; } - + return false; } @Override - public boolean canBeCastByNPCs(){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + // This is a nice example of when onMiss is used for more than just returning a boolean + if(!world.isRemote){ + + if(ticksInUse % 2 == 0){ + + double freeRange = 0.8 * baseRange; // The arc does not reach full range when it has a free end + + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, + caster.posX + caster.getLookVec().x * freeRange, + caster.posY + caster.getEyeHeight() + caster.getLookVec().y * freeRange, + caster.posZ + caster.getLookVec().z * freeRange); + arc.lifetime = 1; + world.spawnEntity(arc); + + } + } + return true; } diff --git a/src/main/java/electroblob/wizardry/spell/LightningSigil.java b/src/main/java/electroblob/wizardry/spell/LightningSigil.java deleted file mode 100644 index 14044079..00000000 --- a/src/main/java/electroblob/wizardry/spell/LightningSigil.java +++ /dev/null @@ -1,53 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityLightningSigil; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.world.World; - -public class LightningSigil extends Spell { - - public LightningSigil(){ - super(Tier.APPRENTICE, 10, Element.LIGHTNING, "lightning_sigil", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(10 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && rayTrace.sideHit == EnumFacing.UP){ - - if(!world.isRemote){ - double x = rayTrace.hitVec.x; - double y = rayTrace.hitVec.y; - double z = rayTrace.hitVec.z; - EntityLightningSigil lightningsigil = new EntityLightningSigil(world, x, y, z, caster, - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(lightningsigil); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0F, 0.3F); - return true; - } - return false; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/LightningWeb.java b/src/main/java/electroblob/wizardry/spell/LightningWeb.java index 7bc5519b..548bec0e 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningWeb.java +++ b/src/main/java/electroblob/wizardry/spell/LightningWeb.java @@ -2,219 +2,169 @@ package electroblob.wizardry.spell; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.EntityArc; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class LightningWeb extends Spell { +public class LightningWeb extends SpellRay { + + private static final float PRIMARY_DAMAGE = 5; + private static final float SECONDARY_DAMAGE = 4; + private static final float TERTIARY_DAMAGE = 3; + + private static final double PRIMARY_RANGE = 10; + private static final double SECONDARY_RANGE = 5; + private static final double TERTIARY_RANGE = 5; + + private static final int SECONDARY_MAX_TARGETS = 5; + private static final int TERTIARY_MAX_TARGETS = 2; // This is per secondary target, giving 10 in total public LightningWeb(){ - super(Tier.MASTER, 15, Element.LIGHTNING, "lightning_web", SpellType.ATTACK, 0, EnumAction.NONE, true); + super("lightning_web", Tier.MASTER, Element.LIGHTNING, SpellType.ATTACK, 15, 0, true, PRIMARY_RANGE, null); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + // TODO: Temporary solution until I implement a better continuous sound system + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag){ + if(ticksInUse == 1){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1, 1); + }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1, 1); + } + } + return flag; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade), 2.0f); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - Entity target = rayTrace.entityHit; - - if(!world.isRemote){ - - // This statement means the arc only spawns every other tick. - if(ticksInUse % 2 == 0){ - EntityArc arc = new EntityArc(world); - // The look vec stuff performs a translation on the start point to line it up with the wand. - // EDIT: removed due to 1st/3rd person render differences. - 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); - } - - if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ - if(!world.isRemote && ticksInUse == 1) - caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); - }else{ - // This motion stuff removes knockback, which is desirable for continuous spells. - double motionX = target.motionX; - double motionY = target.motionY; - double motionZ = target.motionZ; - - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 5.0f * modifiers.get(SpellModifiers.DAMAGE)); - - target.motionX = motionX; - target.motionY = motionY; - target.motionZ = motionZ; - } - }else{ - for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 0, 0, 0, 3); - } + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag){ + if(ticksInUse == 1){ + caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1, 1); + }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ + caster.playSound(WizardrySounds.SPELL_LOOP_LIGHTNING, 1, 1); } - + } + return flag; + } + + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + electrocute(world, caster, caster, target, PRIMARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY), ticksInUse); + // Secondary chaining effect - double seekerRange = 5.0d; - List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(SECONDARY_RANGE, target.posX, target.posY + target.height / 2, target.posZ, world); - // This is a MUCH better way of filtering the secondary targets! + secondaryTargets.remove(target); - if(secondaryTargets.size() > 5) secondaryTargets = secondaryTargets.subList(0, 5); + secondaryTargets.removeIf(e -> !WizardryUtilities.isLiving(e)); + secondaryTargets.removeIf(e -> !WizardryUtilities.isValidTarget(caster, e)); + if(secondaryTargets.size() > SECONDARY_MAX_TARGETS) secondaryTargets = secondaryTargets.subList(0, SECONDARY_MAX_TARGETS); for(EntityLivingBase secondaryTarget : secondaryTargets){ - if(WizardryUtilities.isValidTarget(caster, secondaryTarget)){ + electrocute(world, caster, target, secondaryTarget, + SECONDARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY), ticksInUse); - if(!world.isRemote){ - // This statement means the arc only spawns every other tick. - if(ticksInUse % 2 == 0){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(target.posX, target.posY + 1.2, target.posZ, secondaryTarget.posX, - secondaryTarget.posY + secondaryTarget.height / 2, secondaryTarget.posZ); - arc.lifetime = 1; - world.spawnEntity(arc); - } + // Tertiary chaining effect - if(MagicDamage.isEntityImmune(DamageType.SHOCK, secondaryTarget)){ - if(!world.isRemote && ticksInUse == 1) - caster.sendMessage(new TextComponentTranslation("spell.resist", - secondaryTarget.getName(), this.getNameForTranslationFormatted())); - }else{ - // This motion stuff removes knockback, which is desirable for continuous spells. - double motionX = secondaryTarget.motionX; - double motionY = secondaryTarget.motionY; - double motionZ = secondaryTarget.motionZ; + List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(TERTIARY_RANGE, + secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, + secondaryTarget.posZ, world); + + tertiaryTargets.remove(target); + tertiaryTargets.removeAll(secondaryTargets); + tertiaryTargets.removeIf(e -> !WizardryUtilities.isLiving(e)); + tertiaryTargets.removeIf(e -> !WizardryUtilities.isValidTarget(caster, e)); + if(tertiaryTargets.size() > TERTIARY_MAX_TARGETS) tertiaryTargets = tertiaryTargets.subList(0, TERTIARY_MAX_TARGETS); - secondaryTarget.attackEntityFrom( - MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 4.0f * modifiers.get(SpellModifiers.DAMAGE)); - - secondaryTarget.motionX = motionX; - secondaryTarget.motionY = motionY; - secondaryTarget.motionZ = motionZ; - } - }else{ - for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 3); - } - } - - // Tertiary chaining effect - - List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, - secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, - secondaryTarget.posZ, world); - tertiaryTargets.remove(target); - tertiaryTargets.removeAll(secondaryTargets); - if(tertiaryTargets.size() > 2) tertiaryTargets = tertiaryTargets.subList(0, 2); - - for(EntityLivingBase tertiaryTarget : tertiaryTargets){ - - if(WizardryUtilities.isValidTarget(caster, tertiaryTarget)){ - - if(!world.isRemote){ - // This statement means the arc only spawns every other tick. - if(ticksInUse % 2 == 0){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(secondaryTarget.posX, secondaryTarget.posY + 1.2, - secondaryTarget.posZ, tertiaryTarget.posX, - tertiaryTarget.posY + tertiaryTarget.height / 2, tertiaryTarget.posZ); - arc.lifetime = 1; - world.spawnEntity(arc); - } - - if(MagicDamage.isEntityImmune(DamageType.SHOCK, tertiaryTarget)){ - if(!world.isRemote && ticksInUse == 1) - caster.sendMessage(new TextComponentTranslation("spell.resist", - tertiaryTarget.getName(), this.getNameForTranslationFormatted())); - }else{ - // This motion stuff removes knockback, which is desirable for continuous spells. - double motionX = tertiaryTarget.motionX; - double motionY = tertiaryTarget.motionY; - double motionZ = tertiaryTarget.motionZ; - - tertiaryTarget.attackEntityFrom( - MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 3.0f * modifiers.get(SpellModifiers.DAMAGE)); - - tertiaryTarget.motionX = motionX; - tertiaryTarget.motionY = motionY; - tertiaryTarget.motionZ = motionZ; - } - }else{ - for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - tertiaryTarget.posX + world.rand.nextFloat() - 0.5, - tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2 - + world.rand.nextFloat() * 2 - 1, - tertiaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); - } - } - } - } + for(EntityLivingBase tertiaryTarget : tertiaryTargets){ + electrocute(world, caster, secondaryTarget, tertiaryTarget, + TERTIARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY), ticksInUse); } } + } + + return false; + } - if(ticksInUse == 1){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); - }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + // This is a nice example of when onMiss is used for more than just returning a boolean + if(!world.isRemote){ + + if(ticksInUse % 2 == 0){ + + double freeRange = 0.8 * baseRange; // The arc does not reach full range when it has a free end + + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, + caster.posX + caster.getLookVec().x * freeRange, + caster.posY + caster.getEyeHeight() + caster.getLookVec().y * freeRange, + caster.posZ + caster.getLookVec().z * freeRange); + arc.lifetime = 1; + world.spawnEntity(arc); + } + } + + return true; + } + + private void electrocute(World world, Entity caster, Entity origin, Entity target, float damage, int ticksInUse){ - return true; - + if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ + if(!world.isRemote && ticksInUse == 1) + caster.sendMessage(new TextComponentTranslation("spell.resist", + target.getName(), this.getNameForTranslationFormatted())); }else{ - if(!world.isRemote){ - // This statement means the arc only spawns every other tick. - if(ticksInUse % 2 == 0){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, - caster.posX + caster.getLookVec().x * 8, - caster.posY + caster.eyeHeight + caster.getLookVec().y * 8, - caster.posZ + caster.getLookVec().z * 8); - arc.lifetime = 1; - // arc.setOffset(entityplayer.getLookVec().zCoord * 0.5, entityplayer.getLookVec().xCoord * 0.5); - world.spawnEntity(arc); - } + WizardryUtilities.attackEntityWithoutKnockback(target, + MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage); + } + + if(!world.isRemote){ + // Arc entity spawning + if(ticksInUse % 2 == 0){ + EntityArc arc = new EntityArc(world); + arc.setEndpointCoords(origin.posX, origin.posY + 1.2, origin.posZ, target.posX, + target.posY + target.height / 2, target.posZ); + arc.lifetime = 1; + world.spawnEntity(arc); } - - if(ticksInUse == 1){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1.0F, 1.0f); - }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1.0F, 1.0f); + + }else{ + // Particle effect + for(int i=0; i<5; i++){ + ParticleBuilder.create(Type.SPARK, target); } - - return true; } } diff --git a/src/main/java/electroblob/wizardry/spell/MagicMissile.java b/src/main/java/electroblob/wizardry/spell/MagicMissile.java deleted file mode 100644 index 1b42bc93..00000000 --- a/src/main/java/electroblob/wizardry/spell/MagicMissile.java +++ /dev/null @@ -1,71 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityMagicMissile; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class MagicMissile extends Spell { - - public MagicMissile(){ - super(Tier.BASIC, 5, Element.MAGIC, "magic_missile", SpellType.ATTACK, 10, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityMagicMissile magicMissile = new EntityMagicMissile(world, caster, - 2 * modifiers.get(WizardryItems.range_upgrade), modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(magicMissile); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_MAGIC, 1.0F, - world.rand.nextFloat() * 0.4F + 1.2F); - - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityMagicMissile magicMissile = new EntityMagicMissile(world, caster, target, - 2 * modifiers.get(WizardryItems.range_upgrade), 4, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(magicMissile); - } - - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_MAGIC, 1.0F, world.rand.nextFloat() * 0.4F + 1.2F); - - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java index 5489e28d..56ec9107 100644 --- a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java +++ b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java @@ -9,10 +9,10 @@ import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntitySkeletonMinion; import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -31,21 +31,16 @@ import net.minecraft.entity.passive.EntityChicken; import net.minecraft.entity.passive.EntityCow; import net.minecraft.entity.passive.EntityMooshroom; import net.minecraft.entity.passive.EntityPig; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public class Metamorphosis extends Spell { +public class Metamorphosis extends SpellRay { public static final BiMap, Class> TRANSFORMATIONS = HashBiMap.create(); - public Metamorphosis(){ - super(Tier.APPRENTICE, 15, Element.NECROMANCY, "metamorphosis", SpellType.UTILITY, 30, EnumAction.NONE, false); - + static { addTransformation(EntityPig.class, EntityPigZombie.class); addTransformation(EntityCow.class, EntityMooshroom.class); addTransformation(EntityChicken.class, EntityBat.class); @@ -66,25 +61,26 @@ public class Metamorphosis extends Spell { previousEntity = entity; } } + + public Metamorphosis(){ + super("metamorphosis", Tier.APPRENTICE, Element.NECROMANCY, SpellType.UTILITY, 15, 30, false, 10, WizardrySounds.SPELL_DEFLECTION); + this.soundValues(0.5f, 0.8f, 0); + } + + @Override public boolean canBeCastByNPCs() { return false; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.entityHit != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - Entity entityHit = rayTrace.entityHit; - double xPos = entityHit.posX; - double yPos = entityHit.posY; - double zPos = entityHit.posZ; + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + double xPos = target.posX; + double yPos = target.posY; + double zPos = target.posZ; // Sneaking allows the entities to be cycled through in the other direction. Class newEntityClass = caster.isSneaking() ? - TRANSFORMATIONS.inverse().get(entityHit.getClass()) : TRANSFORMATIONS.get(entityHit.getClass()); + TRANSFORMATIONS.inverse().get(target.getClass()) : TRANSFORMATIONS.get(target.getClass()); if(newEntityClass == null) return false; @@ -93,7 +89,8 @@ public class Metamorphosis extends Spell { try { newEntity = newEntityClass.getConstructor(World.class).newInstance(world); } catch (Exception e){ - Wizardry.logger.error("Error while attempting to transform entity " + entityHit.getClass() + " to entity " + newEntityClass); + Wizardry.logger.error("Error while attempting to transform entity " + target.getClass() + " to entity " + + newEntityClass); e.printStackTrace(); } @@ -101,39 +98,34 @@ public class Metamorphosis extends Spell { if(!world.isRemote){ // Transfers attributes from the old entity to the new one. - newEntity.setHealth(((EntityLivingBase)entityHit).getHealth()); + newEntity.setHealth(((EntityLivingBase)target).getHealth()); NBTTagCompound tag = new NBTTagCompound(); - entityHit.writeToNBT(tag); + target.writeToNBT(tag); // Remove the UUID because keeping it the same causes the entity to disappear WizardryUtilities.removeUniqueId(tag, "UUID"); newEntity.readFromNBT(tag); - entityHit.setDead(); + target.setDead(); newEntity.setPosition(xPos, yPos, zPos); world.spawnEntity(newEntity); }else{ - - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 0.2f, 0.0f, 0.1f); - } - for(int i = 0; i < 5; i++){ - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, xPos, yPos, zPos, 0.0d, - 0.0d, 0.0d, 0, 0.1f, 0.0f, 0.0f); + for(int i=0; i<5; i++){ + ParticleBuilder.create(Type.DARK_MAGIC).pos(xPos, yPos, zPos).colour(0.1f, 0, 0).spawn(world); } } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_DEFLECTION, 0.5F, 0.8f); - return true; } + + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Meteor.java b/src/main/java/electroblob/wizardry/spell/Meteor.java index 073d9ba6..e309762e 100644 --- a/src/main/java/electroblob/wizardry/spell/Meteor.java +++ b/src/main/java/electroblob/wizardry/spell/Meteor.java @@ -7,49 +7,46 @@ import electroblob.wizardry.entity.EntityMeteor; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class Meteor extends Spell { +public class Meteor extends SpellRay { public Meteor(){ - super(Tier.MASTER, 100, Element.FIRE, "meteor", SpellType.ATTACK, 200, EnumAction.NONE, false); + super("meteor", Tier.MASTER, Element.FIRE, SpellType.ATTACK, 100, 200, false, 40, WizardrySounds.SPELL_SUMMONING); + this.soundValues(3, 1, 0); + this.ignoreEntities(true); } + @Override public boolean doesSpellRequirePacket(){ return false; } + @Override - public boolean doesSpellRequirePacket(){ + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(world.canBlockSeeSky(pos.up())){ - RayTraceResult rayTrace = WizardryUtilities.rayTrace(40 * modifiers.get(WizardryItems.range_upgrade), world, - caster, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = rayTrace.getBlockPos(); - - // Not sure why it is +1 but it has to be to work properly. - if(world.canBlockSeeSky(pos.up())){ - - if(!world.isRemote){ - EntityMeteor meteor = new EntityMeteor(world, pos.getX(), pos.getY() + 50, pos.getZ(), - modifiers.get(WizardryItems.blast_upgrade)); - world.spawnEntity(meteor); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 3.0f, 1.0f); - return true; + if(!world.isRemote){ + EntityMeteor meteor = new EntityMeteor(world, pos.getX(), pos.getY() + 50, pos.getZ(), + modifiers.get(WizardryItems.blast_upgrade)); + world.spawnEntity(meteor); } + + return true; } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/MindControl.java b/src/main/java/electroblob/wizardry/spell/MindControl.java index bcf46dc8..96c4cccd 100644 --- a/src/main/java/electroblob/wizardry/spell/MindControl.java +++ b/src/main/java/electroblob/wizardry/spell/MindControl.java @@ -11,8 +11,9 @@ import electroblob.wizardry.entity.living.EntityEvilWizard; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList; @@ -21,12 +22,10 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.INpc; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.item.EntityArmorStand; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; @@ -35,115 +34,73 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber -public class MindControl extends Spell { +public class MindControl extends SpellRay { - /** - * The NBT tag name for storing the controlling entity's UUID in the target's tag compound. Defined here in case it - * changes. - */ + /** The NBT tag name for storing the controlling entity's UUID in the target's tag compound. */ public static final String NBT_KEY = "controllingEntity"; + + private static final int BASE_DURATION = 600; public MindControl(){ - super(Tier.ADVANCED, 40, Element.NECROMANCY, "mind_control", SpellType.ATTACK, 150, EnumAction.NONE, false); + super("mind_control", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 40, 150, false, 8, WizardrySounds.SPELL_SUMMONING); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 8 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.entityHit != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + if(!world.isRemote){ + if(!canControl(target)){ // Adds a message saying that the player/boss entity/wizard resisted mind control caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); - + }else if(target instanceof EntityLiving){ - + if(!MindControl.findMindControlTarget((EntityLiving)target, caster, world)){ // If no valid target was found, this just acts like mind trick. ((EntityLiving)target).setAttackTarget(null); } - + NBTTagCompound entityNBT = target.getEntityData(); if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); - + ((EntityLiving)target).addPotionEffect(new PotionEffect(WizardryPotions.mind_control, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); } + }else{ - for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, - target.posX - 0.25 + world.rand.nextDouble() * 0.5, - target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 - + world.rand.nextDouble() * 0.5, - target.posZ - 0.25 + world.rand.nextDouble() * 0.5, 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, - target.posX - 0.25 + world.rand.nextDouble() * 0.5, - target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 - + world.rand.nextDouble() * 0.5, - target.posZ - 0.25 + world.rand.nextDouble() * 0.5, 0, 0, 0, 0, 0.2f, 0.04f, 0.25f); + + for(int i=0; i<10; i++){ + ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, + target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) + .colour(0.8f, 0.2f, 1.0f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, + target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) + .colour(0.2f, 0.04f, 0.25f).spawn(world); } } - target.playSound(WizardrySounds.SPELL_SUMMONING, 1.0f, 1.0f); - caster.swingArm(hand); + return true; } + return false; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - if(!world.isRemote){ - if(canControl(target)){ - - if(!MindControl.findMindControlTarget((EntityLiving)target, caster, world)){ - // If no valid target was found, this just acts like mind trick. - ((EntityLiving)target).setAttackTarget(null); - } - - NBTTagCompound entityNBT = target.getEntityData(); - if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); - - ((EntityLiving)target).addPotionEffect(new PotionEffect(WizardryPotions.mind_control, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - } - }else{ - for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, - target.posX - 0.25 + world.rand.nextDouble() * 0.5, - target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 - + world.rand.nextDouble() * 0.5, - target.posZ - 0.25 + world.rand.nextDouble() * 0.5, 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, - target.posX - 0.25 + world.rand.nextDouble() * 0.5, - target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 - + world.rand.nextDouble() * 0.5, - target.posZ - 0.25 + world.rand.nextDouble() * 0.5, 0, 0, 0, 0, 0.2f, 0.04f, 0.25f); - } - } - target.playSound(WizardrySounds.SPELL_SUMMONING, 1.0f, 1.0f); - caster.swingArm(hand); - return true; - } + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean canBeCastByNPCs(){ - return true; + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; } /** Returns true if the given entity can be mind controlled (i.e. is not a player, npc, evil wizard or boss). */ - public static boolean canControl(EntityLivingBase target){ + public static boolean canControl(Entity target){ return target instanceof EntityLiving && target.isNonBoss() && !(target instanceof INpc) && !(target instanceof EntityEvilWizard) && !Arrays.asList(Wizardry.settings.mindControlTargetsBlacklist) .contains(EntityList.getKey(target.getClass())); diff --git a/src/main/java/electroblob/wizardry/spell/MindTrick.java b/src/main/java/electroblob/wizardry/spell/MindTrick.java index 9f4f0dab..0bf6b2fa 100644 --- a/src/main/java/electroblob/wizardry/spell/MindTrick.java +++ b/src/main/java/electroblob/wizardry/spell/MindTrick.java @@ -1,23 +1,23 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; @@ -25,90 +25,56 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber -public class MindTrick extends Spell { +public class MindTrick extends SpellRay { + + private static final int BASE_DURATION = 300; public MindTrick(){ - super(Tier.BASIC, 10, Element.NECROMANCY, "mind_trick", SpellType.ATTACK, 40, EnumAction.NONE, false); + super("mind_trick", Tier.BASIC, Element.NECROMANCY, SpellType.ATTACK, 10, 40, false, 8, WizardrySounds.SPELL_DEFLECTION); + this.soundValues(0.7f, 1, 0.4f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 8 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.entityHit != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ if(!world.isRemote){ if(target instanceof EntityPlayer){ - target.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, - (int)(300 * modifiers.get(WizardryItems.duration_upgrade)), 0)); + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.NAUSEA, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); }else if(target instanceof EntityLiving){ ((EntityLiving)target).setAttackTarget(null); - target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, - (int)(300 * modifiers.get(WizardryItems.duration_upgrade)), 0)); + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); } + }else{ - for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, - target.posX - 0.25 + world.rand.nextDouble() * 0.5, - target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 - + world.rand.nextDouble() * 0.5, - target.posZ - 0.25 + world.rand.nextDouble() * 0.5, 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); + for(int i=0; i<10; i++){ + ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, + target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) + .colour(0.8f, 0.2f, 1.0f).spawn(world); } } - - target.playSound(WizardrySounds.SPELL_DEFLECTION, 0.7F, world.rand.nextFloat() * 0.4F + 0.8F); - caster.swingArm(hand); + return true; } + return false; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - if(!world.isRemote){ - if(target instanceof EntityPlayer){ - - target.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, - (int)(300 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - - }else if(target instanceof EntityLiving){ - - ((EntityLiving)target).setAttackTarget(null); - target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, - (int)(300 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - - } - }else{ - for(int i = 0; i < 10; i++){ - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, - target.posX - 0.25 + world.rand.nextDouble() * 0.5, - target.getEntityBoundingBox().minY + target.getEyeHeight() - 0.25 - + world.rand.nextDouble() * 0.5, - target.posZ - 0.25 + world.rand.nextDouble() * 0.5, 0, 0, 0, 0, 0.8f, 0.2f, 1.0f); - } - } - - target.playSound(WizardrySounds.SPELL_DEFLECTION, 0.7F, world.rand.nextFloat() * 0.4F + 0.8F); - caster.swingArm(hand); - return true; - } + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean canBeCastByNPCs(){ - return true; + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; } @SubscribeEvent diff --git a/src/main/java/electroblob/wizardry/spell/None.java b/src/main/java/electroblob/wizardry/spell/None.java index 23d16860..95e82045 100644 --- a/src/main/java/electroblob/wizardry/spell/None.java +++ b/src/main/java/electroblob/wizardry/spell/None.java @@ -12,12 +12,12 @@ import net.minecraft.world.World; /** * This class represents a blank spell used to fill empty slots on wands. It is unobtainable in-game, except via * commands, and does nothing when the player attempts to cast it. Its instance can be referenced directly using - * {@link electroblob.wizardry.registry.Spells#none WizardryRegistry.none} + * {@link electroblob.wizardry.registry.Spells#none Spells.none} */ public class None extends Spell { public None(){ - super(Tier.BASIC, 0, Element.MAGIC, "none", SpellType.UTILITY, 0, EnumAction.NONE, false); + super("none", Tier.BASIC, Element.MAGIC, SpellType.UTILITY, 0, 0, EnumAction.NONE, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Oakflesh.java b/src/main/java/electroblob/wizardry/spell/Oakflesh.java deleted file mode 100644 index 21488735..00000000 --- a/src/main/java/electroblob/wizardry/spell/Oakflesh.java +++ /dev/null @@ -1,79 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Oakflesh extends Spell { - - public Oakflesh(){ - super(Tier.APPRENTICE, 20, Element.HEALING, "oakflesh", SpellType.DEFENCE, 50, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.5f, 0.4f); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!caster.isPotionActive(MobEffects.RESISTANCE)){ - - caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)caster.posY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.5f, 0.4f); - } - } - - caster.playSound(WizardrySounds.SPELL_HEAL, 0.7F, world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Petrify.java b/src/main/java/electroblob/wizardry/spell/Petrify.java index 7b1f1a6a..bdbaba16 100644 --- a/src/main/java/electroblob/wizardry/spell/Petrify.java +++ b/src/main/java/electroblob/wizardry/spell/Petrify.java @@ -1,126 +1,60 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.tileentity.TileEntityStatue; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -public class Petrify extends Spell { +public class Petrify extends SpellRay { - private static final int baseDuration = 900; - - /** - * The NBT tag name for storing the petrified flag in the target's tag compound. Defined here in case it changes. - */ - public static final String NBT_KEY = "petrified"; + private static final int BASE_DURATION = 900; public Petrify(){ - super(Tier.ADVANCED, 40, Element.SORCERY, "petrify", SpellType.ATTACK, 100, EnumAction.NONE, false); + super("petrify", Tier.ADVANCED, Element.SORCERY, SpellType.ATTACK, 40, 100, false, 10, SoundEvents.ENTITY_WITHER_SPAWN); + this.soundValues(1, 1.1f, 0.2f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY - && rayTrace.entityHit instanceof EntityLiving && !world.isRemote){ - - EntityLiving target = (EntityLiving)rayTrace.entityHit; - - if(target.deathTime > 0) return false; - - BlockPos pos = new BlockPos(target); - - target.extinguish(); - - // Short mobs such as spiders and pigs - if((target.height < 1.2 || target.isChild()) && WizardryUtilities.canBlockBeReplaced(world, pos)){ - world.setBlockState(pos, WizardryBlocks.petrified_stone.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 1); - ((TileEntityStatue)world.getTileEntity(pos)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - target.getEntityData().setBoolean(NBT_KEY, true); - target.setDead(); - } - // Normal sized mobs like zombies and skeletons - else if(target.height < 2.5 && WizardryUtilities.canBlockBeReplaced(world, pos) - && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ - world.setBlockState(pos, WizardryBlocks.petrified_stone.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 2); - ((TileEntityStatue)world.getTileEntity(pos)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - - world.setBlockState(pos.up(), WizardryBlocks.petrified_stone.getDefaultState()); - if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 2); - } - target.getEntityData().setBoolean(NBT_KEY, true); - target.setDead(); - } - // Tall mobs like endermen - else if(WizardryUtilities.canBlockBeReplaced(world, pos) - && WizardryUtilities.canBlockBeReplaced(world, pos.up()) - && WizardryUtilities.canBlockBeReplaced(world, pos.up(2))){ - world.setBlockState(pos, WizardryBlocks.petrified_stone.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 3); - ((TileEntityStatue)world.getTileEntity(pos)) - .setLifetime((int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - - world.setBlockState(pos.up(), WizardryBlocks.petrified_stone.getDefaultState()); - if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 3); - } - - world.setBlockState(pos.up(2), WizardryBlocks.petrified_stone.getDefaultState()); - if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(target, 3, 3); - } - target.getEntityData().setBoolean(NBT_KEY, true); - target.setDead(); + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(target instanceof EntityLiving && !world.isRemote){ + // Unchecked cast is fine because the block is a static final field + if(((BlockStatue)WizardryBlocks.petrified_stone).convertToStatue((EntityLiving)target, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)))){ + + return true; } } - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, - 0.1f, 0.1f, 0.1f); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 0.2f, 0.2f, 0.2f); - } - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(0.2f, 0.2f, 0.2f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0.1f, 0.1f).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/PhaseStep.java b/src/main/java/electroblob/wizardry/spell/PhaseStep.java index c7f21d7b..2a7ad268 100644 --- a/src/main/java/electroblob/wizardry/spell/PhaseStep.java +++ b/src/main/java/electroblob/wizardry/spell/PhaseStep.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; public class PhaseStep extends Spell { public PhaseStep(){ - super(Tier.ADVANCED, 35, Element.SORCERY, "phase_step", SpellType.UTILITY, 40, EnumAction.NONE, false); + super("phase_step", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 35, 40, EnumAction.NONE, false); } @Override @@ -28,7 +28,7 @@ public class PhaseStep extends Spell { // Phase step does not gain range from range multiplier, instead it increases the thickness // of the wall you can teleport through. - RayTraceResult rayTrace = WizardryUtilities.rayTrace(5, world, caster, false); + RayTraceResult rayTrace = WizardryUtilities.standardBlockRayTrace(world, caster, 5, false); if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ @@ -71,7 +71,7 @@ public class PhaseStep extends Spell { if(world.isRemote){ for(int i = 0; i < 10; i++){ double dx1 = caster.posX; - double dy1 = WizardryUtilities.getPlayerEyesPos(caster) - 1.5 + 2 * world.rand.nextFloat(); + double dy1 = caster.getEntityBoundingBox().minY + 2 * world.rand.nextFloat(); double dz1 = caster.posZ; world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); diff --git a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java index 03d4ba9e..f9f87a10 100644 --- a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java +++ b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java @@ -2,15 +2,15 @@ package electroblob.wizardry.spell; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -25,42 +25,48 @@ import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; public class PlagueOfDarkness extends Spell { + + private static final double BASE_RADIUS = 5; + private static final float BASE_DAMAGE = 8; + private static final int BASE_DURATION = 140; public PlagueOfDarkness(){ - super(Tier.MASTER, 75, Element.NECROMANCY, "plague_of_darkness", SpellType.ATTACK, 200, EnumAction.BOW, false); + super("plague_of_darkness", Tier.MASTER, Element.NECROMANCY, SpellType.ATTACK, 75, 200, EnumAction.BOW, false); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ List targets = WizardryUtilities.getEntitiesWithinRadius( - 5.0d * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + BASE_RADIUS * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); for(EntityLivingBase target : targets){ if(WizardryUtilities.isValidTarget(caster, target) && !MagicDamage.isEntityImmune(DamageType.WITHER, target)){ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), - 8.0f * modifiers.get(SpellModifiers.DAMAGE)); + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); target.addPotionEffect(new PotionEffect(MobEffects.WITHER, - (int)(140 * modifiers.get(WizardryItems.duration_upgrade)), 2)); + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 2)); } } if(world.isRemote){ + double particleX, particleZ; + for(int i = 0; i < 40 * modifiers.get(WizardryItems.blast_upgrade); i++){ + particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, particleX, - WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, particleX - caster.posX, 0, - particleZ - caster.posZ, 0, 0.1f, 0.0f, 0.0f); + 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); + particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, particleX, - WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, particleX - caster.posX, 0, - particleZ - caster.posZ, 30, 0.1f, 0.0f, 0.05f); + 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); + particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); if(block != null){ @@ -69,9 +75,9 @@ public class PlagueOfDarkness extends Spell { } } } + caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_DEATH, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_DEATH, 1, 1 + 0.2f * world.rand.nextFloat()); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/PocketFurnace.java b/src/main/java/electroblob/wizardry/spell/PocketFurnace.java index 78bc3342..dbcb7312 100644 --- a/src/main/java/electroblob/wizardry/spell/PocketFurnace.java +++ b/src/main/java/electroblob/wizardry/spell/PocketFurnace.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; public class PocketFurnace extends Spell { public PocketFurnace(){ - super(Tier.APPRENTICE, 30, Element.FIRE, "pocket_furnace", SpellType.UTILITY, 40, EnumAction.BOW, false); + super("pocket_furnace", Tier.APPRENTICE, Element.FIRE, SpellType.UTILITY, 30, 40, EnumAction.BOW, false); } @Override @@ -60,7 +60,7 @@ public class PocketFurnace extends Spell { if(world.isRemote){ for(int i = 0; i < 10; i++){ double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); + double y1 = (double)((float)caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5F + world.rand.nextFloat()); double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); world.spawnParticle(EnumParticleTypes.FLAME, x1, y1, z1, 0, 0.01F, 0); } diff --git a/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java b/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java index 9f047445..fc5e9e6a 100644 --- a/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java +++ b/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; public class PocketWorkbench extends Spell { public PocketWorkbench(){ - super(Tier.APPRENTICE, 30, Element.SORCERY, "pocket_workbench", SpellType.UTILITY, 40, EnumAction.BOW, false); + super("pocket_workbench", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 30, 40, EnumAction.BOW, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Poison.java b/src/main/java/electroblob/wizardry/spell/Poison.java index 8fd97d21..0a81900e 100644 --- a/src/main/java/electroblob/wizardry/spell/Poison.java +++ b/src/main/java/electroblob/wizardry/spell/Poison.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -8,110 +7,26 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class Poison extends Spell { +public class Poison extends SpellRay { + + private static final int BASE_DURATION = 200; public Poison(){ - super(Tier.APPRENTICE, 10, Element.EARTH, "poison", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; - // Has no effect on undead or spiders. - if(MagicDamage.isEntityImmune(DamageType.POISON, target)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); - }else{ - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), - 1.0f * modifiers.get(SpellModifiers.DAMAGE)); - target.addPotionEffect(new PotionEffect(MobEffects.POISON, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), 1)); - } - } - - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, - 0.3f, 0.7f, 0.0f); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 0.1f, 0.4f, 0.0f); - } - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - // Has no effect on undead or spiders. - if(!MagicDamage.isEntityImmune(DamageType.POISON, target) && !world.isRemote){ - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), - 1.0f * modifiers.get(SpellModifiers.DAMAGE)); - target.addPotionEffect(new PotionEffect(MobEffects.POISON, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), 1)); - } - - if(world.isRemote){ - - double dx = (target.posX - caster.posX) / caster.getDistance(target); - double dy = (target.posY - caster.posY) / caster.getDistance(target); - double dz = (target.posZ - caster.posZ) / caster.getDistance(target); - - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - - double x1 = caster.posX + dx * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 0, 0.3f, 0.7f, 0.0f); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 0.1f, 0.4f, 0.0f); - } - } - - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - return false; + super("poison", Tier.APPRENTICE, Element.EARTH, SpellType.ATTACK, 10, 20, false, 10, WizardrySounds.SPELL_ICE); + this.soundValues(1, 1.1f, 0.2f); } @Override @@ -119,4 +34,42 @@ public class Poison extends Spell { return true; } + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + // Has no effect on undead or spiders. + if(MagicDamage.isEntityImmune(DamageType.POISON, target)){ + if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted())); + }else{ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), + 1 * modifiers.get(SpellModifiers.POTENCY)); + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.POISON, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1)); + } + + return true; + } + + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.3f, 0.7f, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(0.1f, 0.4f, 0).spawn(world); + } + } diff --git a/src/main/java/electroblob/wizardry/spell/PoisonBomb.java b/src/main/java/electroblob/wizardry/spell/PoisonBomb.java deleted file mode 100644 index d4e51911..00000000 --- a/src/main/java/electroblob/wizardry/spell/PoisonBomb.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityPoisonBomb; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class PoisonBomb extends Spell { - - public PoisonBomb(){ - super(Tier.APPRENTICE, 15, Element.EARTH, "poison_bomb", SpellType.ATTACK, 25, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityPoisonBomb poisonbomb = new EntityPoisonBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - world.spawnEntity(poisonbomb); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityPoisonBomb poisonbomb = new EntityPoisonBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - poisonbomb.directTowards(target, 1.5f); - world.spawnEntity(poisonbomb); - } - - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java index 0af5b579..d5aa5028 100644 --- a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java +++ b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java @@ -1,45 +1,39 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.world.World; -public class ReplenishHunger extends Spell { +public class ReplenishHunger extends SpellBuff { public ReplenishHunger(){ - super(Tier.APPRENTICE, 10, Element.HEALING, "replenish_hunger", SpellType.UTILITY, 30, EnumAction.BOW, false); + super("replenish_hunger", Tier.APPRENTICE, Element.HEALING, SpellType.BUFF, 10, 30, WizardrySounds.SPELL_HEAL, 1, 0.7f, 0.3f); + this.soundValues(0.7f, 1.2f, 0.4f); } - + + @Override public boolean canBeCastByNPCs(){ return false; } + + @Override + protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ + return true; // In this case the best solution is to remove the functionality of this method and override cast. + } + @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(caster.getFoodStats().needFood()){ - int foodAmount = (int)(6 * modifiers.get(SpellModifiers.DAMAGE)); + int foodAmount = (int)(4 * modifiers.get(SpellModifiers.POTENCY)); // Fixed issue #6: Changed to addStats, since setFoodLevel is client-side only caster.getFoodStats().addStats(foodAmount, foodAmount * 0.1f); - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F - + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 1.0f, 0.7f, 0.3f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; + return super.cast(world, caster, hand, ticksInUse, modifiers); } + return false; } diff --git a/src/main/java/electroblob/wizardry/spell/RingOfFire.java b/src/main/java/electroblob/wizardry/spell/RingOfFire.java deleted file mode 100644 index 1d95f216..00000000 --- a/src/main/java/electroblob/wizardry/spell/RingOfFire.java +++ /dev/null @@ -1,74 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityFireRing; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class RingOfFire extends Spell { - - public RingOfFire(){ - super(Tier.ADVANCED, 30, Element.FIRE, "ring_of_fire", SpellType.ATTACK, 100, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(caster.onGround){ - if(!world.isRemote){ - EntityFireRing firering = new EntityFireRing(world, caster.posX, caster.posY, caster.posZ, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(firering); - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - return true; - } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - if(caster.onGround - && world.getEntitiesWithinAABB(EntityFireRing.class, caster.getEntityBoundingBox()).isEmpty()){ - if(!world.isRemote){ - EntityFireRing firering = new EntityFireRing(world, caster.posX, caster.posY, caster.posZ, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(firering); - } - - caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - return true; - } - return false; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/ShadowWard.java b/src/main/java/electroblob/wizardry/spell/ShadowWard.java index 594da63e..6c1db4c4 100644 --- a/src/main/java/electroblob/wizardry/spell/ShadowWard.java +++ b/src/main/java/electroblob/wizardry/spell/ShadowWard.java @@ -27,7 +27,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class ShadowWard extends Spell { public ShadowWard(){ - super(Tier.ADVANCED, 10, Element.NECROMANCY, "shadow_ward", SpellType.DEFENCE, 0, EnumAction.BLOCK, true); + super("shadow_ward", Tier.ADVANCED, Element.NECROMANCY, SpellType.DEFENCE, 10, 0, EnumAction.BLOCK, true); } @Override @@ -37,7 +37,7 @@ public class ShadowWard extends Spell { double dx = -1 + 2 * world.rand.nextFloat(); double dy = -1 + world.rand.nextFloat(); double dz = -1 + 2 * world.rand.nextFloat(); - world.spawnParticle(EnumParticleTypes.PORTAL, caster.posX, WizardryUtilities.getPlayerEyesPos(caster), caster.posZ, dx, dy, dz); + world.spawnParticle(EnumParticleTypes.PORTAL, caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight(), caster.posZ, dx, dy, dz); } if(ticksInUse % 50 == 0){ diff --git a/src/main/java/electroblob/wizardry/spell/Shield.java b/src/main/java/electroblob/wizardry/spell/Shield.java index 0b974fff..dac072c6 100644 --- a/src/main/java/electroblob/wizardry/spell/Shield.java +++ b/src/main/java/electroblob/wizardry/spell/Shield.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; public class Shield extends Spell { public Shield(){ - super(Tier.APPRENTICE, 5, Element.HEALING, "shield", SpellType.DEFENCE, 0, EnumAction.BLOCK, true); + super("shield", Tier.APPRENTICE, Element.HEALING, SpellType.DEFENCE, 5, 0, EnumAction.BLOCK, true); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Shockwave.java b/src/main/java/electroblob/wizardry/spell/Shockwave.java index e1a63679..52bf90a8 100644 --- a/src/main/java/electroblob/wizardry/spell/Shockwave.java +++ b/src/main/java/electroblob/wizardry/spell/Shockwave.java @@ -2,7 +2,6 @@ package electroblob.wizardry.spell; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -10,8 +9,9 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -26,22 +26,25 @@ import net.minecraft.world.World; public class Shockwave extends Spell { + private static final double BASE_RADIUS = 5; + private static final float BASE_DAMAGE = 8; + public Shockwave(){ - super(Tier.MASTER, 65, Element.SORCERY, "shockwave", SpellType.ATTACK, 150, EnumAction.BOW, false); + super("shockwave", Tier.MASTER, Element.SORCERY, SpellType.ATTACK, 65, 150, EnumAction.BOW, false); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ List targets = WizardryUtilities.getEntitiesWithinRadius( - 5.0d * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + BASE_RADIUS * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); for(EntityLivingBase target : targets){ if(WizardryUtilities.isValidTarget(caster, target)){ // Damage increases closer to player up to a maximum of 4 hearts (at 1 block distance). - float damage = Math.min(8.0f / target.getDistance(caster), 8.0f); + float damage = Math.min(BASE_DAMAGE / target.getDistance(caster), BASE_DAMAGE); target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST), - damage * modifiers.get(SpellModifiers.DAMAGE)); + damage * modifiers.get(SpellModifiers.POTENCY)); if(!world.isRemote){ @@ -65,23 +68,25 @@ public class Shockwave extends Spell { } } } + if(world.isRemote){ double particleX, particleZ; + for(int i = 0; i < 40; i++){ + particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, particleX, - WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, particleX - caster.posX, 0, - particleZ - caster.posZ, 30, 0.8f, 0.8f, 1.0f); + 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); + particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, particleX, - WizardryUtilities.getPlayerEyesPos(caster) - 1.5, particleZ, particleX - caster.posX, 0, - particleZ - caster.posZ, 30, 0.9f, 0.9f, 0.9f); + 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); + particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); if(block != null){ @@ -94,6 +99,7 @@ public class Shockwave extends Spell { caster.getEntityBoundingBox().minY + 0.1, caster.posZ, 0, 0, 0); } + caster.swingArm(hand); WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 1.0f, 0.7f); WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 2.0f, 0.3f); diff --git a/src/main/java/electroblob/wizardry/spell/SilverfishSwarm.java b/src/main/java/electroblob/wizardry/spell/SilverfishSwarm.java deleted file mode 100644 index d626418e..00000000 --- a/src/main/java/electroblob/wizardry/spell/SilverfishSwarm.java +++ /dev/null @@ -1,49 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntitySilverfishMinion; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SilverfishSwarm extends Spell { - - public SilverfishSwarm(){ - super(Tier.MASTER, 80, Element.EARTH, "silverfish_swarm", SpellType.MINION, 300, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - for(int i = 0; i < 20; i++){ - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); - // The spell instantly fails if no space was found (see javadoc for the above method). - if(pos == null) return false; - - EntitySilverfishMinion silverfish = new EntitySilverfishMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(silverfish); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - // Can't possibly get this far if nothing was spawned. - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SixthSense.java b/src/main/java/electroblob/wizardry/spell/SixthSense.java index b33ac6c9..a7d731bf 100644 --- a/src/main/java/electroblob/wizardry/spell/SixthSense.java +++ b/src/main/java/electroblob/wizardry/spell/SixthSense.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; public class SixthSense extends Spell { public SixthSense(){ - super(Tier.APPRENTICE, 20, Element.EARTH, "sixth_sense", SpellType.UTILITY, 100, EnumAction.BOW, false); + super("sixth_sense", Tier.APPRENTICE, Element.EARTH, SpellType.BUFF, 20, 100, EnumAction.BOW, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Slime.java b/src/main/java/electroblob/wizardry/spell/Slime.java index b1569eab..4b04b83d 100644 --- a/src/main/java/electroblob/wizardry/spell/Slime.java +++ b/src/main/java/electroblob/wizardry/spell/Slime.java @@ -1,6 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -8,119 +7,87 @@ import electroblob.wizardry.entity.living.EntityMagicSlime; import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntitySkeleton; import net.minecraft.entity.monster.EntitySlime; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class Slime extends Spell { +public class Slime extends SpellRay { + + private static final int BASE_DURATION = 200; public Slime(){ - super(Tier.ADVANCED, 20, Element.EARTH, "slime", SpellType.ATTACK, 50, EnumAction.NONE, false); + super("slime", Tier.ADVANCED, Element.EARTH, SpellType.ATTACK, 20, 50, false, 8, WizardrySounds.SPELL_ICE); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + // This spell uses more than one sound, so this is required... + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SLIME_ATTACK, 1.0F, 0.5F); + return flag; + } - Vec3d look = caster.getLookVec(); + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag) caster.playSound(SoundEvents.ENTITY_SLIME_ATTACK, 1.0F, 0.5F); + return flag; + } - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 8 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.entityHit != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target) && !(target instanceof EntityMagicSlime)){ if(target instanceof EntitySlime){ if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted())); - }else if(!(target instanceof EntityMagicSlime)){ + }else{ - if(target instanceof EntitySkeleton) WizardryAdvancementTriggers.slime_skeleton.triggerFor(caster); + if(target instanceof EntitySkeleton && caster instanceof EntityPlayer) + WizardryAdvancementTriggers.slime_skeleton.triggerFor((EntityPlayer)caster); if(!world.isRemote){ - EntityMagicSlime slime = new EntityMagicSlime(world, caster, target, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade))); + EntityMagicSlime slime = new EntityMagicSlime(world, caster, (EntityLivingBase)target, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); world.spawnEntity(slime); } } - } - - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - world.spawnParticle(EnumParticleTypes.SLIME, x1, y1, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, - 0.2f, 0.8f, 0.1f); - } - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SLIME_ATTACK, 1.0F, 0.5F); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null && !(target instanceof EntitySlime) && !(target instanceof EntityMagicSlime)){ - - if(!world.isRemote){ - EntityMagicSlime slime = new EntityMagicSlime(world, caster, target, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(slime); - } - - if(world.isRemote){ - - double dx = (target.posX - caster.posX) / caster.getDistance(target); - double dy = (target.posY - caster.posY) / caster.getDistance(target); - double dz = (target.posZ - caster.posZ) / caster.getDistance(target); - - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - - double x1 = caster.posX + dx * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - world.spawnParticle(EnumParticleTypes.SLIME, x1, y1, z1, 0.0d, 0.0d, 0.0d); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 0, 0.2f, 0.8f, 0.1f); - } - } - - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_SLIME_ATTACK, 1.0F, 0.5F); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, 1.0F); + return true; - } - + return false; } @Override - public boolean canBeCastByNPCs(){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + world.spawnParticle(EnumParticleTypes.SLIME, x, y, z, 0, 0, 0); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.2f, 0.8f, 0.1f).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/SmokeBomb.java b/src/main/java/electroblob/wizardry/spell/SmokeBomb.java deleted file mode 100644 index c10a4b5b..00000000 --- a/src/main/java/electroblob/wizardry/spell/SmokeBomb.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntitySmokeBomb; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class SmokeBomb extends Spell { - - public SmokeBomb(){ - super(Tier.BASIC, 10, Element.FIRE, "smoke_bomb", SpellType.ATTACK, 20, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntitySmokeBomb smokebomb = new EntitySmokeBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - world.spawnEntity(smokebomb); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntitySmokeBomb smokebomb = new EntitySmokeBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - smokebomb.directTowards(target, 1.5f); - world.spawnEntity(smokebomb); - } - - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Snare.java b/src/main/java/electroblob/wizardry/spell/Snare.java index 64fb6f55..d7e64753 100644 --- a/src/main/java/electroblob/wizardry/spell/Snare.java +++ b/src/main/java/electroblob/wizardry/spell/Snare.java @@ -1,78 +1,62 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryBlocks; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.tileentity.TileEntityPlayerSave; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class Snare extends Spell { +public class Snare extends SpellRay { public Snare(){ - super(Tier.BASIC, 10, Element.EARTH, "snare", SpellType.ATTACK, 10, EnumAction.NONE, false); + super("snare", Tier.BASIC, Element.EARTH, SpellType.ATTACK, 10, 10, false, 10, SoundEvents.BLOCK_GRASS_PLACE); + this.soundValues(1, 1.4f, 0.4f); + this.ignoreEntities(true); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(10 * modifiers.get(WizardryItems.range_upgrade), world, - caster, true); - - // Gets block the player is looking at and places snare - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = rayTrace.getBlockPos(); - - if(rayTrace.sideHit == EnumFacing.UP && world.isSideSolid(pos, EnumFacing.UP) - && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ - - if(!world.isRemote){ - world.setBlockState(pos.up(), WizardryBlocks.snare.getDefaultState()); - ((TileEntityPlayerSave)world.getTileEntity(pos.up())).setCaster(caster); - } - - double dx = pos.getX() + 0.5 - caster.posX; - double dy = pos.getY() + 1.5 - (caster.posY + caster.height / 2); - double dz = pos.getZ() + 0.5 - caster.posZ; - - if(world.isRemote){ - for(int i = 1; i < 5; i++){ - float brightness = world.rand.nextFloat() / 4; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) - + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0.0d, 0.0d, 0.0d, - 20 + world.rand.nextInt(8), brightness, brightness + 0.1f, 0.0f); - Wizardry.proxy.spawnParticle(Type.LEAF, world, - caster.posX + (i * (dx / 5)) + world.rand.nextFloat() / 5, - WizardryUtilities.getPlayerEyesPos(caster) + (i * (dy / 5)) - + world.rand.nextFloat() / 5, - caster.posZ + (i * (dz / 5)) + world.rand.nextFloat() / 5, 0, -0.01, 0, - 40 + world.rand.nextInt(10)); - } - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_GRASS_PLACE, 1.0F, - world.rand.nextFloat() * 0.4F + 1.2F); - return true; - } - } + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(side == EnumFacing.UP && world.isSideSolid(pos, EnumFacing.UP) + && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + + if(!world.isRemote){ + world.setBlockState(pos.up(), WizardryBlocks.snare.getDefaultState()); + ((TileEntityPlayerSave)world.getTileEntity(pos.up())).setCaster(caster); + } + + return true; + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + float brightness = world.rand.nextFloat() * 0.25f; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(20 + world.rand.nextInt(8)) + .colour(brightness, brightness + 0.1f, 0).spawn(world); + ParticleBuilder.create(Type.LEAF).pos(x, y, z).vel(0, -0.01, 0).lifetime(40 + world.rand.nextInt(10)).spawn(world); + } + } diff --git a/src/main/java/electroblob/wizardry/spell/Snowball.java b/src/main/java/electroblob/wizardry/spell/Snowball.java index 0f7f71e5..1e4e901a 100644 --- a/src/main/java/electroblob/wizardry/spell/Snowball.java +++ b/src/main/java/electroblob/wizardry/spell/Snowball.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; public class Snowball extends Spell { public Snowball(){ - super(Tier.BASIC, 1, Element.ICE, "snowball", SpellType.ATTACK, 1, EnumAction.NONE, false); + super("snowball", Tier.BASIC, Element.ICE, SpellType.ATTACK, 1, 1, EnumAction.NONE, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/SparkBomb.java b/src/main/java/electroblob/wizardry/spell/SparkBomb.java deleted file mode 100644 index b8adbdb5..00000000 --- a/src/main/java/electroblob/wizardry/spell/SparkBomb.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntitySparkBomb; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class SparkBomb extends Spell { - - public SparkBomb(){ - super(Tier.APPRENTICE, 15, Element.LIGHTNING, "spark_bomb", SpellType.ATTACK, 25, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntitySparkBomb sparkBomb = new EntitySparkBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - world.spawnEntity(sparkBomb); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntitySparkBomb sparkBomb = new EntitySparkBomb(world, caster, modifiers.get(SpellModifiers.DAMAGE), - modifiers.get(WizardryItems.blast_upgrade)); - sparkBomb.directTowards(target, 1.5f); - world.spawnEntity(sparkBomb); - } - - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SpectralPathway.java b/src/main/java/electroblob/wizardry/spell/SpectralPathway.java index db2b3c59..5591448b 100644 --- a/src/main/java/electroblob/wizardry/spell/SpectralPathway.java +++ b/src/main/java/electroblob/wizardry/spell/SpectralPathway.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; public class SpectralPathway extends Spell { public SpectralPathway(){ - super(Tier.ADVANCED, 40, Element.SORCERY, "spectral_pathway", SpellType.UTILITY, 300, EnumAction.BOW, false); + super("spectral_pathway", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 40, 300, EnumAction.BOW, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Spell.java b/src/main/java/electroblob/wizardry/spell/Spell.java index f15e49dd..b7b1a930 100644 --- a/src/main/java/electroblob/wizardry/spell/Spell.java +++ b/src/main/java/electroblob/wizardry/spell/Spell.java @@ -79,16 +79,18 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C /** Forge registry-based replacement for the internal spells list. */ public static IForgeRegistry registry; - /** The tier this spell belongs to. */ - public final Tier tier; - /** Mana cost of the spell. If it is a continuous spell the cost is per second. */ - public final int cost; - /** The element this spell belongs to. */ - public final Element element; + /** Mod ID of the mod that added this spell; defaults to {@link Wizardry#MODID} if not specified. */ + private final String modID; /** The unlocalised name of the spell. */ private final String unlocalisedName; + /** The tier this spell belongs to. */ + public final Tier tier; + /** The element this spell belongs to. */ + public final Element element; /** The type of spell this is classified as. */ public final SpellType type; + /** Mana cost of the spell. If it is a continuous spell the cost is per second. */ + public final int cost; /** Cooldown for the spell in ticks */ public final int cooldown; /** The action the player does when this spell is cast. */ @@ -98,66 +100,64 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C /** ResourceLocation of the spell icon. */ private final ResourceLocation icon; - /** Mod ID of the mod that added this spell; defaults to {@link Wizardry#MODID} if not specified. */ - private final String modID; /** * False if the spell has been disabled in the config file, true otherwise. This is now encapsulated to stop it * being fiddled with. */ - private boolean isEnabled = true; + private boolean enabled = true; /** * This constructor should be called from any subclasses, either feeding in the constants directly or through their * own constructor from wherever the spell is registered. This is the constructor for wizardry's own spells; spells * added by other mods should use - * {@link Spell#Spell(Tier, int, Element, String, SpellType, int, EnumAction, boolean, String)}. - * - * @param tier The tier this spell belongs to. - * @param cost The amount of mana used to cast the spell. If this is a continuous spell, it represents mana cost per - * second and should be a multiple of 5. - * @param element The element this spell belongs to. + * {@link Spell#Spell(String, String, Tier, Element, SpellType, int, int, EnumAction, boolean)}. * @param name The registry name of the spell. This will also be the name of the icon file. The spell's * unlocalised name will be a resource location with the format [modid]:[name]. + * @param tier The tier this spell belongs to. + * @param element The element this spell belongs to. + * @param type The type of spell this is classified as. + * @param cost The amount of mana used to cast the spell. If this is a continuous spell, it represents mana cost per + * second and should be a multiple of 5. * @param cooldown The cooldown time for this spell in ticks. * @param action The vanilla usage action to be displayed when casting this spell. * @param isContinuous Whether this spell is continuous, meaning you cast it for a length of time by holding the * right mouse button. */ - public Spell(Tier tier, int cost, Element element, String name, SpellType type, int cooldown, EnumAction action, + public Spell(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, boolean isContinuous){ - this(tier, cost, element, name, type, cooldown, action, isContinuous, Wizardry.MODID); + this(Wizardry.MODID, name, tier, element, type, cost, cooldown, action, isContinuous); } /** * This constructor should be called from any subclasses, either feeding in the constants directly or through their * own constructor from wherever the spell is registered. - * - * @param tier The tier this spell belongs to. - * @param cost The amount of mana used to cast the spell. If this is a continuous spell, it represents mana cost per - * second and should be a multiple of 5. - * @param element The element this spell belongs to. + * @param modID The mod id of the mod that added this spell. This allows wizardry to use the correct file path for + * the spell icon, and also more generally to distinguish between original and addon spells. * @param name The registry name of the spell, excluding the mod id. This will also be the name of the icon * file. The spell's unlocalised name will be a resource location with the format [modid]:[name]. + * @param tier The tier this spell belongs to. + * @param element The element this spell belongs to. + * @param type The type of spell this is classified as. + * @param cost The amount of mana used to cast the spell. If this is a continuous spell, it represents mana cost per + * second and should be a multiple of 5. * @param cooldown The cooldown time for this spell in ticks. * @param action The vanilla usage action to be displayed when casting this spell (see {@link}EnumAction) * @param isContinuous Whether this spell is continuous, meaning you cast it for a length of time by holding the * right mouse button. - * @param modID The mod id of the mod that added this spell. This allows wizardry to use the correct file path for - * the spell icon, and also more generally to distinguish between original and addon spells. */ - public Spell(Tier tier, int cost, Element element, String name, SpellType type, int cooldown, EnumAction action, - boolean isContinuous, String modID){ - this.tier = tier; - this.cost = cost; - this.element = element; - this.type = type; - this.cooldown = cooldown; - this.action = action; - this.isContinuous = isContinuous; + public Spell(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, + EnumAction action, boolean isContinuous){ this.modID = modID; this.setRegistryName(modID, name); this.unlocalisedName = this.getRegistryName().toString(); + this.tier = tier; + this.element = element; + this.type = type; + this.cost = cost; + this.cooldown = cooldown; + this.action = action; + this.isContinuous = isContinuous; this.icon = new ResourceLocation(this.modID, "textures/spells/" + name + ".png"); } @@ -187,8 +187,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * {@code new SpellModifiers()}. * @return True if the spell succeeded and mana should be used up, false if not. */ - public abstract boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, - SpellModifiers modifiers); + public abstract boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers); /** * Casts the spell, but with an EntityLiving as the caster. Each subclass can optionally override this method and @@ -337,12 +336,12 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C /** Returns whether the spell is enabled in the config. */ public final boolean isEnabled(){ - return isEnabled; + return enabled; } /** Sets whether the spell is enabled or not. */ public final void setEnabled(boolean isEnabled){ - this.isEnabled = isEnabled; + this.enabled = isEnabled; } // Spells are sorted according to tier and element. Where several spells have the same tier and element, @@ -472,5 +471,5 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C return spell.isEnabled() && (this.tier == null || spell.tier == this.tier) && (this.element == null || spell.element == this.element); } - }; + } } diff --git a/src/main/java/electroblob/wizardry/spell/SpellAreaEffect.java b/src/main/java/electroblob/wizardry/spell/SpellAreaEffect.java new file mode 100644 index 00000000..3194da2d --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpellAreaEffect.java @@ -0,0 +1,140 @@ +package electroblob.wizardry.spell; + +import java.util.List; + +import javax.annotation.Nullable; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +public abstract class SpellAreaEffect extends Spell { + + // TODO: This class doesn't really work as it is right now, it needs rethinking. The aim is to try and have all the + // different casting methods call a single (abstract) positional method to do the actual AoE. + + /** The base radius of this spell's area of effect. */ + protected final double baseRadius; + /** The sound that gets played when this spell is cast. */ + @Nullable + protected final SoundEvent sound; + + /** The average number of particles to spawn per block in this spell's area of effect. */ + protected float particleDensity = 0.65f; + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + + public SpellAreaEffect(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, double baseRadius, SoundEvent sound){ + this(Wizardry.MODID, name, tier, element, type, cost, cooldown, action, baseRadius, sound); + } + + public SpellAreaEffect(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, double baseRadius, SoundEvent sound){ + super(modID, name, tier, element, type, cost, cooldown, action, false); + this.baseRadius = baseRadius; + this.sound = sound; + } + + /** + * Sets the sound parameters for this spell. + * @param volume + * @param pitch + * @param pitchVariation + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellAreaEffect soundValues(float volume, float pitch, float pitchVariation) { + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; + } + + /** + * Sets the number of particles to spawn per block for this spell. + * @param particleDensity The average number of particles to spawn per block in this spell's area of effect. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellAreaEffect particleDensity(float particleDensity) { + this.particleDensity = particleDensity; + return this; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + List targets = WizardryUtilities.getEntitiesWithinRadius( + baseRadius * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + + targets.removeIf(target -> !WizardryUtilities.isValidTarget(caster, target)); + + for(EntityLivingBase target : targets){ + affectEntity(world, caster, target, modifiers); + } + + if(world.isRemote){ + spawnParticleEffect(world, caster, modifiers); + } + + if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + + } + + /** + * Called to do something to each entity within the spell's area of effect. + * @param world The world in which the spell was cast. + * @param caster The entity that cast the spell. + * @param target The entity to do something to. + * @param modifiers The modifiers the spell was cast with. + */ + protected abstract void affectEntity(World world, EntityLivingBase caster, EntityLivingBase target, SpellModifiers modifiers); + + /** + * Called to spawn the spell's particle effect. By default, this generates a set of random points within the spell's + * area of effect and calls {@link SpellAreaEffect#spawnParticle(World, double, double, double)} at each to spawn + * the individual particles. Only called client-side. Override to add a custom particle effect. + * @param world + * @param caster + * @param modifiers + */ + protected void spawnParticleEffect(World world, EntityLivingBase caster, SpellModifiers modifiers){ + + double maxRadius = baseRadius * modifiers.get(WizardryItems.blast_upgrade); + int particleCount = (int)Math.round(particleDensity * Math.PI * maxRadius * maxRadius); + + for(int i=0; i + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + *

+ * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + * + * @author Electroblob + * @since Wizardry 4.2 + */ +public class SpellArrow extends Spell { + + // The general contract for these spell subtypes is that any required parameters are set via the constructor and are + // final, whereas any non-critical parameters are set via chainable setters with sensible defaults if not. For example, + // the actual sound to play is required, but it makes sense for its volume and pitch to default to 1 if unspecified. + + /** A factory that creates projectile entities. */ + protected final Function arrowFactory; + /** The base range (projectile speed) of this spell. */ + protected final float baseRange; + /** The sound that gets played when this spell is cast, or null if the spell plays no sound. */ + @Nullable + protected final SoundEvent sound; + + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + + public SpellArrow(String name, Tier tier, Element element, int cost, int cooldown, Function arrowFactory, float baseRange, SoundEvent sound) { + this(Wizardry.MODID, name, tier, element, cost, cooldown, arrowFactory, baseRange, sound); + } + + public SpellArrow(String modID, String name, Tier tier, Element element, int cost, int cooldown, Function arrowFactory, float baseRange, SoundEvent sound){ + super(modID, name, tier, element, SpellType.PROJECTILE, cost, cooldown, EnumAction.NONE, false); + this.arrowFactory = arrowFactory; + this.baseRange = baseRange; + this.sound = sound; + } + + /** + * Sets the sound parameters for this spell. + * @param volume + * @param pitch + * @param pitchVariation + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellArrow soundValues(float volume, float pitch, float pitchVariation) { + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; + } + + @Override public boolean doesSpellRequirePacket(){ return false; } + + @Override public boolean canBeCastByNPCs(){ return true; } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(!world.isRemote){ + // Creates a projectile from the supplied factory + EntityMagicArrow projectile = arrowFactory.apply(world); + // Sets the necessary parameters + projectile.aim(caster, baseRange * modifiers.get(WizardryItems.range_upgrade)); + projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + // Spawns the projectile in the world + world.spawnEntity(projectile); + } + + caster.swingArm(hand); + + if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + // Creates a projectile from the supplied factory + EntityMagicArrow projectile = arrowFactory.apply(world); + // Sets the necessary parameters + int aimingError = caster instanceof ISpellCaster ? ((ISpellCaster)caster).getAimingError(world.getDifficulty()) + : WizardryUtilities.getDefaultAimingError(world.getDifficulty()); + projectile.aim(caster, target, baseRange * modifiers.get(WizardryItems.range_upgrade), aimingError); + projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + // Spawns the projectile in the world + world.spawnEntity(projectile); + } + + caster.swingArm(hand); + + if(sound != null) caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + + return true; + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SpellBuff.java b/src/main/java/electroblob/wizardry/spell/SpellBuff.java new file mode 100644 index 00000000..0c91c08f --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpellBuff.java @@ -0,0 +1,153 @@ +package electroblob.wizardry.spell; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.Triple; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; +import net.minecraft.world.World; + +/** + * Generic superclass for all spells which buff their caster. + * This allows all the relevant code to be centralised, since these spells all work in the same way. Usually, a simple + * instantiation of this class is sufficient to create a buff spell; if something extra needs to be done, such as + * applying a non-potion buff, then methods can be overridden (perhaps using an anonymous class) to add the required + * functionality. + *

+ * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + *

+ * By default, this type of spell requires a packet to be sent. {@link Spell#doesSpellRequirePacket()} + * + * @author Electroblob + * @since Wizardry 4.2 + */ +public class SpellBuff extends Spell { + + /** An array of triples representing the parameters of the status effects that this spell applies to its caster. + * These are of the form [effect, base duration, base amplifier]. */ + protected final Triple[] effects; + /** A set of all the different potions (status effects) that this spell applies to its caster. */ + protected final Set potionSet; + /** The sound that gets played when this spell is cast. */ + protected final SoundEvent sound; + /** The RGB colour values of the particles spawned when this spell is cast. */ + protected final float r, g, b; + + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + /** The number of sparkle particles spawned when this spell is cast. Defualts to 10. */ + protected float particleCount = 10; + + @SafeVarargs + public SpellBuff(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, SoundEvent sound, float r, float g, float b, Triple... effects){ + this(Wizardry.MODID, name, tier, element, type, cost, cooldown, sound, r, g, b, effects); + } + + @SafeVarargs + public SpellBuff(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, SoundEvent sound, float r, float g, float b, Triple... effects){ + super(modID, name, tier, element, type, cost, cooldown, EnumAction.BOW, false); + this.sound = sound; + this.effects = effects; + this.r = r; + this.g = g; + this.b = b; + // Pretty sure this is better than iterating over (or streaming) all the elements each time the spell is cast. + this.potionSet = Arrays.stream(effects).map(Triple::getLeft).collect(Collectors.toSet()); + } + + /** + * Sets the sound parameters for this spell. + * @param volume + * @param pitch + * @param pitchVariation + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellBuff soundValues(float volume, float pitch, float pitchVariation) { + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; + } + + /** + * Sets the number of sparkle particles spawned when this spell is cast. + * @param particleCount The number of particles. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellBuff particleCount(int particleCount){ + this.particleCount = particleCount; + return this; + } + + @Override public boolean canBeCastByNPCs(){ return true; } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(!this.applyEffects(caster, modifiers)) return false; + if(world.isRemote) this.spawnParticles(world, caster, modifiers); + WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + // Wizards can only cast a buff spell if they don't already have its effects. + if(caster.getActivePotionMap().keySet().containsAll(potionSet)) return false; + if(!this.applyEffects(caster, modifiers)) return false; + if(world.isRemote) this.spawnParticles(world, caster, modifiers); + caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + /** Actually applies the status effects to the caster. By default, this iterates through the array of effects and + * applies each in turn, multiplying the duration and amplifier by the appropriate modifiers. Particles are always + * hidden and isAmbient is always set to false. Override to do something special, like apply a non-potion buff. + * Returns a boolean to allow subclasses to cause the spell to fail if for some reason the effect cannot be applied + * (for example, {@link Heal} fails if the caster is on full health). */ + protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ + // TODO: Find a good way (if any) of implementing potency modifiers + for(Triple effect : effects){ + caster.addPotionEffect(new PotionEffect(effect.getLeft(), (int)(effect.getMiddle() + * modifiers.get(WizardryItems.duration_upgrade)), effect.getRight(), false, false)); + } + + return true; + } + + /** Spawns buff particles around the caster. Override to add a custom particle effect. Only called client-side. */ + protected void spawnParticles(World world, EntityLivingBase caster, SpellModifiers modifiers){ + + for(int i = 0; i < particleCount; i++){ + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(r, g, b).spawn(world); + } + + Wizardry.proxy.spawnEntityParticle(world, caster, 15, r, g, b); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SpellConjuration.java b/src/main/java/electroblob/wizardry/spell/SpellConjuration.java new file mode 100644 index 00000000..9dd9d068 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpellConjuration.java @@ -0,0 +1,120 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.item.IConjuredItem; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; +import net.minecraft.world.World; + +/** + * Generic superclass for all spells which conjure an item for a certain duration. + * This allows all the relevant code to be centralised, since these spells all work in the same way. Usually, a simple + * instantiation of this class is sufficient to create a conjuration spell; if something extra needs to be done, such as + * a custom particle effect or conjuring the item in a specific slot, then methods can be overridden (perhaps using an + * anonymous class) to add the required functionality. + *

+ * By default, this type of spell cannot be cast by NPCs. {@link Spell#canBeCastByNPCs()} + *

+ * By default, this type of spell requires a packet to be sent. {@link Spell#doesSpellRequirePacket()} + * + * @author Electroblob + * @since Wizardry 4.2 + * @see IConjuredItem + */ +public class SpellConjuration extends Spell { + + /** The item that is conjured by this spell. Should implement {@link IConjuredItem}. */ + protected final Item item; + /** The sound that gets played when this spell is cast. */ + protected final SoundEvent sound; + + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + + public SpellConjuration(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, Item item, SoundEvent sound){ + this(Wizardry.MODID, name, tier, element, type, cost, cooldown, item, sound); + } + + public SpellConjuration(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, Item item, SoundEvent sound){ + super(modID, name, tier, element, type, cost, cooldown, EnumAction.BOW, false); + this.item = item; + this.sound = sound; + } + + /** + * Sets the sound parameters for this spell. + * @param volume + * @param pitch + * @param pitchVariation + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellConjuration soundValues(float volume, float pitch, float pitchVariation) { + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(conjureItem(caster, modifiers)){ + + if(world.isRemote) spawnParticles(world, caster, modifiers); + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1); + return true; + } + + return false; + } + + /** Spawns sparkle particles around the caster. Override to add a custom particle effect. Only called client-side. */ + protected void spawnParticles(World world, EntityLivingBase caster, SpellModifiers modifiers){ + + for(int i=0; i<10; i++){ + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.7f, 0.9f, 1).spawn(world); + } + } + + /** Adds this spell's item to the given player's inventory, placing it in the main hand if the main hand is empty. + * Returns true if the item was successfully added to the player's inventory, false if there as no space or if the + * player already had the item. Override to add special conjuring behaviour. */ + protected boolean conjureItem(EntityPlayer caster, SpellModifiers modifiers){ + + ItemStack stack = new ItemStack(item); + + IConjuredItem.setDurationMultiplier(stack, modifiers.get(WizardryItems.duration_upgrade)); + + if(WizardryUtilities.doesPlayerHaveItem(caster, item)) return false; + + if(caster.getHeldItemMainhand().isEmpty()){ + caster.setHeldItem(EnumHand.MAIN_HAND, stack); + return true; + }else{ + return caster.inventory.addItemStackToInventory(stack); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SpellConstruct.java b/src/main/java/electroblob/wizardry/spell/SpellConstruct.java new file mode 100644 index 00000000..bd3b4ad5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpellConstruct.java @@ -0,0 +1,185 @@ +package electroblob.wizardry.spell; + +import java.util.function.Function; + +import javax.annotation.Nullable; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityMagicConstruct; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; +import net.minecraft.world.World; + +/** + * Generic superclass for all spells which conjure constructs (i.e. instances of {@link EntityMagicConstruct}). + * This allows all the relevant code to be centralised, since these spells all work in a similar way. Usually, a simple + * instantiation of this class is sufficient to create a construct spell; if something extra needs to be done, such as + * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. + * It is encouraged, however, to put extra functionality in the construct entity class instead whenever possible. + *

+ * This class spawns the construct entity at the caster's feet, like ring of fire and healing aura. Use + * {@link SpellConstructRanged} (which extends this class) for spells that spawn constructs at an aimed-at position. + *

+ * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + *

+ * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + * + * @author Electroblob + * @since Wizardry 4.2 + * @see SpellConstructRanged + */ +public class SpellConstruct extends Spell { + + /** A factory that creates projectile entities. */ + protected final Function constructFactory; + /** The base lifetime of the construct created by this spell, or -1 if the construct does not despawn. */ + protected final int baseDuration; + /** The sound that gets played when this spell is cast, or null if the spell plays no sound. */ + @Nullable + protected final SoundEvent sound; + + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + /** Whether the construct must be spawned on the ground. Defaults to false. */ + protected boolean requiresFloor = false; + /** Whether constructs spawned by this spell may overlap. Defaults to false. */ + protected boolean allowOverlap = false; + + public SpellConstruct(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, Function constructFactory, int baseDuration, SoundEvent sound){ + this(Wizardry.MODID, name, tier, element, type, cost, cooldown, action, constructFactory, baseDuration, sound); + } + + public SpellConstruct(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, Function constructFactory, int baseDuration, SoundEvent sound){ + super(modID, name, tier, element, type, cost, cooldown, action, false); + this.constructFactory = constructFactory; + this.baseDuration = baseDuration; + this.sound = sound; + } + + /** + * Sets the sound parameters for this spell. + * @param volume The volume of the sound, relative to 1. + * @param pitch The pitch of the sound, relative to 1. + * @param pitchVariation The pitch variation. The pitch will be set to a random value within this range either side + * of the set pitch value. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellConstruct soundValues(float volume, float pitch, float pitchVariation) { + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; + } + + @Override public boolean doesSpellRequirePacket(){ return false; } + + @Override public boolean canBeCastByNPCs(){ return true; } + + /** + * Sets whether the construct must be spawned on the ground. + * @param requiresFloor True to require that the construct be spawned on the ground, false to allow it in mid-air. + * Defaults to false. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellConstruct floor(boolean requiresFloor){ + this.requiresFloor = requiresFloor; + return this; + } + + /** + * Sets whether constructs spawned by this spell may overlap. + * @param allowOverlap True to allow overlapping, false to prevent it. Defaults to false. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellConstruct overlap(boolean allowOverlap){ + this.allowOverlap = allowOverlap; + return this; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(caster.onGround || !requiresFloor){ + if(!spawnConstruct(world, caster.posX, caster.posY, caster.posZ, caster, modifiers)) return false; + if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + if(caster.onGround || !requiresFloor){ + if(!spawnConstruct(world, caster.posX, caster.posY, caster.posZ, caster, modifiers)) return false; + if(sound != null) caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + } + + return false; + } + + /** + * Actually spawns the construct. By default, spawns the construct at the position of the caster and always returns + * true. Returning false will cause the spell to fail. + * @param world The world to spawn the construct in. + * @param x The x coordinate to spawn the construct at. + * @param y The y coordinate to spawn the construct at. + * @param z The z coordinate to spawn the construct at. + * @param caster The EntityLivingBase that cast this spell. + * @param modifiers The modifiers with which the spell was cast. + * @return false to cause the spell to fail, true to continue with casting. + */ + protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + + if(!world.isRemote){ + // Creates a new constuct using the supplied factory + T construct = constructFactory.apply(world); + // Sets the position of the construct (and initialises its bounding box) + construct.setPosition(x, y, z); + // Prevents overlapping of multiple constructs of the same type. Since we have an instance here this is + // very simple. The trade-off is that we have to create the entity before the spell fails, but unless + // world.spawnEntity(...) is called, its scope is limited to this method so it should be fine. + if(!allowOverlap && !world.getEntitiesWithinAABB(construct.getClass(), caster.getEntityBoundingBox()).isEmpty()) return false; + // Sets the various parameters + construct.setCaster(caster); + construct.lifetime = baseDuration == -1 ? -1 : (int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade)); + construct.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + addConstructExtras(construct, caster, modifiers); + // Spawns the construct in the world + world.spawnEntity(construct); + } + + return true; + } + + /** + * Called just before each construct is spawned. Does nothing by default, but is provided to allow subclasses to call + * extra methods on the spawned entity. This method is only called server-side so cannot be used to spawn particles + * directly. + * @param construct The entity being spawned. + * @param caster The caster of this spell. + * @param modifiers The modifiers this spell was cast with. + */ + // This is the reason this class is generic: it allows subclasses to do whatever they want to their specific entity, + // without needing to cast to it. + protected void addConstructExtras(T construct, EntityLivingBase caster, SpellModifiers modifiers){} + +} diff --git a/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java b/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java new file mode 100644 index 00000000..cac214de --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java @@ -0,0 +1,133 @@ +package electroblob.wizardry.spell; + +import java.util.function.Function; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.construct.EntityMagicConstruct; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +/** + * Generic superclass for all spells which conjure constructs (i.e. instances of {@link EntityMagicConstruct}) at an + * aimed-at position (players and dispensers) or target (non-player spell casters). + * This allows all the relevant code to be centralised, since these spells all work in a similar way. Usually, a simple + * instantiation of this class is sufficient to create a construct spell; if something extra needs to be done, such as + * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. + * It is encouraged, however, to put extra functionality in the construct entity class instead whenever possible. + *

+ * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + *

+ * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + * + * @author Electroblob + * @since Wizardry 4.2 + * @see SpellConstruct + */ +public class SpellConstructRanged extends SpellConstruct { + + /** The base range of this spell. */ + protected final double baseRange; + + public SpellConstructRanged(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, + Function constructFactory, int baseDuration, double baseRange, SoundEvent sound){ + this(Wizardry.MODID, name, tier, element, type, cost, cooldown, constructFactory, baseDuration, baseRange, sound); + } + + public SpellConstructRanged(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, + Function constructFactory, int baseDuration, double baseRange, SoundEvent sound){ + super(modID, name, tier, element, type, cost, cooldown, EnumAction.NONE, constructFactory, baseDuration, sound); + this.baseRange = baseRange; + } + + @Override public boolean doesSpellRequirePacket(){ return false; } + + @Override public boolean canBeCastByNPCs(){ return true; } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + double range = baseRange * modifiers.get(WizardryItems.range_upgrade); + RayTraceResult rayTrace = WizardryUtilities.standardBlockRayTrace(world, caster, range, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && (rayTrace.sideHit == EnumFacing.UP || + !requiresFloor)){ + + if(!world.isRemote){ + + double x = rayTrace.hitVec.x; + double y = rayTrace.hitVec.y; + double z = rayTrace.hitVec.z; + + if(!spawnConstruct(world, x, y, z, caster, modifiers)) return false; + } + + }else if(!requiresFloor){ + + if(!world.isRemote){ + + Vec3d look = caster.getLookVec(); + + double x = caster.posX + look.x * range; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() + look.y * range; + double z = caster.posZ + look.z * range; + + if(!spawnConstruct(world, x, y, z, caster, modifiers)) return false; + } + + }else{ + return false; + } + + caster.swingArm(hand); + if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, + SpellModifiers modifiers){ + + double range = baseRange * modifiers.get(WizardryItems.range_upgrade); + + if(target != null && caster.getDistance(target) <= range){ + + if(!world.isRemote){ + + double x = target.posX; + double y = target.posY; + double z = target.posZ; + + // If the target is not on the ground but the construct must be placed on the floor, searches for the + // floor under the caster and returns false if it does not find one within 3 blocks. + if(!target.onGround && requiresFloor){ + y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(x, y, z), 3); + if(y < 0) return false; + } + + if(!spawnConstruct(world, x, y, z, caster, modifiers)) return false; + } + + caster.swingArm(hand); + if(sound != null) caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SpellMinion.java b/src/main/java/electroblob/wizardry/spell/SpellMinion.java new file mode 100644 index 00000000..d7971d27 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpellMinion.java @@ -0,0 +1,165 @@ +package electroblob.wizardry.spell; + +import java.util.function.Function; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.entity.living.ISummonedCreature; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +/** + * Generic superclass for all spells which summon minions (i.e. instances of {@link ISummonedCreature}). + * This allows all the relevant code to be centralised, since these spells all work in the same way. Usually, a simple + * instantiation of this class is sufficient to create a projectile spell; if something extra needs to be done, such as + * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. + * It is encouraged, however, to put extra functionality in the summoned creature class instead whenever possible. + *

+ * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + *

+ * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + * + * @author Electroblob + * @since Wizardry 4.2 + */ +// Adding a type parameter to this class seems to work very nicely! +public class SpellMinion extends Spell { + + /** A factory that creates summoned creature entities. */ + protected final Function minionFactory; + /** The base lifetime of the summoned creature. */ + protected final int baseDuration; + /** The sound that gets played when this spell is cast. */ + protected final SoundEvent sound; + + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + /** The number of minions to summon. Defaults to 1. */ + protected int quantity = 1; + /** The maximum number of blocks from the caster in a single direction that the minions can spawn, defaults to 2. */ + protected int range = 2; + + public SpellMinion(String name, Tier tier, Element element, int cost, int cooldown, Function minionFactory, int baseDuration, SoundEvent sound){ + this(Wizardry.MODID, name, tier, element, cost, cooldown, minionFactory, baseDuration, sound); + } + + public SpellMinion(String modID, String name, Tier tier, Element element, int cost, int cooldown, Function minionFactory, int baseDuration, SoundEvent sound){ + super(modID, name, tier, element, SpellType.MINION, cost, cooldown, EnumAction.BOW, false); + this.minionFactory = minionFactory; + this.baseDuration = baseDuration; + this.sound = sound; + } + + /** + * Sets the sound parameters for this spell. + * @param volume + * @param pitch + * @param pitchVariation + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellMinion soundValues(float volume, float pitch, float pitchVariation) { + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; + } + + /** + * Sets the number of minions this spell will summon. + * @param quantity The number of minions to summon. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellMinion quantity(int quantity){ + this.quantity = quantity; + return this; + } + + /** + * Sets the range within which minions can spawn. + * @param range The maximum number of blocks from the caster that minions can be spawned. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellMinion range(int range){ + this.range = range; + return this; + } + + @Override public boolean doesSpellRequirePacket(){ return false; } + + @Override public boolean canBeCastByNPCs(){ return true; } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(!this.spawnMinions(world, caster, modifiers)) return false; + WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, + SpellModifiers modifiers){ + + if(!this.spawnMinions(world, caster, modifiers)) return false; + caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + /** Actually spawns the minions. By default, this spawns the number of minions specified by + * {@link SpellMinion#quantity} within a number of blocks of the caster specified by {@link SpellMinion#range}, + * returning false if there is no space to spawn the minions. Returning false from this method causes the spell to + * fail. Override to do something special, like spawning mnions in a specific position. + * @see SpellMinion#addMinionExtras(Entity, EntityLivingBase, SpellModifiers, int) */ + // Protected since someone might want to extend this class and change the behaviour of this method. + protected boolean spawnMinions(World world, EntityLivingBase caster, SpellModifiers modifiers){ + + if(!world.isRemote){ + for(int i=0; i + * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + *

+ * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + * + * @author Electroblob + * @since Wizardry 4.2 + */ +public class SpellProjectile extends Spell { + + // The general contract for these spell subtypes is that any required parameters are set via the constructor and are + // final, whereas any non-critical parameters are set via chainable setters with sensible defaults if not. For example, + // the actual sound to play is required, but it makes sense for its volume and pitch to default to 1 if unspecified. + + /** A factory that creates projectile entities. */ + protected final Function projectileFactory; + /** The base range (projectile speed) of this spell. */ + protected final float baseRange; + /** The sound that gets played when this spell is cast. */ + protected final SoundEvent sound; + + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + + public SpellProjectile(String name, Tier tier, Element element, int cost, int cooldown, Function projectileFactory, float baseRange, SoundEvent sound) { + this(Wizardry.MODID, name, tier, element, cost, cooldown, projectileFactory, baseRange, sound); + } + + public SpellProjectile(String modID, String name, Tier tier, Element element, int cost, int cooldown, Function projectileFactory, float baseRange, SoundEvent sound){ + super(modID, name, tier, element, SpellType.PROJECTILE, cost, cooldown, EnumAction.NONE, false); + this.projectileFactory = projectileFactory; + this.baseRange = baseRange; + this.sound = sound; + } + + /** + * Sets the sound parameters for this spell. + * @param volume + * @param pitch + * @param pitchVariation + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellProjectile soundValues(float volume, float pitch, float pitchVariation) { + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; + } + + @Override public boolean doesSpellRequirePacket(){ return false; } + + @Override public boolean canBeCastByNPCs(){ return true; } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(!world.isRemote){ + // Creates a projectile from the supplied factory + EntityMagicProjectile projectile = projectileFactory.apply(world); + // Sets the necessary parameters + projectile.aim(caster, baseRange * modifiers.get(WizardryItems.range_upgrade)); + projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + if(projectile instanceof EntityBomb) ((EntityBomb)projectile).blastMultiplier = modifiers.get(WizardryItems.blast_upgrade); + // Spawns the projectile in the world + world.spawnEntity(projectile); + } + + caster.swingArm(hand); + + WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(target != null){ + + if(!world.isRemote){ + // Creates a projectile from the supplied factory + EntityMagicProjectile projectile = projectileFactory.apply(world); + // Sets the necessary parameters + int aimingError = caster instanceof ISpellCaster ? ((ISpellCaster)caster).getAimingError(world.getDifficulty()) + : WizardryUtilities.getDefaultAimingError(world.getDifficulty()); + projectile.aim(caster, target, baseRange * modifiers.get(WizardryItems.range_upgrade), aimingError); + projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + if(projectile instanceof EntityBomb) ((EntityBomb)projectile).blastMultiplier = modifiers.get(WizardryItems.blast_upgrade); + // Spawns the projectile in the world + world.spawnEntity(projectile); + } + + caster.swingArm(hand); + + caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + + return true; + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SpellRay.java b/src/main/java/electroblob/wizardry/spell/SpellRay.java new file mode 100644 index 00000000..79b2f310 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpellRay.java @@ -0,0 +1,320 @@ +package electroblob.wizardry.spell; + +import javax.annotation.Nullable; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +/** + * Generic superclass for all spells which use a raytrace to do something and (optionally) spawn particles along that + * trajectory. This is for both continuous ('stream') spells and non-continuous ('bolt') spells This allows all the + * relevant code to be centralised. This class differs from most other spell superclasses in that it is abstract and as + * such must be subclassed to define what the spell actually does. This is because ray-like spells do a wider variety of + * different things, so it does not make sense to define more specific functions in this class since they would be + * redundant in the majority of cases. + *

+ * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} + *

+ * By default, this type of spell requires a packet to be sent. {@link Spell#doesSpellRequirePacket()} + * + * @author Electroblob + * @since Wizardry 4.2 + * @see SpellStream + */ +public abstract class SpellRay extends Spell { + + // TODO: Implement the 'aim assist' (borderSize) effect for rayTracing + + /** The distance below the caster's eyes that the bolt particles start from. */ + private static final double Y_OFFSET = 0.4; + + /** The base range of this spell. */ + protected final double baseRange; + /** The sound that gets played when this spell is cast. */ + @Nullable + protected final SoundEvent sound; + + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + /** The distance between spawned particles. Defaults to 0.85. */ + // 0.85 was chosen to keep it similar to the most common method used previously, which gave an effective spacing of + // 10/12 = 0.8333 when the spell did not hit anything. + protected double particleSpacing = 0.85; + /** The maximum dither (random position offset) for spawned particles. Defaults to 0.1. */ + protected double particleDither = 0.1; + /** The velocity of spawned particles in the direction the caster is aiming, can be negative. Defaults to 0. */ + protected double particleVelocity = 0; + /** Whether entities are ignored when raytracing. Defaults to false. */ + protected boolean ignoreEntities = false; + /** Whether liquids count as blocks when raytracing. Defaults to false. */ + protected boolean hitLiquids = false; + + public SpellRay(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, boolean isContinuous, double baseRange, SoundEvent sound){ + this(Wizardry.MODID, name, tier, element, type, cost, cooldown, isContinuous, baseRange, sound); + } + + public SpellRay(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, boolean isContinuous, double baseRange, SoundEvent sound){ + super(modID, name, tier, element, type, cost, cooldown, EnumAction.NONE, isContinuous); + this.baseRange = baseRange; + this.sound = sound; + } + + /** + * Sets the sound parameters for this spell. + * @param volume + * @param pitch + * @param pitchVariation + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellRay soundValues(float volume, float pitch, float pitchVariation) { + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; + } + + /** + * Sets the distance between spawned particles. + * @param particleSpacing The distance between particles in the ray effect. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellRay particleSpacing(double particleSpacing){ + this.particleSpacing = particleSpacing; + return this; + } + + /** + * Sets the maximum dither (random position offset) for spawned particles. + * @param particleDither The maximum dither for particles in the ray effect. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellRay particleDither(double particleDither){ + this.particleDither = particleDither; + return this; + } + + /** + * Sets the velocity of spawned particles. + * @param particleVelocity The velocity of spawned particles in the direction the caster is aiming, can be negative. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellRay particleVelocity(double particleVelocity){ + this.particleVelocity = particleVelocity; + return this; + } + + /** + * Sets whether entities are ignored when raytracing. + * @param ignoreEntities Whether to ignore entities when raytracing. If this is true, the spell will pass through + * entities as if they weren't there. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellRay ignoreEntities(boolean ignoreEntities){ + this.ignoreEntities = ignoreEntities; + return this; + } + + /** + * Sets whether liquids count as blocks when raytracing. + * @param hitLiquids Whether to hit liquids when raytracing. If this is false, the spell will pass through + * liquids as if they weren't there. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellRay hitLiquids(boolean hitLiquids){ + this.hitLiquids = hitLiquids; + return this; + } + + @Override public boolean canBeCastByNPCs(){ return true; } + + // Finally everything in here is standardised and written in a form that's actually readable - it was long overdue! + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + Vec3d look = caster.getLookVec(); + Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight() - Y_OFFSET, + caster.posZ); + + double range = baseRange * modifiers.get(WizardryItems.range_upgrade); + + // The first method will hit the first block it touches, passing through entities as if they weren't there. + // The second method will hit the first thing it touches, whether that's a block or an entity. + // Note that when it hits a block, the exact position hit is returned in hitVec, whereas when it hits an + // entity, it just returns the entity's position in hitVec. + RayTraceResult rayTrace = ignoreEntities + ? WizardryUtilities.standardBlockRayTrace(world, caster, range, hitLiquids) + : WizardryUtilities.standardEntityRayTrace(world, caster, range, hitLiquids); + + boolean flag = false; + + if(rayTrace != null){ + // Doesn't matter which way round these are, they're mutually exclusive + if(rayTrace.typeOfHit == RayTraceResult.Type.ENTITY){ + + Entity target = rayTrace.entityHit; + // Do whatever the spell does when it hits an entity + flag = onEntityHit(world, target, caster, ticksInUse, modifiers); + // If the spell succeeded, clip the particles to the correct distance so they don't go through the entity + if(flag){ + // The most pragmatic solution is to use the target's centre point for reasons explained earlier + double dx = origin.x - target.posX; + double dy = origin.y - (target.getEntityBoundingBox().minY + target.height/2); + double dz = origin.z - target.posZ; + range = MathHelper.sqrt(dx*dx + dy*dy + dz*dz); + } + + }else if(rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + // Do whatever the spell does when it hits an block + flag = onBlockHit(world, rayTrace.getBlockPos(), rayTrace.sideHit, caster, ticksInUse, modifiers); + // If the spell succeeded, clip the particles to the correct distance so they don't go through the block + if(flag) range = origin.distanceTo(rayTrace.hitVec); + } + } + + // If flag is false, either the spell missed or the relevant entity/block hit method returned false + if(!flag && !onMiss(world, caster, ticksInUse, modifiers)) return false; + + // Particle spawning + if(world.isRemote){ + spawnParticleRay(world, origin, look, range); + } + + if(!isContinuous) caster.swingArm(hand); // Bit of a dirty fix but I don't think it'll be a problem! + if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + // IDEA: Add in an aiming error and trigger onMiss accordingly + Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight() - Y_OFFSET, caster.posZ); + Vec3d direction = null; + + boolean flag = false; + + if(target != null){ + + if(!ignoreEntities && onEntityHit(world, target, caster, ticksInUse, modifiers)){ + + direction = new Vec3d(target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ) + .subtract(origin); + flag = true; + + }else{ // Will run if the spell does not do anything special on entity hit. + + int x = MathHelper.floor(target.posX); + int y = (int)target.getEntityBoundingBox().minY - 1; // -1 because we need the block under the target + int z = MathHelper.floor(target.posZ); + BlockPos pos = new BlockPos(x, y, z); + + // This works as if the NPC had actually aimed at the floor beneath the target, so it needs to check + // that the block is not air and (optionally) not a liquid. + if(!world.isAirBlock(pos) && (!world.getBlockState(pos).getMaterial().isLiquid() || hitLiquids) + && onBlockHit(world, pos, EnumFacing.UP, caster, ticksInUse, modifiers)){ + + direction = new Vec3d(x + 0.5, y + 1, z + 0.5).subtract(origin); + flag = true; + } + } + } + + // Wizards don't miss... yet + if(!flag) return false; + + // Particle spawning (direction should never be null at this point but no harm in checking) + if(world.isRemote && direction != null){ + spawnParticleRay(world, origin, direction.normalize(), direction.lengthVector()); + } + + if(!isContinuous) caster.swingArm(hand); // Bit of a dirty fix but I don't think it'll be a problem! + if(sound != null) caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + return true; + } + + // Private helper method, no-one will need to override it since it's pretty much the whole point of this class. + private void spawnParticleRay(World world, Vec3d origin, Vec3d direction, double distance){ + + Vec3d velocity = direction.scale(particleVelocity); + + for(double d = particleSpacing; d <= distance; d += particleSpacing){ + double x = origin.x + d*direction.x + particleDither * (world.rand.nextDouble()*2 - 1); + double y = origin.y + d*direction.y + particleDither * (world.rand.nextDouble()*2 - 1); + double z = origin.z + d*direction.z + particleDither * (world.rand.nextDouble()*2 - 1); + spawnParticle(world, x, y, z, velocity.x, velocity.y, velocity.z); + } + } + + /** + * Called when the spell hits an entity. Will never be called if ignoreEntities is true. + * @param world The world the entity is in. + * @param target The entity that was hit. + * @param caster The caster of this spell, or null if this spell was cast from a dispenser. + * @param ticksInUse The number of ticks the spell has already been cast for (used only for continuous spells). + * @param modifiers The modifiers this spell was cast with. + * @return True to continue with spell casting and spawn particles, false to trigger a miss (N.B. you will need to + * return false from {@link SpellRay#onMiss(World, EntityLivingBase, int, SpellModifiers)} if a miss should not consume + * mana). + */ + protected abstract boolean onEntityHit(World world, Entity target, @Nullable EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers); + + /** + * Called when the spell hits a block. + * @param world The world the block is in. + * @param pos The BlockPos of the block that was hit. + * @param side The side of the block that was hit. + * @param caster The caster of this spell, or null if this spell was cast from a dispenser. + * @param ticksInUse The number of ticks the spell has already been cast for (used only for continuous spells). + * @param modifiers The modifiers this spell was cast with. + * @return True to continue with spell casting and spawn particles, false to trigger a miss (N.B. you will need to + * return false from {@link SpellRay#onMiss(World, EntityLivingBase, int, SpellModifiers)} if a miss should not consume + * mana). + */ + protected abstract boolean onBlockHit(World world, BlockPos pos, EnumFacing side, @Nullable EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers); + + /** + * Called when the spell does not hit anything or when the spell hits something it has no effect on. Most of the time + * this will just return true or false, but some spells may, for example, display a chat readout. + * @param world The world the spell is in. + * @param caster The caster of this spell, or null if this spell was cast from a dispenser. + * @param ticksInUse The number of ticks the spell has already been cast for (used only for continuous spells). + * @param modifiers The modifiers this spell was cast with. + * @return True to continue with spell casting and spawn particles, false to cause the spell to fail. + */ + protected abstract boolean onMiss(World world, @Nullable EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers); + + /** + * Called at each point along the spell trajectory to spawn one or more particles at that point. Only called + * client-side. Does nothing by default. + * @param world The world in which to spawn the particle. + * @param x The x-coordinate to spawn the particle at, with dither already applied. + * @param y The y-coordinate to spawn the particle at, with dither already applied. + * @param z The z-coordinate to spawn the particle at, with dither already applied. + * @param vx The x velocity to spawn the particle with. Usually this is only non-zero for continuous spells. + * @param vy The y velocity to spawn the particle with. Usually this is only non-zero for continuous spells. + * @param vz The z velocity to spawn the particle with. Usually this is only non-zero for continuous spells. + */ + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){} + +} diff --git a/src/main/java/electroblob/wizardry/spell/SpiderSwarm.java b/src/main/java/electroblob/wizardry/spell/SpiderSwarm.java deleted file mode 100644 index fbb9d926..00000000 --- a/src/main/java/electroblob/wizardry/spell/SpiderSwarm.java +++ /dev/null @@ -1,76 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntitySpiderMinion; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SpiderSwarm extends Spell { - - public SpiderSwarm(){ - super(Tier.ADVANCED, 45, Element.EARTH, "spider_swarm", SpellType.MINION, 200, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - for(int i = 0; i < 5; i++){ - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); - // The spell instantly fails if no space was found (see javadoc for the above method). - if(pos == null) return false; - - EntitySpiderMinion spider = new EntitySpiderMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(spider); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - // Can't possibly get this far if nothing was spawned. - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!world.isRemote){ - for(int i = 0; i < 5; i++){ - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); - // The spell instantly fails if no space was found (see javadoc for the above method). - if(pos == null) return false; - - EntitySpiderMinion spider = new EntitySpiderMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(spider); - } - } - - caster.playSound(SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); - // Can't possibly get this far if nothing was spawned. - return true; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } -} diff --git a/src/main/java/electroblob/wizardry/spell/StaticAura.java b/src/main/java/electroblob/wizardry/spell/StaticAura.java deleted file mode 100644 index b04cc612..00000000 --- a/src/main/java/electroblob/wizardry/spell/StaticAura.java +++ /dev/null @@ -1,71 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class StaticAura extends Spell { - - public StaticAura(){ - super(Tier.ADVANCED, 40, Element.LIGHTNING, "static_aura", SpellType.DEFENCE, 250, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - // Cannot be cast when it has already been cast - if(!caster.isPotionActive(WizardryPotions.static_aura)){ - if(!world.isRemote){ - caster.addPotionEffect(new PotionEffect(WizardryPotions.static_aura, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SPARK, 1.0F, - world.rand.nextFloat() * 0.4F + 1.4F); - return true; - } - return false; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - // Cannot be cast when it has already been cast - if(!caster.isPotionActive(WizardryPotions.static_aura)){ - if(!world.isRemote){ - caster.addPotionEffect(new PotionEffect(WizardryPotions.static_aura, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - } - caster.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.4F); - return true; - } - return false; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SummonBlaze.java b/src/main/java/electroblob/wizardry/spell/SummonBlaze.java deleted file mode 100644 index 9a67355b..00000000 --- a/src/main/java/electroblob/wizardry/spell/SummonBlaze.java +++ /dev/null @@ -1,71 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityBlazeMinion; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SummonBlaze extends Spell { - - public SummonBlaze(){ - super(Tier.ADVANCED, 40, Element.FIRE, "summon_blaze", SpellType.MINION, 200, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityBlazeMinion blaze = new EntityBlazeMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, - caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(blaze); - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityBlazeMinion blaze = new EntityBlazeMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, - caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(blaze); - } - - caster.playSound(SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java b/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java deleted file mode 100644 index 87d30b8d..00000000 --- a/src/main/java/electroblob/wizardry/spell/SummonIceGiant.java +++ /dev/null @@ -1,53 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityIceGiant; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SummonIceGiant extends Spell { - - public SummonIceGiant(){ - super(Tier.MASTER, 100, Element.ICE, "summon_ice_giant", SpellType.MINION, 400, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - if(!world.isRemote){ - - EntityIceGiant icegiant = new EntityIceGiant(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(icegiant); - } - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)pos.getX() + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)pos.getZ() + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); - } - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, - world.rand.nextFloat() * 0.1F + 0.2F); - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SummonIceWraith.java b/src/main/java/electroblob/wizardry/spell/SummonIceWraith.java deleted file mode 100644 index 83571178..00000000 --- a/src/main/java/electroblob/wizardry/spell/SummonIceWraith.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityIceWraith; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SummonIceWraith extends Spell { - - public SummonIceWraith(){ - super(Tier.ADVANCED, 40, Element.ICE, "summon_ice_wraith", SpellType.MINION, 200, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityIceWraith iceWraith = new EntityIceWraith(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, - caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(iceWraith); - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityIceWraith iceWraith = new EntityIceWraith(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, - caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(iceWraith); - } - caster.playSound(SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java index fa2a0759..1fee0dab 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java @@ -1,11 +1,11 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.monster.EntityIronGolem; import net.minecraft.entity.player.EntityPlayer; @@ -18,7 +18,7 @@ import net.minecraft.world.World; public class SummonIronGolem extends Spell { public SummonIronGolem(){ - super(Tier.MASTER, 175, Element.SORCERY, "summon_iron_golem", SpellType.MINION, 400, EnumAction.BOW, false); + super("summon_iron_golem", Tier.MASTER, Element.SORCERY, SpellType.MINION, 175, 400, EnumAction.BOW, false); } @Override @@ -28,23 +28,22 @@ public class SummonIronGolem extends Spell { if(pos == null) return false; if(!world.isRemote){ + EntityIronGolem golem = new EntityIronGolem(world); golem.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); world.spawnEntity(golem); - } - - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)pos.getX() + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)pos.getZ() + world.rand.nextFloat() * 2 - 1.0F); - if(world.isRemote){ - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); + + }else{ + + for(int i=0; i<10; i++){ + double x = pos.getX() + world.rand.nextDouble() * 2 - 1; + double y = pos.getY() + 0.5 + world.rand.nextDouble(); + double z = pos.getZ() + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).colour(0.6f, 0.6f, 1).spawn(world); } } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); + WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1, 1 + 0.2f * world.rand.nextFloat()); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/SummonLightningWraith.java b/src/main/java/electroblob/wizardry/spell/SummonLightningWraith.java deleted file mode 100644 index 0baff375..00000000 --- a/src/main/java/electroblob/wizardry/spell/SummonLightningWraith.java +++ /dev/null @@ -1,70 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityLightningWraith; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SummonLightningWraith extends Spell { - - public SummonLightningWraith(){ - super(Tier.ADVANCED, 40, Element.LIGHTNING, "summon_lightning_wraith", SpellType.MINION, 200, EnumAction.BOW, - false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityLightningWraith lightningWraith = new EntityLightningWraith(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(lightningWraith); - } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityLightningWraith lightningWraith = new EntityLightningWraith(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(lightningWraith); - } - caster.playSound(SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SummonPhoenix.java b/src/main/java/electroblob/wizardry/spell/SummonPhoenix.java deleted file mode 100644 index c74b39d9..00000000 --- a/src/main/java/electroblob/wizardry/spell/SummonPhoenix.java +++ /dev/null @@ -1,46 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityPhoenix; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SummonPhoenix extends Spell { - - public SummonPhoenix(){ - super(Tier.MASTER, 150, Element.FIRE, "summon_phoenix", SpellType.MINION, 400, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityPhoenix phoenix = new EntityPhoenix(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, caster, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(phoenix); - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java b/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java index 6f00f8f2..8dac0d1c 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java +++ b/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java @@ -1,48 +1,17 @@ package electroblob.wizardry.spell; import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntityShadowWraith; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -public class SummonShadowWraith extends Spell { +public class SummonShadowWraith extends SpellMinion { public SummonShadowWraith(){ - super(Tier.MASTER, 100, Element.NECROMANCY, "summon_shadow_wraith", SpellType.MINION, 400, EnumAction.BOW, - false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityShadowWraith shadowWraith = new EntityShadowWraith(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(shadowWraith); - } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; + super("summon_shadow_wraith", Tier.MASTER, Element.NECROMANCY, 100, 400, EntityShadowWraith::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT); + this.soundValues(1, 1.1f, 0.1f); } @SideOnly(Side.CLIENT) diff --git a/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java b/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java index 68bcbcf1..4bec5e60 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java @@ -1,75 +1,26 @@ package electroblob.wizardry.spell; import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntitySkeletonMinion; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; -import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -public class SummonSkeleton extends Spell { +public class SummonSkeleton extends SpellMinion { public SummonSkeleton(){ - super(Tier.APPRENTICE, 15, Element.NECROMANCY, "summon_skeleton", SpellType.MINION, 50, EnumAction.BOW, false); + super("summon_skeleton", Tier.APPRENTICE, Element.NECROMANCY, 15, 50, EntitySkeletonMinion::new, 600, WizardrySounds.SPELL_SUMMONING); + this.soundValues(7, 0.6f, 0); } - + @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); - skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); - world.spawnEntity(skeleton); - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); - skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); - world.spawnEntity(skeleton); - } - caster.playSound(WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); - return true; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; + protected void addMinionExtras(EntitySkeletonMinion minion, EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){ + minion.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); + minion.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java b/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java index 02defe38..f7fb9c4c 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java @@ -1,78 +1,40 @@ package electroblob.wizardry.spell; import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntitySkeletonMinion; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Items; import net.minecraft.init.SoundEvents; import net.minecraft.inventory.EntityEquipmentSlot; -import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -public class SummonSkeletonLegion extends Spell { +public class SummonSkeletonLegion extends SpellMinion { public SummonSkeletonLegion(){ - super(Tier.MASTER, 100, Element.NECROMANCY, "summon_skeleton_legion", SpellType.MINION, 400, EnumAction.BOW, - false); + super("summon_skeleton_legion", Tier.MASTER, Element.NECROMANCY, 100, 400, EntitySkeletonMinion::new, 1200, SoundEvents.ENTITY_WITHER_SPAWN); + this.soundValues(1, 1.1f, 0.1f); + this.quantity(3); + this.range(3); } - + @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ + protected void addMinionExtras(EntitySkeletonMinion minion, EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){ + + if(alreadySpawned % 2 == 0){ // Archers - for(int i = 0; i < 3; i++){ - // This is all so much neater now thanks to this method. - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); - // The spell instantly fails if no space was found (see javadoc for the above method). - if(pos == null) return false; - - EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(1200 * modifiers.get(WizardryItems.duration_upgrade))); - skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); - skeleton.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(Items.CHAINMAIL_HELMET)); - skeleton.setItemStackToSlot(EntityEquipmentSlot.CHEST, new ItemStack(Items.CHAINMAIL_CHESTPLATE)); - skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); - skeleton.setDropChance(EntityEquipmentSlot.HEAD, 0.0f); - skeleton.setDropChance(EntityEquipmentSlot.CHEST, 0.0f); - world.spawnEntity(skeleton); - } + minion.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); + }else{ // Swordsmen - for(int i = 0; i < 3; i++){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 3, 6); - // The spell instantly fails if no space was found (see javadoc for the above method). - if(pos == null) return false; - - EntitySkeletonMinion skeleton = new EntitySkeletonMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(1200 * modifiers.get(WizardryItems.duration_upgrade))); - skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SWORD)); - skeleton.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(Items.CHAINMAIL_HELMET)); - skeleton.setItemStackToSlot(EntityEquipmentSlot.CHEST, new ItemStack(Items.CHAINMAIL_CHESTPLATE)); - skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); - skeleton.setDropChance(EntityEquipmentSlot.HEAD, 0.0f); - skeleton.setDropChance(EntityEquipmentSlot.CHEST, 0.0f); - world.spawnEntity(skeleton); - } + minion.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SWORD)); } - - // Can't possibly get this far if nothing was spawned. - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; + + minion.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(Items.CHAINMAIL_HELMET)); + minion.setItemStackToSlot(EntityEquipmentSlot.CHEST, new ItemStack(Items.CHAINMAIL_CHESTPLATE)); + minion.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); + minion.setDropChance(EntityEquipmentSlot.HEAD, 0.0f); + minion.setDropChance(EntityEquipmentSlot.CHEST, 0.0f); } } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java index d50da8c1..e168d3b8 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java @@ -1,12 +1,12 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.monster.EntitySnowman; import net.minecraft.entity.player.EntityPlayer; @@ -18,7 +18,7 @@ import net.minecraft.world.World; public class SummonSnowGolem extends Spell { public SummonSnowGolem(){ - super(Tier.APPRENTICE, 15, Element.ICE, "summon_snow_golem", SpellType.MINION, 20, EnumAction.BOW, false); + super("summon_snow_golem", Tier.APPRENTICE, Element.ICE, SpellType.MINION, 15, 20, EnumAction.BOW, false); } @Override @@ -28,21 +28,22 @@ public class SummonSnowGolem extends Spell { if(pos == null) return false; if(!world.isRemote){ + EntitySnowman snowman = new EntitySnowman(world); snowman.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); world.spawnEntity(snowman); - } - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)pos.getX() + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)pos.getY() + 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)pos.getZ() + world.rand.nextFloat() * 2 - 1.0F); - if(world.isRemote){ - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.6f, 0.6f, 1.0f); + + }else{ + + for(int i=0; i<10; i++){ + double x = pos.getX() + world.rand.nextDouble() * 2 - 1; + double y = pos.getY() + 0.5 + world.rand.nextDouble(); + double z = pos.getZ() + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.6f, 0.6f, 1).spawn(world); } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); + + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7f, 1 + 0.4f * world.rand.nextFloat()); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java b/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java index 359e2b45..a256d880 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; public class SummonSpiritHorse extends Spell { public SummonSpiritHorse(){ - super(Tier.ADVANCED, 50, Element.EARTH, "summon_spirit_horse", SpellType.MINION, 150, EnumAction.BOW, false); + super("summon_spirit_horse", Tier.ADVANCED, Element.EARTH, SpellType.MINION, 50, 150, EnumAction.BOW, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java b/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java index 4d0ce4c3..f3896c7f 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; public class SummonSpiritWolf extends Spell { public SummonSpiritWolf(){ - super(Tier.APPRENTICE, 25, Element.EARTH, "summon_spirit_wolf", SpellType.MINION, 100, EnumAction.BOW, false); + super("summon_spirit_wolf", Tier.APPRENTICE, Element.EARTH, SpellType.MINION, 25, 100, EnumAction.BOW, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/SummonStormElemental.java b/src/main/java/electroblob/wizardry/spell/SummonStormElemental.java deleted file mode 100644 index ed41e623..00000000 --- a/src/main/java/electroblob/wizardry/spell/SummonStormElemental.java +++ /dev/null @@ -1,45 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityStormElemental; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SummonStormElemental extends Spell { - - public SummonStormElemental(){ - super(Tier.MASTER, 100, Element.LIGHTNING, "summon_storm_elemental", SpellType.MINION, 400, EnumAction.BOW, - false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityStormElemental stormElemental = new EntityStormElemental(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(stormElemental); - } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_AMBIENT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } -} diff --git a/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java b/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java deleted file mode 100644 index 58372589..00000000 --- a/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java +++ /dev/null @@ -1,76 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Items; -import net.minecraft.inventory.EntityEquipmentSlot; -import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SummonWitherSkeleton extends Spell { - - public SummonWitherSkeleton(){ - super(Tier.ADVANCED, 35, Element.NECROMANCY, "summon_wither_skeleton", SpellType.MINION, 150, EnumAction.BOW, - false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityWitherSkeletonMinion skeleton = new EntityWitherSkeletonMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.STONE_SWORD)); - skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); - world.spawnEntity(skeleton); - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityWitherSkeletonMinion skeleton = new EntityWitherSkeletonMinion(world, pos.getX() + 0.5, pos.getY(), - pos.getZ() + 0.5, caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - skeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.STONE_SWORD)); - skeleton.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); - world.spawnEntity(skeleton); - } - caster.playSound(WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); - return true; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/SummonZombie.java b/src/main/java/electroblob/wizardry/spell/SummonZombie.java deleted file mode 100644 index 8e8e684f..00000000 --- a/src/main/java/electroblob/wizardry/spell/SummonZombie.java +++ /dev/null @@ -1,67 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityZombieMinion; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class SummonZombie extends Spell { - - public SummonZombie(){ - super(Tier.BASIC, 10, Element.NECROMANCY, "summon_zombie", SpellType.MINION, 40, EnumAction.BOW, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - EntityZombieMinion zombie = new EntityZombieMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, - caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(zombie); - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(!world.isRemote){ - - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; - - EntityZombieMinion zombie = new EntityZombieMinion(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, - caster, (int)(600 * modifiers.get(WizardryItems.duration_upgrade))); - world.spawnEntity(zombie); - } - caster.playSound(WizardrySounds.SPELL_SUMMONING, 7.0f, 0.6f); - return true; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Telekinesis.java b/src/main/java/electroblob/wizardry/spell/Telekinesis.java index 40b7f34b..13dbe35c 100644 --- a/src/main/java/electroblob/wizardry/spell/Telekinesis.java +++ b/src/main/java/electroblob/wizardry/spell/Telekinesis.java @@ -4,115 +4,80 @@ import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class Telekinesis extends Spell { +public class Telekinesis extends SpellRay { public Telekinesis(){ - super(Tier.BASIC, 5, Element.SORCERY, "telekinesis", SpellType.UTILITY, 5, EnumAction.NONE, false); + super("telekinesis", Tier.BASIC, Element.SORCERY, SpellType.UTILITY, 5, 5, false, 8, WizardrySounds.SPELL_CONJURATION); } + @Override public boolean doesSpellRequirePacket(){ return false; } + @Override - public boolean doesSpellRequirePacket(){ - return false; - } + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(target instanceof EntityItem){ - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + target.motionX = (caster.posX - target.posX) / 6; + target.motionY = (caster.posY + caster.getEyeHeight() - target.posY) / 6; + target.motionZ = (caster.posZ - target.posZ) / 6; + return true; - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 8 * modifiers.get(WizardryItems.range_upgrade), 3.0f); - - if(rayTrace != null && rayTrace.entityHit != null){ - - if(rayTrace.entityHit instanceof EntityItem){ - - Entity entityHit = rayTrace.entityHit; - entityHit.motionX = (caster.posX - entityHit.posX) / 6; - entityHit.motionY = (caster.posY + caster.eyeHeight - entityHit.posY) / 6; - entityHit.motionZ = (caster.posZ - entityHit.posZ) / 6; - entityHit.playSound(WizardrySounds.SPELL_CONJURATION, 1.0F, 1.0f); - caster.swingArm(hand); - return true; - - }else if(rayTrace.entityHit instanceof EntityPlayer && Wizardry.settings.telekineticDisarmament){ - - EntityPlayer target = (EntityPlayer)rayTrace.entityHit; - - if(!target.getHeldItemMainhand().isEmpty()){ - - if(!world.isRemote){ - EntityItem item = target.entityDropItem(target.getHeldItemMainhand(), 0.0f); - // Makes the item move towards the caster - item.motionX = (caster.posX - target.posX) / 20; - item.motionZ = (caster.posZ - target.posZ) / 20; - } - - target.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY); - - target.playSound(WizardrySounds.SPELL_CONJURATION, 1.0F, 1.0f); - caster.swingArm(hand); - return true; - } - } - } - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - IBlockState blockstate = world.getBlockState(new BlockPos(rayTrace.getBlockPos())); - - if(blockstate.getBlock().onBlockActivated(world, rayTrace.getBlockPos(), blockstate, caster, hand, - rayTrace.sideHit, 0, 0, 0)){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0F, 1.0f); - caster.swingArm(hand); - return true; - } - } - return false; - } - - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target instanceof EntityPlayer && !target.getHeldItemMainhand().isEmpty()){ + }else if(target instanceof EntityPlayer && (Wizardry.settings.telekineticDisarmament || !(caster instanceof EntityPlayer))){ + EntityPlayer player = (EntityPlayer)target; + // IDEA: Disarm the offhand if the mainhand is empty or otherwise harmless? - if(!world.isRemote){ - EntityItem item = target.entityDropItem(target.getHeldItemMainhand(), 0.0f); - // Makes the item move towards the caster - item.motionX = (caster.posX - target.posX) / 20; - item.motionZ = (caster.posZ - target.posZ) / 20; + if(!player.getHeldItemMainhand().isEmpty()){ + + if(!world.isRemote){ + EntityItem item = player.entityDropItem(player.getHeldItemMainhand(), 0); + // Makes the item move towards the caster + item.motionX = (caster.posX - player.posX) / 20; + item.motionZ = (caster.posZ - player.posZ) / 20; + } + + player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY); + + return true; } - - target.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY); - - target.playSound(WizardrySounds.SPELL_CONJURATION, 1.0F, 1.0f); - caster.swingArm(hand); - return true; } - + return false; } @Override - public boolean canBeCastByNPCs(){ - return true; + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(caster instanceof EntityPlayer){ + + IBlockState blockstate = world.getBlockState(pos); + + if(blockstate.getBlock().onBlockActivated(world, pos, blockstate, (EntityPlayer)caster, EnumHand.MAIN_HAND, + side, 0, 0, 0)){ + return true; + } + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; } } diff --git a/src/main/java/electroblob/wizardry/spell/Thunderbolt.java b/src/main/java/electroblob/wizardry/spell/Thunderbolt.java deleted file mode 100644 index ecdf0762..00000000 --- a/src/main/java/electroblob/wizardry/spell/Thunderbolt.java +++ /dev/null @@ -1,68 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.projectile.EntityThunderbolt; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class Thunderbolt extends Spell { - - public Thunderbolt(){ - super(Tier.BASIC, 10, Element.LIGHTNING, "thunderbolt", SpellType.ATTACK, 15, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - EntityThunderbolt thunderbolt = new EntityThunderbolt(world, caster, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(thunderbolt); - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.8F, - world.rand.nextFloat() * 0.2F + 0.8F); - caster.swingArm(hand); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - EntityThunderbolt thunderbolt = new EntityThunderbolt(world, caster, - modifiers.get(SpellModifiers.DAMAGE)); - thunderbolt.directTowards(target, 2.5f); - world.spawnEntity(thunderbolt); - } - - caster.playSound(WizardrySounds.SPELL_ICE, 0.8F, world.rand.nextFloat() * 0.2F + 0.8F); - caster.swingArm(hand); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java index cb533a50..a96d65ea 100644 --- a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java +++ b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java @@ -2,7 +2,6 @@ package electroblob.wizardry.spell; import java.util.List; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; @@ -11,27 +10,37 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.effect.EntityLightningBolt; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; -import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class Thunderstorm extends Spell { public Thunderstorm(){ - super(Tier.MASTER, 100, Element.LIGHTNING, "thunderstorm", SpellType.ATTACK, 250, EnumAction.BOW, false); + super("thunderstorm", Tier.MASTER, Element.LIGHTNING, SpellType.ATTACK, 100, 250, EnumAction.BOW, false); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - + return doCasting(world, caster, modifiers); + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + return doCasting(world, caster, modifiers); + } + + // This spell is exactly the same for players and NPCs. + private boolean doCasting(World world, EntityLivingBase caster, SpellModifiers modifiers){ + if(world.canBlockSeeSky(new BlockPos(caster))){ for(int r = 0; r < 10; r++){ @@ -69,25 +78,16 @@ public class Thunderstorm extends Spell { secondaryTarget.posY + secondaryTarget.height / 2, secondaryTarget.posZ); world.spawnEntity(arc); }else{ - for(int j = 0; j < 8; j++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - 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, 3); - 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); - } + ParticleBuilder.spawnShockParticles(world, secondaryTarget.posX, + secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2, + secondaryTarget.posZ); } secondaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); secondaryTarget.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 10.0f * modifiers.get(SpellModifiers.DAMAGE)); + 10.0f * modifiers.get(SpellModifiers.POTENCY)); // Tertiary chaining effect @@ -110,18 +110,9 @@ public class Thunderstorm extends Spell { tertiaryTarget.posZ); world.spawnEntity(arc); }else{ - for(int k = 0; k < 8; k++){ - Wizardry.proxy.spawnParticle(Type.SPARK, world, - tertiaryTarget.posX + world.rand.nextFloat() - 0.5, - tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2 - + world.rand.nextFloat() * 2 - 1, - tertiaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0, 3); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, - tertiaryTarget.posX + world.rand.nextFloat() - 0.5, - tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2 - + world.rand.nextFloat() * 2 - 1, - tertiaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); - } + ParticleBuilder.spawnShockParticles(world, tertiaryTarget.posX, + tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2, + tertiaryTarget.posZ); } tertiaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, @@ -129,7 +120,7 @@ public class Thunderstorm extends Spell { tertiaryTarget.attackEntityFrom( MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 8.0f * modifiers.get(SpellModifiers.DAMAGE)); + 8.0f * modifiers.get(SpellModifiers.POTENCY)); } } } diff --git a/src/main/java/electroblob/wizardry/spell/Tornado.java b/src/main/java/electroblob/wizardry/spell/Tornado.java index bae3d7ee..166b071e 100644 --- a/src/main/java/electroblob/wizardry/spell/Tornado.java +++ b/src/main/java/electroblob/wizardry/spell/Tornado.java @@ -4,74 +4,20 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityTornado; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; -public class Tornado extends Spell { +public class Tornado extends SpellConstruct { public Tornado(){ - super(Tier.ADVANCED, 35, Element.EARTH, "tornado", SpellType.ATTACK, 80, EnumAction.NONE, false); + super("tornado", Tier.ADVANCED, Element.EARTH, SpellType.ATTACK, 35, 80, EnumAction.NONE, EntityTornado::new, 200, WizardrySounds.SPELL_ICE); } @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!world.isRemote){ - double x = caster.posX + caster.getLookVec().x; - double y = caster.posY; - double z = caster.posZ + caster.getLookVec().z; - - EntityTornado tornado = new EntityTornado(world, x, y, z, caster, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), caster.getLookVec().x / 3, - caster.getLookVec().z / 3, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(tornado); - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - double x = caster.posX + caster.getLookVec().x; - double y = caster.posY; - double z = caster.posZ + caster.getLookVec().z; - - EntityTornado tornado = new EntityTornado(world, x, y, z, caster, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), caster.getLookVec().x / 3, - caster.getLookVec().z / 3, modifiers.get(SpellModifiers.DAMAGE)); - world.spawnEntity(tornado); - } - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 1.0F, 1.0F); - - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; + protected void addConstructExtras(EntityTornado construct, EntityLivingBase caster, SpellModifiers modifiers){ + construct.setHorizontalVelocity(caster.getLookVec().x / 3, caster.getLookVec().z / 3); } } diff --git a/src/main/java/electroblob/wizardry/spell/Transience.java b/src/main/java/electroblob/wizardry/spell/Transience.java index faee9216..07bcc516 100644 --- a/src/main/java/electroblob/wizardry/spell/Transience.java +++ b/src/main/java/electroblob/wizardry/spell/Transience.java @@ -24,7 +24,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class Transience extends Spell { public Transience(){ - super(Tier.ADVANCED, 50, Element.HEALING, "transience", SpellType.DEFENCE, 100, EnumAction.BOW, false); + super("transience", Tier.ADVANCED, Element.HEALING, SpellType.BUFF, 50, 100, EnumAction.BOW, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/Transportation.java b/src/main/java/electroblob/wizardry/spell/Transportation.java index 51b8cedd..2e91f4dd 100644 --- a/src/main/java/electroblob/wizardry/spell/Transportation.java +++ b/src/main/java/electroblob/wizardry/spell/Transportation.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; public class Transportation extends Spell { public Transportation(){ - super(Tier.ADVANCED, 100, Element.SORCERY, "transportation", SpellType.UTILITY, 100, EnumAction.BOW, false); + super("transportation", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 100, 100, EnumAction.BOW, false); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/VanishingBox.java b/src/main/java/electroblob/wizardry/spell/VanishingBox.java index 76bf97ee..24ea13df 100644 --- a/src/main/java/electroblob/wizardry/spell/VanishingBox.java +++ b/src/main/java/electroblob/wizardry/spell/VanishingBox.java @@ -15,13 +15,10 @@ import net.minecraft.world.World; public class VanishingBox extends Spell { public VanishingBox(){ - super(Tier.ADVANCED, 45, Element.SORCERY, "vanishing_box", SpellType.UTILITY, 70, EnumAction.BOW, false); + super("vanishing_box", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 45, 70, EnumAction.BOW, false); } - @Override - public boolean doesSpellRequirePacket(){ - return false; - } + @Override public boolean doesSpellRequirePacket(){ return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/WallOfFrost.java b/src/main/java/electroblob/wizardry/spell/WallOfFrost.java index 98907300..37a55b55 100644 --- a/src/main/java/electroblob/wizardry/spell/WallOfFrost.java +++ b/src/main/java/electroblob/wizardry/spell/WallOfFrost.java @@ -1,103 +1,137 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.ParticleBuilder.Type; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -public class WallOfFrost extends Spell { +public class WallOfFrost extends SpellRay { + private static final int BASE_DURATION = 600; + public WallOfFrost(){ - super(Tier.MASTER, 15, Element.ICE, "wall_of_frost", SpellType.UTILITY, 0, EnumAction.NONE, true); + super("wall_of_frost", Tier.MASTER, Element.ICE, SpellType.UTILITY, 15, 0, true, 10, null); + this.particleVelocity(1); + this.particleSpacing(0.5); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + // TODO: Temporary solution until I implement a better continuous sound system + boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); + if(flag){ + if(ticksInUse % 12 == 0){ + if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5f, 1); + WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_ICE, 0.5f, 1); + } + } + return flag; } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); + if(flag){ + if(ticksInUse % 12 == 0){ + if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_ICE, 0.5f, 1); + caster.playSound(WizardrySounds.SPELL_LOOP_ICE, 0.5f, 1); + } + } + return flag; + } - // IDEA: Use frosted ice instead of ice statue + @Override + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + // Wall of frost now freezes entities solid too! + if(target instanceof EntityLiving && !world.isRemote){ + // Unchecked cast is fine because the block is a static final field + if(((BlockStatue)WizardryBlocks.ice_statue).convertToStatue((EntityLiving)target, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)))){ + + target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + return true; + } + } + + return false; + } - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.rayTrace(10 * modifiers.get(WizardryItems.range_upgrade), world, - caster, true); - - if(rayTrace != null && !world.isRemote){ - - BlockPos pos = rayTrace.getBlockPos(); + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + // IDEA: Use frosted ice instead of ice statue blocks + + if(!world.isRemote){ // Stops the ice being placed floating above snow and grass. Directions other than up included for // completeness. if(WizardryUtilities.canBlockBeReplaced(world, pos)){ // Moves the blockpos back into the block - pos = pos.offset(rayTrace.sideHit.getOpposite()); + pos = pos.offset(side.getOpposite()); } if(caster.getDistance(pos.getX(), pos.getY(), pos.getZ()) > 2 && world.getBlockState(pos).getBlock() != WizardryBlocks.ice_statue){ - pos = pos.offset(rayTrace.sideHit); + pos = pos.offset(side); + + int duration = (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)); if(WizardryUtilities.canBlockBeReplaced(world, pos)){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration); + } } // Builds a 2 block high wall if it hits the ground - if(rayTrace.sideHit == EnumFacing.UP){ - pos = pos.offset(rayTrace.sideHit); + if(side == EnumFacing.UP){ + pos = pos.offset(side); if(WizardryUtilities.canBlockBeReplaced(world, pos)){ + world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); + + if(world.getTileEntity(pos) instanceof TileEntityStatue){ + ((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration); + } } } } } - - for(int i = 0; i < 20; i++){ - - if(world.isRemote){ - - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, - look.x * modifiers.get(WizardryItems.range_upgrade), - look.y * modifiers.get(WizardryItems.range_upgrade), - look.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 0.4f, - 0.6f, 1.0f); - - x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, - look.x * modifiers.get(WizardryItems.range_upgrade), - look.y * modifiers.get(WizardryItems.range_upgrade), - look.z * modifiers.get(WizardryItems.range_upgrade), 8 + world.rand.nextInt(12), 1.0f, - 1.0f, 1.0f); - } - } - - if(ticksInUse % 12 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5F, 1.0f); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_ICE, 0.5F, 1.0f); - } - + return true; } + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + float brightness = world.rand.nextFloat(); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)) + .colour(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)).spawn(world); + } + } diff --git a/src/main/java/electroblob/wizardry/spell/WaterBreathing.java b/src/main/java/electroblob/wizardry/spell/WaterBreathing.java deleted file mode 100644 index 4b2462eb..00000000 --- a/src/main/java/electroblob/wizardry/spell/WaterBreathing.java +++ /dev/null @@ -1,44 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.EnumAction; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.world.World; - -public class WaterBreathing extends Spell { - - public WaterBreathing(){ - super(Tier.ADVANCED, 30, Element.EARTH, "water_breathing", SpellType.UTILITY, 250, EnumAction.BOW, false); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - caster.addPotionEffect(new PotionEffect(MobEffects.WATER_BREATHING, - (int)(1200 * modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)caster.posX + world.rand.nextFloat() * 2 - 1.0F); - double y1 = (double)((float)WizardryUtilities.getPlayerEyesPos(caster) - 0.5F + world.rand.nextFloat()); - double z1 = (double)((float)caster.posZ + world.rand.nextFloat() * 2 - 1.0F); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0, 0.1F, 0, - 48 + world.rand.nextInt(12), 0.3f, 0.3f, 1.0f); - } - } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/Whirlwind.java b/src/main/java/electroblob/wizardry/spell/Whirlwind.java index 526b8dbb..c3ff793e 100644 --- a/src/main/java/electroblob/wizardry/spell/Whirlwind.java +++ b/src/main/java/electroblob/wizardry/spell/Whirlwind.java @@ -3,36 +3,29 @@ package electroblob.wizardry.spell; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.item.EnumAction; import net.minecraft.network.play.server.SPacketEntityVelocity; -import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public class Whirlwind extends Spell { +public class Whirlwind extends SpellRay { public Whirlwind(){ - super(Tier.APPRENTICE, 10, Element.EARTH, "whirlwind", SpellType.DEFENCE, 15, EnumAction.NONE, false); + super("whirlwind", Tier.APPRENTICE, Element.EARTH, SpellType.DEFENCE, 10, 15, false, 10, WizardrySounds.SPELL_ICE); + this.soundValues(0.8f, 0.7f, 0.2f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + // Left as EntityLivingBase because why not be able to move armour stands around? - if(rayTrace != null && rayTrace.entityHit instanceof EntityLivingBase){ - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; + if(target instanceof EntityLivingBase){ if(!world.isRemote){ @@ -48,66 +41,31 @@ public class Whirlwind extends Spell { if(world.isRemote){ for(int i = 0; i < 10; i++){ - double x2 = (double)(caster.posX + world.rand.nextFloat() - 0.5F + double x = (double)(caster.posX + world.rand.nextFloat() - 0.5F + caster.getLookVec().x * caster.getDistance(target) * 0.5); - double y2 = (double)(WizardryUtilities.getPlayerEyesPos(caster) + world.rand.nextFloat() - 0.5F + double y = (double)(caster.getEntityBoundingBox().minY + caster.getEyeHeight() + world.rand.nextFloat() - 0.5F + caster.getLookVec().y * caster.getDistance(target) * 0.5); - double z2 = (double)(caster.posZ + world.rand.nextFloat() - 0.5F + double z = (double)(caster.posZ + world.rand.nextFloat() - 0.5F + caster.getLookVec().z * caster.getDistance(target) * 0.5); - world.spawnParticle(EnumParticleTypes.CLOUD, x2, y2, z2, caster.getLookVec().x, + world.spawnParticle(EnumParticleTypes.CLOUD, x, y, z, caster.getLookVec().x, caster.getLookVec().y, caster.getLookVec().z); - // Minecraft.getMinecraft().effectRenderer.addEffect(new EntitySparkleFX(world, x2, y2, z2, - // entityplayer.getLookVec().xCoord, entityplayer.getLookVec().yCoord, - // entityplayer.getLookVec().zCoord, null, 1.0f, 1.0f, 0.8f, 10)); } } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.8F, - world.rand.nextFloat() * 0.2F + 0.6F); + return true; } + return false; } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - target.motionX = caster.getLookVec().x * 2; - target.motionY = caster.getLookVec().y * 2 + 1; - target.motionZ = caster.getLookVec().z * 2; - - // Player motion is handled on that player's client so needs packets - if(target instanceof EntityPlayerMP){ - ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); - } - } - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x2 = (double)(caster.posX + world.rand.nextFloat() - 0.5F - + caster.getLookVec().x * caster.getDistance(target) * 0.5); - double y2 = (double)(caster.posY + caster.getEyeHeight() + world.rand.nextFloat() - 0.5F - + caster.getLookVec().y * caster.getDistance(target) * 0.5); - double z2 = (double)(caster.posZ + world.rand.nextFloat() - 0.5F - + caster.getLookVec().z * caster.getDistance(target) * 0.5); - world.spawnParticle(EnumParticleTypes.CLOUD, x2, y2, z2, caster.getLookVec().x, - caster.getLookVec().y, caster.getLookVec().z); - } - } - caster.swingArm(hand); - caster.playSound(WizardrySounds.SPELL_ICE, 0.8F, world.rand.nextFloat() * 0.2F + 0.6F); - return true; - } - + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - public boolean canBeCastByNPCs(){ - return true; + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; } } diff --git a/src/main/java/electroblob/wizardry/spell/Wither.java b/src/main/java/electroblob/wizardry/spell/Wither.java index 9234756d..bd356785 100644 --- a/src/main/java/electroblob/wizardry/spell/Wither.java +++ b/src/main/java/electroblob/wizardry/spell/Wither.java @@ -1,45 +1,38 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class Wither extends Spell { +public class Wither extends SpellRay { + + private static final int BASE_DURATION = 200; public Wither(){ - super(Tier.APPRENTICE, 10, Element.NECROMANCY, "wither", SpellType.ATTACK, 20, EnumAction.NONE, false); + super("wither", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 10, 20, false, 10, SoundEvents.ENTITY_WITHER_HURT); + this.soundValues(1, 1.1f, 0.2f); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, caster, - 10 * modifiers.get(WizardryItems.range_upgrade)); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.ENTITY && WizardryUtilities.isLiving(rayTrace.entityHit)){ - - EntityLivingBase target = (EntityLivingBase)rayTrace.entityHit; + protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ // Has no effect on withers or wither skeletons. if(MagicDamage.isEntityImmune(DamageType.WITHER, target)){ @@ -47,79 +40,31 @@ public class Wither extends Spell { this.getNameForTranslationFormatted())); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), - 1.0f * modifiers.get(SpellModifiers.DAMAGE)); - target.addPotionEffect(new PotionEffect(MobEffects.WITHER, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), 1)); + 1.0f * modifiers.get(SpellModifiers.POTENCY)); + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.WITHER, + (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1)); } - } - if(world.isRemote){ - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - // I figured it out! when on client side, entityplayer.posY is at the eyes, not the feet! - // This is a test for lining up the ray with the wand tip. Not sure if I like it or not. - /* Vec3d origin = Wizardry.proxy.getWandTipPosition(caster); double x1 = origin.xCoord + look.xCoord*i/2 - * + world.rand.nextFloat()/5 - 0.1f; double y1 = origin.yCoord + look.yCoord*i/2 + - * world.rand.nextFloat()/5 - 0.1f; double z1 = origin.zCoord + look.zCoord*i/2 + - * world.rand.nextFloat()/5 - 0.1f; */ - double x1 = caster.posX + look.x * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = WizardryUtilities.getPlayerEyesPos(caster) - 0.4f + look.y * i / 2 - + world.rand.nextFloat() / 5 - 0.1f; - double z1 = caster.posZ + look.z * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - // world.spawnParticle("mobSpell", x1, y1, z1, -1*look.xCoord, -1*look.yCoord, -1*look.zCoord); - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, 0, - 0.1f, 0.0f, 0.0f); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 0.1f, 0.0f, 0.05f); - } - } - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_HURT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - // Has no effect on withers or wither skeletons. - if(!MagicDamage.isEntityImmune(DamageType.WITHER, target) && !world.isRemote){ - target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), - 1.0f * modifiers.get(SpellModifiers.DAMAGE)); - target.addPotionEffect(new PotionEffect(MobEffects.WITHER, - (int)(200 * modifiers.get(WizardryItems.duration_upgrade)), 1)); - } - - if(world.isRemote){ - - double dx = (target.posX - caster.posX) / caster.getDistance(target); - double dy = (target.posY - caster.posY) / caster.getDistance(target); - double dz = (target.posZ - caster.posZ) / caster.getDistance(target); - - for(int i = 1; i < (int)(25 * modifiers.get(WizardryItems.range_upgrade)); i += 2){ - - double x1 = caster.posX + dx * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - double y1 = caster.posY + caster.getEyeHeight() - 0.4f + dy * i / 2 + world.rand.nextFloat() / 5 - - 0.1f; - double z1 = caster.posZ + dz * i / 2 + world.rand.nextFloat() / 5 - 0.1f; - - Wizardry.proxy.spawnParticle(Type.DARK_MAGIC, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 0, 0.1f, 0.0f, 0.0f); - Wizardry.proxy.spawnParticle(Type.SPARKLE, world, x1, y1, z1, 0.0d, 0.0d, 0.0d, - 12 + world.rand.nextInt(8), 0.1f, 0.0f, 0.05f); - } - } - caster.swingArm(hand); - caster.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + return true; } - + return false; } @Override - public boolean canBeCastByNPCs(){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ return true; } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(0.1f, 0, 0.05f).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/spell/WitherSkull.java b/src/main/java/electroblob/wizardry/spell/WitherSkull.java index b6bd4549..85a8b363 100644 --- a/src/main/java/electroblob/wizardry/spell/WitherSkull.java +++ b/src/main/java/electroblob/wizardry/spell/WitherSkull.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; public class WitherSkull extends Spell { public WitherSkull(){ - super(Tier.ADVANCED, 20, Element.NECROMANCY, "wither_skull", SpellType.ATTACK, 30, EnumAction.NONE, false); + super("wither_skull", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 20, 30, EnumAction.NONE, false); } @Override diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index c09fe325..0b7e7c10 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -4,6 +4,7 @@ import java.util.Random; import electroblob.wizardry.Wizardry; import net.minecraft.entity.Entity; +import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; @@ -375,4 +376,21 @@ public final class ParticleBuilder { entity = null; } + // Methods for spawning specific effects (similar to the FX playing methods with the ids in RenderGlobal) + + /** Spawns spark and large smoke particles (8 of each) within a 1x1x1 volume centred on the given position. */ + public static void spawnShockParticles(World world, double x, double y, double z) { + double px, py, pz; + for(int i=0; i<8; i++){ + px = x + world.rand.nextDouble() - 0.5; + py = y + world.rand.nextDouble() - 0.5; + pz = z + world.rand.nextDouble() - 0.5; + ParticleBuilder.create(Type.SPARK).pos(px, py, pz).spawn(world); + px = x + world.rand.nextDouble() - 0.5; + py = y + world.rand.nextDouble() - 0.5; + pz = z + world.rand.nextDouble() - 0.5; + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, px, py, pz, 0, 0, 0); + } + } + } diff --git a/src/main/java/electroblob/wizardry/util/SpellModifiers.java b/src/main/java/electroblob/wizardry/util/SpellModifiers.java index bbb7c08c..59155a29 100644 --- a/src/main/java/electroblob/wizardry/util/SpellModifiers.java +++ b/src/main/java/electroblob/wizardry/util/SpellModifiers.java @@ -40,8 +40,8 @@ import net.minecraftforge.fml.common.network.ByteBufUtils; // fly. public final class SpellModifiers { - /** Constant string identifier for the damage modifier. All the other modifiers in Wizardry have items. */ - public static final String DAMAGE = "damage"; + /** Constant string identifier for the potency modifier. All the other modifiers in Wizardry have items. */ + public static final String POTENCY = "potency"; private Map multiplierMap; private Map syncedMultiplierMap; diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index 1e15ef13..6fc8622d 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -53,6 +53,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.ReflectionHelper; import net.minecraftforge.fml.relauncher.Side; @@ -238,15 +239,15 @@ public final class WizardryUtilities { } /** - * Gets a random position on the ground near the player within the specified horizontal and vertical ranges. Used to - * find a position to spawn entities in summoning spells. + * Gets a random position on the ground near the given entity within the specified horizontal and vertical ranges. + * Used to find a position to spawn entities in summoning spells. * - * @param entity The entity around which to search + * @param entity The entity around which to search. * @param horizontalRange The maximum number of blocks on the x or z axis the returned position can be from the * given entity. The number of operations performed by this method is proportional to the square of this * parameter, so for performance reasons it is recommended that it does not exceed around 10. * @param verticalRange The maximum number of blocks on the y axis the returned position can be from the given - * entity + * entity. * @return A BlockPos with the coordinates of the block directly above the ground at the position found, or null if * none were found within range. Importantly, since this method checks all possible positions within * range (i.e. randomness only occurs when deciding between the possible positions), if it returns null once @@ -257,8 +258,31 @@ public final class WizardryUtilities { public static BlockPos findNearbyFloorSpace(Entity entity, int horizontalRange, int verticalRange){ World world = entity.world; - List possibleLocations = new ArrayList(); BlockPos origin = new BlockPos(entity); + return findNearbyFloorSpace(world, origin, horizontalRange, verticalRange); + } + + /** + * Gets a random position on the ground near the given BlockPos within the specified horizontal and vertical ranges. + * Used to find a position to spawn entities in summoning spells. + * + * @param world The world in which to search. + * @param origin The BlockPos around which to search. + * @param horizontalRange The maximum number of blocks on the x or z axis the returned position can be from the + * given position. The number of operations performed by this method is proportional to the square of this + * parameter, so for performance reasons it is recommended that it does not exceed around 10. + * @param verticalRange The maximum number of blocks on the y axis the returned position can be from the given + * position. + * @return A BlockPos with the coordinates of the block directly above the ground at the position found, or null if + * none were found within range. Importantly, since this method checks all possible positions within + * range (i.e. randomness only occurs when deciding between the possible positions), if it returns null once + * then it will always return null given the same circumstances and parameters. What this means is that you + * can (and should) immediately stop trying to cast a summoning spell if this returns null. + */ + @Nullable + public static BlockPos findNearbyFloorSpace(World world, BlockPos origin, int horizontalRange, int verticalRange){ + + List possibleLocations = new ArrayList(); for(int x = -horizontalRange; x <= horizontalRange; x++){ for(int z = -horizontalRange; z <= horizontalRange; z++){ @@ -272,7 +296,6 @@ public final class WizardryUtilities { }else{ return possibleLocations.get(world.rand.nextInt(possibleLocations.size())); } - } /** @@ -424,23 +447,6 @@ public final class WizardryUtilities { target.knockBack(null, 0.4f, dx, dz); } - // Just what benefit does having posY be the eye position on the first person client actually give? - - /** - * Gets the y coordinate of the given player's eyes. This is to cover an inconsistency between the value of - * EntityPlayer.posY on the first person client and everywhere else; in first person (i.e. when - * Minecraft.getMinecraft().player == player) player.posY is the eye position, but everywhere else it is the feet - * position. This is intended for use when spawning particles, since this is the only situation where the - * discrepancy is likely to matter. - *

- * As of Wizardry 1.2, this is just a shorthand for: - *

- *

player.getEntityBoundingBox().minY + player.getEyeHeight()
- */ - public static double getPlayerEyesPos(EntityPlayer player){ - return player.getEntityBoundingBox().minY + player.getEyeHeight(); - } - /** * Returns a list of the itemstacks in the given player's hotbar. Defined here for convenience and to centralise the * (unfortunately unavoidable) use of hardcoded numbers to reference the inventory slots. The returned list is a @@ -509,6 +515,17 @@ public final class WizardryUtilities { public static boolean isPlayerOp(EntityPlayer player, MinecraftServer server){ return server.getPlayerList().getOppedPlayers().getEntry(player.getGameProfile()) != null; } + + /** Returns the default aiming arror used by skeletons for the given difficulty. For reference, these are: Easy - 10, + * Normal - 6, Hard - 2, Peaceful - 10 (rarely used). */ + public static int getDefaultAimingError(EnumDifficulty difficulty){ + switch(difficulty){ + case EASY: return 10; + case NORMAL: return 6; + case HARD: return 2; + default: return 10; // Peaceful counts as easy; the only time this is used is when a player attacks a (good) wizard. + } + } /** * Returns true if the given entity is an EntityLivingBase and not an armour stand; makes the code a bit neater. @@ -539,7 +556,7 @@ public final class WizardryUtilities { * Does a block ray trace (NOT entities) from an entity's eyes (i.e. properly...) */ @Nullable - public static RayTraceResult rayTrace(double range, World world, EntityLivingBase entity, boolean hitLiquids){ + public static RayTraceResult standardBlockRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids){ Vec3d start = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); Vec3d look = entity.getLookVec(); @@ -557,16 +574,8 @@ public final class WizardryUtilities { * @return */ @Nullable - public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range){ - double dx = entity.getLookVec().x * range; - double dy = entity.getLookVec().y * range; - double dz = entity.getLookVec().z * range; - HashSet hashset = new HashSet(1); - hashset.add(entity); - return WizardryUtilities.tracePath(world, (float)entity.posX, - (float)(entity.getEntityBoundingBox().minY + entity.getEyeHeight()), (float)entity.posZ, - (float)(entity.posX + dx), (float)(entity.posY + entity.getEyeHeight() + dy), (float)(entity.posZ + dz), - 1.0f, hashset, false); + public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids){ + return standardEntityRayTrace(world, entity, range, 1, hitLiquids); } /** @@ -580,8 +589,7 @@ public final class WizardryUtilities { * @return */ @Nullable - public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range, - float borderSize){ + public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range, float borderSize, boolean hitLiquids){ double dx = entity.getLookVec().x * range; double dy = entity.getLookVec().y * range; double dz = entity.getLookVec().z * range; @@ -590,12 +598,11 @@ public final class WizardryUtilities { return WizardryUtilities.tracePath(world, (float)entity.posX, (float)(entity.getEntityBoundingBox().minY + entity.getEyeHeight()), (float)entity.posZ, (float)(entity.posX + dx), (float)(entity.posY + entity.getEyeHeight() + dy), (float)(entity.posZ + dz), - borderSize, hashset, false); + borderSize, hashset, false, hitLiquids); } /** - * Method for ray tracing entities (the useless default method doesn't work, despite EnumHitType having an ENTITY - * field...) You can also use this for seeking. + * Method for ray tracing entities. You can also use this for seeking. * * @param world * @param x startX @@ -611,7 +618,7 @@ public final class WizardryUtilities { */ @Nullable public static RayTraceResult tracePath(World world, float x, float y, float z, float tx, float ty, float tz, - float borderSize, HashSet excluded, boolean collideablesOnly){ + float borderSize, HashSet excluded, boolean collideablesOnly, boolean hitLiquids){ Vec3d startVec = new Vec3d(x, y, z); // Vec3d lookVec = new Vec3d(tx-x, ty-y, tz-z); @@ -622,10 +629,9 @@ public final class WizardryUtilities { float maxX = x > tx ? x : tx; float maxY = y > ty ? y : ty; float maxZ = z > tz ? z : tz; - AxisAlignedBB bb = new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ).grow(borderSize, borderSize, - borderSize); + AxisAlignedBB bb = new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ).grow(borderSize, borderSize, borderSize); List allEntities = world.getEntitiesWithinAABBExcludingEntity(null, bb); - RayTraceResult blockHit = world.rayTraceBlocks(startVec, endVec); + RayTraceResult blockHit = world.rayTraceBlocks(startVec, endVec, hitLiquids); startVec = new Vec3d(x, y, z); endVec = new Vec3d(tx, ty, tz); float maxDistance = (float)endVec.distanceTo(startVec); From 106148fd9ee8cb758f272d59792b8198d1aaad17 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:28:56 +0100 Subject: [PATCH 16/68] Miscellaneous cleanup and commenting --- .../java/electroblob/wizardry/WizardData.java | 3 +-- .../wizardry/client/ClientProxy.java | 24 +++++++++---------- .../wizardry/entity/EntityMeteor.java | 3 +-- .../wizardry/entity/living/EntityWizard.java | 2 +- .../electroblob/wizardry/item/ItemScroll.java | 1 - .../wizardry/util/ParticleBuilder.java | 9 +++++-- .../wizardry/util/WizardryUtilities.java | 4 ++-- 7 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/main/java/electroblob/wizardry/WizardData.java b/src/main/java/electroblob/wizardry/WizardData.java index 03ef8f86..bd779fef 100644 --- a/src/main/java/electroblob/wizardry/WizardData.java +++ b/src/main/java/electroblob/wizardry/WizardData.java @@ -526,8 +526,7 @@ public class WizardData implements INBTSerializable { // THIS is why I wrote the list/map <-> NBT methods. Look how neat this is! properties.setTag("allies", WizardryUtilities.listToNBT(this.allies, WizardryUtilities::UUIDtoTagCompound)); properties.setTag("allyNames", WizardryUtilities.listToNBT(this.allyNames, NBTTagString::new)); - properties.setTag("soulboundCreatures", - WizardryUtilities.listToNBT(this.soulboundCreatures, WizardryUtilities::UUIDtoTagCompound)); + properties.setTag("soulboundCreatures", WizardryUtilities.listToNBT(this.soulboundCreatures, WizardryUtilities::UUIDtoTagCompound)); // Might be worth converting this over to WizardryUtilities.listToNBT. int[] spells = new int[this.spellsDiscovered.size()]; diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 411fdc59..5e978c33 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -277,18 +277,18 @@ public class ClientProxy extends CommonProxy { factories = new HashMap<>(); - factories.put(Type.BLIZZARD, (world, x, y, z) -> new ParticleBlizzard(world, x, y, z)); - factories.put(Type.DARK_MAGIC, (world, x, y, z) -> new ParticleDarkMagic(world, x, y, z)); - factories.put(Type.DUST, (world, x, y, z) -> new ParticleDust(world, x, y, z)); - factories.put(Type.FLASH, (world, x, y, z) -> new ParticleFlash(world, x, y, z)); - factories.put(Type.ICE, (world, x, y, z) -> new ParticleIce(world, x, y, z)); - factories.put(Type.LEAF, (world, x, y, z) -> new ParticleLeaf(world, x, y, z)); - factories.put(Type.MAGIC_BUBBLE, (world, x, y, z) -> new ParticleMagicBubble(world, x, y, z)); - factories.put(Type.MAGIC_FIRE, (world, x, y, z) -> new ParticleMagicFlame(world, x, y, z)); - factories.put(Type.PATH, (world, x, y, z) -> new ParticlePath(world, x, y, z)); - factories.put(Type.SNOW, (world, x, y, z) -> new ParticleSnow(world, x, y, z)); - factories.put(Type.SPARK, (world, x, y, z) -> new ParticleSpark(world, x, y, z)); - factories.put(Type.SPARKLE, (world, x, y, z) -> new ParticleSparkle(world, x, y, z)); + factories.put(Type.BLIZZARD, (world, x, y, z) -> new ParticleBlizzard(world, x, y, z)); + factories.put(Type.DARK_MAGIC, (world, x, y, z) -> new ParticleDarkMagic(world, x, y, z)); + factories.put(Type.DUST, (world, x, y, z) -> new ParticleDust(world, x, y, z)); + factories.put(Type.FLASH, (world, x, y, z) -> new ParticleFlash(world, x, y, z)); + factories.put(Type.ICE, (world, x, y, z) -> new ParticleIce(world, x, y, z)); + factories.put(Type.LEAF, (world, x, y, z) -> new ParticleLeaf(world, x, y, z)); + factories.put(Type.MAGIC_BUBBLE, (world, x, y, z) -> new ParticleMagicBubble(world, x, y, z)); + factories.put(Type.MAGIC_FIRE, (world, x, y, z) -> new ParticleMagicFlame(world, x, y, z)); + factories.put(Type.PATH, (world, x, y, z) -> new ParticlePath(world, x, y, z)); + factories.put(Type.SNOW, (world, x, y, z) -> new ParticleSnow(world, x, y, z)); + factories.put(Type.SPARK, (world, x, y, z) -> new ParticleSpark(world, x, y, z)); + factories.put(Type.SPARKLE, (world, x, y, z) -> new ParticleSparkle(world, x, y, z)); factories.put(Type.SPARKLE_ROTATING, (world, x, y, z) -> new ParticleRotatingSparkle(world, x, y, z)); } diff --git a/src/main/java/electroblob/wizardry/entity/EntityMeteor.java b/src/main/java/electroblob/wizardry/entity/EntityMeteor.java index 53e3a87d..14784b3f 100644 --- a/src/main/java/electroblob/wizardry/entity/EntityMeteor.java +++ b/src/main/java/electroblob/wizardry/entity/EntityMeteor.java @@ -17,8 +17,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; public class EntityMeteor extends EntityFallingBlock { /** - * The entity blast multiplier. Only some projectiles cause a blast, which is why this isn't in - * EntityMagicProjectile. + * The entity blast multiplier. */ public float blastMultiplier; diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 339e6f41..9c3a474f 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -134,7 +134,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp this.tasks.addTask(0, new EntityAISwimming(this)); // Why would you go to the effort of making the IMerchant interface and then have the AI classes only accept - // EntityVillager? N + // EntityVillager? this.tasks.addTask(1, new EntityAITradePlayer(this)); this.tasks.addTask(1, new EntityAILookAtTradePlayer(this)); this.tasks.addTask(4, new EntityAIRestrictOpenDoor(this)); diff --git a/src/main/java/electroblob/wizardry/item/ItemScroll.java b/src/main/java/electroblob/wizardry/item/ItemScroll.java index 079927d5..e70f730e 100644 --- a/src/main/java/electroblob/wizardry/item/ItemScroll.java +++ b/src/main/java/electroblob/wizardry/item/ItemScroll.java @@ -60,7 +60,6 @@ public class ItemScroll extends Item { * server side, but the result to then be sent to the client, which means broken discovery system. Simply put, I * can't predict that, and it's not my job to cater for other people's incorrect usage of code, especially when * that might compromise some perfectly reasonable use (think Bibliocraft's 'best guess' book detection). */ - // TODO: Backport this proxy-based fix. return Wizardry.proxy.getScrollDisplayName(stack); } diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index 0b7e7c10..a4ea6725 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -32,7 +32,7 @@ import net.minecraft.world.World; *

* ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).colour(r, g, b).spawn(world); * @author Electroblob - * @since Wizardry 4.2.0 + * @since Wizardry 4.2 */ public final class ParticleBuilder { @@ -58,7 +58,7 @@ public final class ParticleBuilder { private Entity entity; /** Enum constants representing the different types of particle added by wizardry. As of 4.2.0, this has been moved - * from its own file {@code Type} to inside {@link ParticleBuilder}. This allowed its name to be + * from its own file {@code WizardryParticleType} to inside {@link ParticleBuilder}. This allowed its name to be * shortened to simply {@code Type}, making most references more concise. References in classes where another * {@code Type} is also used can simply refer to the full name, {@code ParticleBuilder.Type}, which is no more verbose * than before. @@ -87,6 +87,11 @@ public final class ParticleBuilder { // Convenience methods + // These may seem to go against the whole point of this class, but of course they return the ParticleBuilder instance + // so anything else can still be chained onto them - centralising commonly-used particle spawning patterns without + // losing any of the flexibility of the particle builder. In addition, callers of these methods are still free to + // change any of the parameters that were set within them afterwards. + /** * Starts building a particle of the given type. Static convenience version of * {@link ParticleBuilder#particle(Type)}; makes code more concise. diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index 6fc8622d..d9578fd6 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -464,7 +464,7 @@ public final class WizardryUtilities { /** * Returns a list of the itemstacks in the given player's hotbar and offhand, sorted into the following order: main - * hand, offhand, rest of hotbar left-to-right. The returned list is a modifiable copy of part of the player's + * hand, offhand, rest of hotbar left-to-right. The returned list is a modifiable shallow copy of part of the player's * inventory stack list; as such, changes to the list are not written through to the player's inventory. * However, the ItemStack instances themselves are not copied, so changes to any of their fields (size, metadata...) * will change those in the player's inventory. @@ -983,7 +983,7 @@ public final class WizardryUtilities { *

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

* {@link ParticleBuilder#instance} retrieves the static instance of the particle builder. Use * {@link ParticleBuilder#particle(Type)} to start building a particle, or alternatively use the static @@ -335,6 +336,14 @@ public final class ParticleBuilder { if(y < 0 && entity == null) Wizardry.logger.warn("Spawning particle below y = 0 - are you sure the position/entity" + "has been set correctly?"); + if(!world.isRemote){ + Wizardry.logger.warn("ParticleBuilder.spawn(...) called on the server side! ParticleBuilder has prevented a" + + "server crash, but calling it on the server will do nothing. Consider adding a world.isRemote check."); + // Must stop here because the line after this if statement would crash the server! + reset(); + return; + } + electroblob.wizardry.client.particle.ParticleWizardry particle = Wizardry.proxy.createParticle(type, world, x, y, z); if(particle == null){ From be952e65f49765c34b8a52efe9aea2f4ad9d3e6e Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:33:53 +0100 Subject: [PATCH 20/68] Fix incorrect position input in ParticleBuilder's spherical particle spawning convenience method --- .../electroblob/wizardry/util/ParticleBuilder.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index 06f1313b..880b437f 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -141,13 +141,13 @@ public final class ParticleBuilder { */ public static ParticleBuilder create(Type type, Random random, double x, double y, double z, double radius, boolean move){ - double px = x + (random.nextDouble() - 0.5D) * radius; - double py = y + (random.nextDouble() - 0.5D) * radius; - double pz = z + (random.nextDouble() - 0.5D) * radius; + double px = x + (random.nextDouble()*2 - 1) * radius; + double py = y + (random.nextDouble()*2 - 1) * radius; + double pz = z + (random.nextDouble()*2 - 1) * radius; - if(move) return ParticleBuilder.instance.particle(type).pos(x, y, z).vel(px-x, py-y, pz-z); + if(move) return ParticleBuilder.instance.particle(type).pos(px, py, pz).vel(px-x, py-y, pz-z); - return ParticleBuilder.instance.particle(type).pos(x, y, z); + return ParticleBuilder.instance.particle(type).pos(px, py, pz); } // Core builder methods From 2301e54de438dfe220d7c991f0c2cdc042b53e14 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:35:07 +0100 Subject: [PATCH 21/68] Prevent potions with custom particles from mixing their particle colour (black) with other potions --- .../potion/ICustomPotionParticles.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java b/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java index 8bc4a30c..c1c565ff 100644 --- a/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java +++ b/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java @@ -1,18 +1,23 @@ package electroblob.wizardry.potion; +import java.util.stream.Collectors; + import net.minecraft.potion.PotionEffect; +import net.minecraft.potion.PotionUtils; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.event.entity.living.PotionColorCalculationEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; /** * Interface for potion effects that spawn custom particles instead of (or as well as) the vanilla 'swirly' particles. + * To hide the vanilla 'swirly' particles, set the potion's liquid colour to 0 (black). By default, potions that implement + * this interface no longer mix their colour with other potions. * * @author Electroblob * @since Wizardry 1.2 */ -// TODO: Backport. @Mod.EventBusSubscriber public interface ICustomPotionParticles { @@ -26,6 +31,11 @@ public interface ICustomPotionParticles { * @param z The z coordinate of the particle, already set to a random value within the entity's bounding box. */ void spawnCustomParticle(World world, double x, double y, double z); + + /** Returns true if this potion should mix its colour with others, false if not. Defaults to false. */ + default boolean shouldMixColour(){ + return false; + } @SubscribeEvent public static void onLivingUpdateEvent(LivingUpdateEvent event){ @@ -42,10 +52,17 @@ public interface ICustomPotionParticles { double z = event.getEntityLiving().posZ + (event.getEntityLiving().world.rand.nextDouble() - 0.5) * event.getEntityLiving().width; - ((ICustomPotionParticles)effect.getPotion()).spawnCustomParticle(event.getEntityLiving().world, x, - y, z); + ((ICustomPotionParticles)effect.getPotion()).spawnCustomParticle(event.getEntityLiving().world, x, y, z); } } } } + + @SubscribeEvent + // Prevents instances of this interface for which shouldMixColour() returns false from affecting mixed potion colours + public static void onPotionColourCalculationEvent(PotionColorCalculationEvent event){ + event.setColor(PotionUtils.getPotionColorFromEffectList(event.getEffects().stream().filter( + p -> !(p instanceof ICustomPotionParticles && !((ICustomPotionParticles)p).shouldMixColour())) + .collect(Collectors.toList()))); + } } From 8f0727403d62601ae21df111e0841de32fa2d641 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:36:15 +0100 Subject: [PATCH 22/68] Correct fallback translation key for spirit horse --- .../electroblob/wizardry/entity/living/EntitySpiritHorse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java index 49ff3a66..efd656d0 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java @@ -43,7 +43,7 @@ public class EntitySpiritHorse extends EntityHorse { if(this.hasCustomName()){ return this.getCustomNameTag(); }else{ - return I18n.translateToLocal("entity.wizardry.Spirit Horse.name"); + return I18n.translateToLocal("entity.wizardry.spirit_horse.name"); } } From c3abdcf68b3a9b8edf1e2a4fd2678f8ebc8dc476 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:57:05 +0100 Subject: [PATCH 23/68] Fix NPE in immunity initialisation, fixes #49 --- src/main/java/electroblob/wizardry/util/MagicDamage.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/util/MagicDamage.java b/src/main/java/electroblob/wizardry/util/MagicDamage.java index 40b46da0..5055c9ff 100644 --- a/src/main/java/electroblob/wizardry/util/MagicDamage.java +++ b/src/main/java/electroblob/wizardry/util/MagicDamage.java @@ -1,5 +1,6 @@ package electroblob.wizardry.util; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -164,7 +165,8 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage /** Adds the passed in damage type to the list of damage types to which the given entity is immune. */ public static void addEntityImmunity(Class entityType, DamageType immunity){ - List immunities = Arrays.asList(immunityMapping.get(entityType)); + List immunities = immunityMapping.get(entityType) == null ? new ArrayList() + : Arrays.asList(immunityMapping.get(entityType)); immunities.add(immunity); // Apparently putting 0 here works just fine. immunityMapping.put(entityType, immunities.toArray(new DamageType[0])); From c7c7d57e7e13c35cf0ab9b267fb0b8957b030e86 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:58:50 +0100 Subject: [PATCH 24/68] Change target blacklist/whitelist checking to use the correct method for retrieving an entity key from EntityList --- .../electroblob/wizardry/entity/living/EntityWizard.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 9114aeba..7214304e 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -158,10 +158,11 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp if((entity instanceof IMob || entity instanceof ISummonedCreature // ... or in the whitelist ... || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist) - .contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))) + .contains(EntityList.getKey(entity.getClass()))) // ... and isn't in the blacklist ... && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist) - .contains(EntityList.getEntityString(entity).toLowerCase(Locale.ROOT))){ + .contains(EntityList.getKey(entity.getClass()))){ + // ... it can be attacked. return true; } } From f3c9fbdd2e0e675552dd5c06454dfa8bfcb18b60 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 12:23:08 +0100 Subject: [PATCH 25/68] Move GUI classes to separate package --- .../client/{ => gui}/GuiArcaneWorkbench.java | 20 +++++++++---------- .../client/{ => gui}/GuiButtonApply.java | 2 +- .../client/{ => gui}/GuiButtonInvisible.java | 2 +- .../client/{ => gui}/GuiButtonTurnPage.java | 2 +- .../client/{ => gui}/GuiConfigWizardry.java | 2 +- .../client/{ => gui}/GuiPortableCrafting.java | 2 +- .../client/{ => gui}/GuiSpellBook.java | 2 +- .../client/{ => gui}/GuiSpellDisplay.java | 2 +- .../client/{ => gui}/GuiWizardHandbook.java | 3 ++- 9 files changed, 19 insertions(+), 18 deletions(-) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiArcaneWorkbench.java (91%) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiButtonApply.java (96%) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiButtonInvisible.java (93%) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiButtonTurnPage.java (97%) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiConfigWizardry.java (99%) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiPortableCrafting.java (97%) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiSpellBook.java (99%) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiSpellDisplay.java (99%) rename src/main/java/electroblob/wizardry/client/{ => gui}/GuiWizardHandbook.java (99%) diff --git a/src/main/java/electroblob/wizardry/client/GuiArcaneWorkbench.java b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java similarity index 91% rename from src/main/java/electroblob/wizardry/client/GuiArcaneWorkbench.java rename to src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java index 453b71ee..a560abd5 100644 --- a/src/main/java/electroblob/wizardry/client/GuiArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import org.lwjgl.input.Keyboard; @@ -54,8 +54,8 @@ public class GuiArcaneWorkbench extends GuiContainer { public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_){ // Tests if there is a wand in the workbench and edits the positioning accordingly - if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots - .getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){ + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots + .getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){ xSize = xSizeNoTip + tooltipWidth; guiLeft = (this.width - this.xSize) / 2; this.applyBtn.x = (this.width - tooltipWidth) / 2 + 48; @@ -65,7 +65,7 @@ public class GuiArcaneWorkbench extends GuiContainer { this.applyBtn.x = this.width / 2 + 48; } - if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack()){ + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){ this.applyBtn.enabled = true; }else{ this.applyBtn.enabled = false; @@ -94,8 +94,8 @@ public class GuiArcaneWorkbench extends GuiContainer { } // Tooltip only drawn if there is a wand - if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots - .getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){ + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots + .getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){ // Tooltip box drawTexturedModalRect(guiLeft + xSizeNoTip, guiTop, xSizeNoTip, 0, 256 - xSizeNoTip - 4, ySize); @@ -103,7 +103,7 @@ public class GuiArcaneWorkbench extends GuiContainer { drawTexturedModalRect(guiLeft + xSize - (256 - xSizeNoTip - 4), guiTop, xSizeNoTip + 4, 0, 256 - xSizeNoTip - 4, ySize); - ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack(); + ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack(); Spell[] spells = WandHelper.getSpells(wand); @@ -161,10 +161,10 @@ public class GuiArcaneWorkbench extends GuiContainer { this.fontRenderer.drawString(this.playerInventory.hasCustomName() ? this.playerInventory.getName() : I18n.format(this.playerInventory.getName()), 8, this.ySize - 96 + 2, 4210752); - if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots - .getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){ + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots + .getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){ - ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack(); + ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack(); this.fontRenderer.drawStringWithShadow("\u00A7f" + wand.getDisplayName(), xSizeNoTip + 6, 6, 0); this.fontRenderer.drawStringWithShadow( diff --git a/src/main/java/electroblob/wizardry/client/GuiButtonApply.java b/src/main/java/electroblob/wizardry/client/gui/GuiButtonApply.java similarity index 96% rename from src/main/java/electroblob/wizardry/client/GuiButtonApply.java rename to src/main/java/electroblob/wizardry/client/gui/GuiButtonApply.java index 195327e8..a18d9668 100644 --- a/src/main/java/electroblob/wizardry/client/GuiButtonApply.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiButtonApply.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.WizardryUtilities; diff --git a/src/main/java/electroblob/wizardry/client/GuiButtonInvisible.java b/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java similarity index 93% rename from src/main/java/electroblob/wizardry/client/GuiButtonInvisible.java rename to src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java index 70e9c2e4..c80db3af 100644 --- a/src/main/java/electroblob/wizardry/client/GuiButtonInvisible.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; diff --git a/src/main/java/electroblob/wizardry/client/GuiButtonTurnPage.java b/src/main/java/electroblob/wizardry/client/gui/GuiButtonTurnPage.java similarity index 97% rename from src/main/java/electroblob/wizardry/client/GuiButtonTurnPage.java rename to src/main/java/electroblob/wizardry/client/gui/GuiButtonTurnPage.java index 2bdeb44e..f9c7a8cd 100644 --- a/src/main/java/electroblob/wizardry/client/GuiButtonTurnPage.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiButtonTurnPage.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.WizardryUtilities; diff --git a/src/main/java/electroblob/wizardry/client/GuiConfigWizardry.java b/src/main/java/electroblob/wizardry/client/gui/GuiConfigWizardry.java similarity index 99% rename from src/main/java/electroblob/wizardry/client/GuiConfigWizardry.java rename to src/main/java/electroblob/wizardry/client/gui/GuiConfigWizardry.java index 4da979bf..7e7fc01e 100644 --- a/src/main/java/electroblob/wizardry/client/GuiConfigWizardry.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiConfigWizardry.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/electroblob/wizardry/client/GuiPortableCrafting.java b/src/main/java/electroblob/wizardry/client/gui/GuiPortableCrafting.java similarity index 97% rename from src/main/java/electroblob/wizardry/client/GuiPortableCrafting.java rename to src/main/java/electroblob/wizardry/client/gui/GuiPortableCrafting.java index 5fc05f3a..88162dbf 100644 --- a/src/main/java/electroblob/wizardry/client/GuiPortableCrafting.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiPortableCrafting.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; diff --git a/src/main/java/electroblob/wizardry/client/GuiSpellBook.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java similarity index 99% rename from src/main/java/electroblob/wizardry/client/GuiSpellBook.java rename to src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java index fcfb2366..2d78b219 100644 --- a/src/main/java/electroblob/wizardry/client/GuiSpellBook.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import org.lwjgl.input.Keyboard; diff --git a/src/main/java/electroblob/wizardry/client/GuiSpellDisplay.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java similarity index 99% rename from src/main/java/electroblob/wizardry/client/GuiSpellDisplay.java rename to src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java index 0f905882..10088ab2 100644 --- a/src/main/java/electroblob/wizardry/client/GuiSpellDisplay.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import java.util.List; diff --git a/src/main/java/electroblob/wizardry/client/GuiWizardHandbook.java b/src/main/java/electroblob/wizardry/client/gui/GuiWizardHandbook.java similarity index 99% rename from src/main/java/electroblob/wizardry/client/GuiWizardHandbook.java rename to src/main/java/electroblob/wizardry/client/gui/GuiWizardHandbook.java index 98fa241e..b3e5d884 100644 --- a/src/main/java/electroblob/wizardry/client/GuiWizardHandbook.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiWizardHandbook.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui; import java.io.BufferedReader; import java.io.IOException; @@ -13,6 +13,7 @@ import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.GL11; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.ClientProxy; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; From 6da42a18c7b91c858415744b00a946692c04ec15 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 12:45:49 +0100 Subject: [PATCH 26/68] Update references to moved GUI classes --- .../java/electroblob/wizardry/WizardryGuiFactory.java | 2 +- .../java/electroblob/wizardry/WizardryGuiHandler.java | 10 +++++----- .../java/electroblob/wizardry/client/ClientProxy.java | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/electroblob/wizardry/WizardryGuiFactory.java b/src/main/java/electroblob/wizardry/WizardryGuiFactory.java index 19951840..169c473e 100644 --- a/src/main/java/electroblob/wizardry/WizardryGuiFactory.java +++ b/src/main/java/electroblob/wizardry/WizardryGuiFactory.java @@ -2,7 +2,7 @@ package electroblob.wizardry; import java.util.Set; -import electroblob.wizardry.client.GuiConfigWizardry; +import electroblob.wizardry.client.gui.GuiConfigWizardry; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraftforge.fml.client.IModGuiFactory; diff --git a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java index f3dffaa6..13cfaaa6 100644 --- a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java @@ -40,20 +40,20 @@ public class WizardryGuiHandler implements IGuiHandler { if(id == ARCANE_WORKBENCH){ TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z)); if(tileEntity instanceof TileEntityArcaneWorkbench){ - return new electroblob.wizardry.client.GuiArcaneWorkbench(player.inventory, + return new electroblob.wizardry.client.gui.GuiArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench)tileEntity); } }else if(id == WIZARD_HANDBOOK && (player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook || player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook)){ - return new electroblob.wizardry.client.GuiWizardHandbook(); + return new electroblob.wizardry.client.gui.GuiWizardHandbook(); }else if(id == SPELL_BOOK){ if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){ - return new electroblob.wizardry.client.GuiSpellBook(Spell.get(player.getHeldItemMainhand().getItemDamage())); + return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.get(player.getHeldItemMainhand().getItemDamage())); }else if(player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){ - return new electroblob.wizardry.client.GuiSpellBook(Spell.get(player.getHeldItemOffhand().getItemDamage())); + return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.get(player.getHeldItemOffhand().getItemDamage())); } }else if(id == PORTABLE_CRAFTING){ - return new electroblob.wizardry.client.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z)); + return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z)); } return null; } diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 5e978c33..cd68ad7c 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -10,6 +10,8 @@ import electroblob.wizardry.CommonProxy; import electroblob.wizardry.SpellGlyphData; import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.gui.GuiSpellDisplay; +import electroblob.wizardry.client.gui.GuiWizardHandbook; import electroblob.wizardry.client.model.ModelWizardArmour; import electroblob.wizardry.client.particle.ParticleBlizzard; import electroblob.wizardry.client.particle.ParticleBuff; From 75e5de603ef0f658b4ff45f2f272f21eb1139026 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 12:52:55 +0100 Subject: [PATCH 27/68] Delegate workbench apply button and slot behaviour to item classes --- .../wizardry/item/IWorkbenchItem.java | 56 +++ .../wizardry/item/ItemBlankScroll.java | 56 +++ .../electroblob/wizardry/item/ItemWand.java | 145 ++++++- .../wizardry/item/ItemWizardArmour.java | 53 ++- .../tileentity/ContainerArcaneWorkbench.java | 388 +++++------------- ...WandArmour.java => SlotWorkbenchItem.java} | 15 +- .../tileentity/TileEntityArcaneWorkbench.java | 19 +- 7 files changed, 423 insertions(+), 309 deletions(-) create mode 100644 src/main/java/electroblob/wizardry/item/IWorkbenchItem.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemBlankScroll.java rename src/main/java/electroblob/wizardry/tileentity/{SlotWandArmour.java => SlotWorkbenchItem.java} (59%) diff --git a/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java b/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java new file mode 100644 index 00000000..22af5327 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java @@ -0,0 +1,56 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.event.SpellBindEvent; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +/** + * Items that implement this interface may be placed in the central slot of the arcane workbench as long as + * {@link IWorkbenchItem#canPlace(ItemStack)} returns true.The number of spell book slots displayed is also specified + * using {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}. + *

+ * Items that implement this interface define what happens if they are in the central slot of the arcane workbench and + * the apply button is pressed, in {@link IWorkbenchItem#onApplyButtonPressed(EntityPlayer, Slot, Slot, Slot, Slot[])}. + * This is a core part of the arcane workbench refactoring in version 4.2 and allows for custom spell casting items and + * chargeable armour without requiring that they extend {@link ItemWand} or {@link ItemWizardArmour}. + * @author Electroblob + * @since Wizardry 4.2 + */ +public interface IWorkbenchItem { + + /** + * Returns true if the item can be placed in the central slot of an arcane workbench, false otherwise. Allows + * for itemstack-sensitive behaviour. Returns true by default. + * @param stack The stack that is being placed into the workbench. + * @return True to allow the item to be placed into the workbench, false to prevent that from happening. + */ + default boolean canPlace(ItemStack stack){ + return true; + } + + /** + * Returns the number of spell book slots that should appear in the workbench when this item is placed into it, + * based on the given itemstack. + * @param stack The stack that is being placed into the workbench. + * @return The number of spell book slots that should appear around this item when it is placed into the workbench. + * Can be 0, but must not be negative. + */ + int getSpellSlotCount(ItemStack stack); + + /** + * Called when this item is in the central slot of an arcane workbench and the apply button is pressed. Items must + * implement this method to define what happens when the apply button is pressed. Note that {@link SpellBindEvent} + * is fired before this method is called. + * @param player The player that pressed the apply button. + * @param centre The central slot in the arcane workbench. This slot will always contain a stack of the implementing + * item, or in other words, it is guaranteed that {@code this == centre.getStack().getItem()}. + * @param crystals The magic crystal slot of the arcane workbench. + * @param upgrade The upgrade slot of the arcane workbench. + * @param spellBooks An array of the active (visible) spell book slots in the arcane workbench. The length of + * the array will be equal to the value returned by {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}. + * @return True if anything changed, false if not. + */ + boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks); + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java b/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java new file mode 100644 index 00000000..3e9242d6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java @@ -0,0 +1,56 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.WizardData; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.spell.Spell; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public class ItemBlankScroll extends Item implements IWorkbenchItem { + + public ItemBlankScroll(){ + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public int getSpellSlotCount(ItemStack stack){ + return 1; + } + + @Override + public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){ + + if(!spellBooks[0].getStack().isEmpty() && !crystals.getStack().isEmpty()){ + + Spell spell = Spell.get(spellBooks[0].getStack().getItemDamage()); + WizardData data = WizardData.get(player); + + // Spells can only be bound to scrolls if the player has already cast them (prevents casting of master + // spells without getting a master wand) + // This restriction does not apply in creative mode + if(spell != Spells.none && player.capabilities.isCreativeMode || (data != null + && data.hasSpellBeenDiscovered(spell))){ + + int cost = spell.cost; + // Continuous spell scrolls require enough mana to cast them for the duration defined in ItemScroll. + if(spell.isContinuous) cost *= ItemScroll.CASTING_TIME / 20; + + if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL > cost){ + // Rounds up to the nearest whole crystal + crystals.decrStackSize(cost / Constants.MANA_PER_CRYSTAL + 1); + centre.putStack(new ItemStack(WizardryItems.scroll, 1, spell.id())); + return true; + } + + } + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemWand.java b/src/main/java/electroblob/wizardry/item/ItemWand.java index 522d819d..bdc1d183 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWand.java +++ b/src/main/java/electroblob/wizardry/item/ItemWand.java @@ -13,6 +13,7 @@ import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent.Source; import electroblob.wizardry.packet.PacketCastSpell; import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; @@ -30,6 +31,7 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.inventory.Slot; import net.minecraft.item.EnumAction; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -59,7 +61,10 @@ import net.minecraftforge.fml.relauncher.SideOnly; * * @since Wizardry 1.0 */ -public class ItemWand extends Item { +public class ItemWand extends Item implements IWorkbenchItem { + + /** The number of spell slots a wand has with no attunement upgrades applied. */ + public static final int BASE_SPELL_SLOTS = 5; public Tier tier; public Element element; @@ -424,4 +429,142 @@ public class ItemWand extends Item { return false; } + + @Override + public int getSpellSlotCount(ItemStack stack){ + return BASE_SPELL_SLOTS + WandHelper.getUpgradeLevel(stack, WizardryItems.attunement_upgrade); + } + + @Override + public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){ + + boolean changed = false; + + // Upgrades wand if necessary. Damage is copied, preserving remaining durability, + // and also the entire NBT tag compound. + if(upgrade.getStack().getItem() == WizardryItems.arcane_tome){ + + // Checks the wand upgrade is for the tier above the wand's tier. + // It is guaranteed that: this == centre.getStack().getItem() + if(upgrade.getStack().getItemDamage() - 1 == this.tier.ordinal()){ + + Tier tier = Tier.values()[upgrade.getStack().getItemDamage()]; + + ItemStack newWand = new ItemStack(WizardryUtilities.getWand(tier, this.element)); + newWand.setTagCompound(centre.getStack().getTagCompound()); + // This needs to be done after copying the tag compound so the max damage for the new wand + // takes storage upgrades into account. + newWand.setItemDamage(newWand.getMaxDamage() - (centre.getStack().getMaxDamage() - centre.getStack().getItemDamage())); + + centre.putStack(newWand); + upgrade.decrStackSize(1); + + if(tier == Tier.APPRENTICE) WizardryAdvancementTriggers.apprentice.triggerFor(player); + if(tier == Tier.MASTER) WizardryAdvancementTriggers.master.triggerFor(player); + + changed = true; + } + + }else if(WandHelper.isWandUpgrade(upgrade.getStack().getItem())){ + + // Special upgrades + Item specialUpgrade = upgrade.getStack().getItem(); + + if(WandHelper.getTotalUpgrades(centre.getStack()) < this.tier.upgradeLimit + && WandHelper.getUpgradeLevel(centre.getStack(), specialUpgrade) < Constants.UPGRADE_STACK_LIMIT){ + + // Used to preserve existing mana when upgrading storage rather than creating free mana. + int prevMana = centre.getStack().getMaxDamage() - centre.getStack().getItemDamage(); + + WandHelper.applyUpgrade(centre.getStack(), specialUpgrade); + + // Special behaviours for specific upgrades + if(specialUpgrade == WizardryItems.storage_upgrade){ + + centre.getStack().setItemDamage(centre.getStack().getMaxDamage() - prevMana); + + }else if(specialUpgrade == WizardryItems.attunement_upgrade){ + + int newSlotCount = BASE_SPELL_SLOTS + WandHelper.getUpgradeLevel(centre.getStack(), + WizardryItems.attunement_upgrade); + + Spell[] spells = WandHelper.getSpells(centre.getStack()); + Spell[] newSpells = new Spell[newSlotCount]; + + for(int i = 0; i < newSpells.length; i++){ + newSpells[i] = i < spells.length && spells[i] != null ? spells[i] : Spells.none; + } + + WandHelper.setSpells(centre.getStack(), newSpells); + + int[] cooldowns = WandHelper.getCooldowns(centre.getStack()); + int[] newCooldowns = new int[newSlotCount]; + + if(cooldowns.length > 0){ + for(int i = 0; i < cooldowns.length; i++){ + newCooldowns[i] = cooldowns[i]; + } + } + + WandHelper.setCooldowns(centre.getStack(), newCooldowns); + } + + upgrade.decrStackSize(1); + WizardryAdvancementTriggers.special_upgrade.triggerFor(player); + + if(WandHelper.getTotalUpgrades(centre.getStack()) == Tier.MASTER.upgradeLimit){ + WizardryAdvancementTriggers.max_out_wand.triggerFor(player); + } + + changed = true; + } + } + + // Reads NBT spell id array to variable, edits this, then writes it back to NBT. + // Original spells are preserved; if a slot is left empty the existing spell binding will remain. + // Accounts for spells which cannot be applied because they are above the wand's tier; these spells + // will not bind but the existing spell in that slot will remain and other applicable spells will + // be bound as normal, along with any upgrades and crystals. + Spell[] spells = WandHelper.getSpells(centre.getStack()); + + if(spells.length <= 0){ + // Base value here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades + spells = new Spell[BASE_SPELL_SLOTS]; + } + + for(int i = 0; i < spells.length; i++){ + if(spellBooks[i].getStack() != ItemStack.EMPTY){ + + Spell spell = Spell.get(spellBooks[i].getStack().getItemDamage()); + // If the wand is powerful enough for the spell and it's not already bound to that slot + if(!(spell.tier.level > this.tier.level) && spells[i] != spell){ + spells[i] = spell; + changed = true; + } + } + } + + WandHelper.setSpells(centre.getStack(), spells); + + // Charges wand by appropriate amount + if(crystals.getStack() != ItemStack.EMPTY){ + + int chargeDepleted = centre.getStack().getItemDamage(); + + if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){ + + centre.getStack().setItemDamage(chargeDepleted - crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL); + crystals.decrStackSize(crystals.getStack().getCount()); + changed = true; + + }else if(chargeDepleted != 0){ + + centre.getStack().setItemDamage(0); + crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / Constants.MANA_PER_CRYSTAL)); + changed = true; + } + } + + return changed; + } } diff --git a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java index bb356ec8..898576b5 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java +++ b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java @@ -11,6 +11,7 @@ import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; import electroblob.wizardry.registry.WizardryAdvancementTriggers; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryTabs; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.util.ITooltipFlag; @@ -20,9 +21,11 @@ import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.inventory.Slot; import net.minecraft.item.EnumAction; import net.minecraft.item.ItemArmor; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumHandSide; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; @@ -32,7 +35,7 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @Mod.EventBusSubscriber -public class ItemWizardArmour extends ItemArmor { +public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { //VanillaCopy, ItemArmor has this set to private for some reason. public static final UUID[] ARMOR_MODIFIERS = new UUID[] {UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")}; @@ -211,4 +214,52 @@ public class ItemWizardArmour extends ItemArmor { } } + @Override + public int getSpellSlotCount(ItemStack stack){ + return 0; // Doesn't have any spell slots! + } + + @Override + public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){ + + boolean changed = false; + + // Applies legendary upgrade + if(upgrade.getStack().getItem() == WizardryItems.armour_upgrade){ + + if(!centre.getStack().hasTagCompound()){ + centre.getStack().setTagCompound(new NBTTagCompound()); + } + + if(!centre.getStack().getTagCompound().hasKey("legendary")){ + + centre.getStack().getTagCompound().setBoolean("legendary", true); + upgrade.decrStackSize(1); + WizardryAdvancementTriggers.legendary.triggerFor(player); + changed = true; + } + } + + // Charges armour by appropriate amount + if(crystals.getStack() != ItemStack.EMPTY){ + + int chargeDepleted = centre.getStack().getItemDamage(); + + if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){ + + centre.getStack().setItemDamage(chargeDepleted - crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL); + crystals.decrStackSize(crystals.getStack().getCount()); + changed = true; + + }else if(chargeDepleted != 0){ + + centre.getStack().setItemDamage(0); + crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / Constants.MANA_PER_CRYSTAL)); + changed = true; + } + } + + return changed; + } + } diff --git a/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java b/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java index 8615c69f..523f9b7a 100644 --- a/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java @@ -3,30 +3,22 @@ package electroblob.wizardry.tileentity; import java.util.HashSet; import java.util.Set; -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.event.SpellBindEvent; +import electroblob.wizardry.item.IWorkbenchItem; import electroblob.wizardry.item.ItemArcaneTome; import electroblob.wizardry.item.ItemArmourUpgrade; import electroblob.wizardry.item.ItemSpellBook; -import electroblob.wizardry.item.ItemWand; -import electroblob.wizardry.item.ItemWizardArmour; -import electroblob.wizardry.registry.Spells; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; import net.minecraftforge.common.MinecraftForge; public class ContainerArcaneWorkbench extends Container { @@ -40,29 +32,26 @@ public class ContainerArcaneWorkbench extends Container { "gui/empty_slot_upgrade"); public static final int CRYSTAL_SLOT = 8; - public static final int WAND_SLOT = 9; + public static final int CENTRE_SLOT = 9; public static final int UPGRADE_SLOT = 10; - - private static final int[][][] SPELL_BOOK_SLOT_COORDS = { - {{80, 22}, {121, 51}, {106, 98}, {54, 98}, {39, 51}, {-999, -999}, {-999, -999}, {-999, -999}}, - {{80, 22}, {117, 43}, {117, 85}, {80, 106}, {43, 85}, {43, 43}, {-999, -999}, {-999, -999}}, - {{80, 22}, {113, 38}, {121, 74}, {98, 102}, {62, 102}, {39, 74}, {47, 38}, {-999, -999}}, - {{80, 22}, {111, 33}, {122, 64}, {111, 95}, {80, 106}, {49, 95}, {38, 64}, {49, 33}}}; + + public static final int SLOT_RADIUS = 42; public ContainerArcaneWorkbench(IInventory inventory, TileEntityArcaneWorkbench tileentity){ this.tileentity = tileentity; - ItemStack wand = tileentity.getStackInSlot(WAND_SLOT); + ItemStack wand = tileentity.getStackInSlot(CENTRE_SLOT); for(int i = 0; i < 8; i++){ - this.addSlotToContainer(new SlotItemList(tileentity, i, -999, -999, 1, WizardryItems.spell_book)); + Slot slot = new SlotItemList(tileentity, i, -999, -999, 1, WizardryItems.spell_book); + this.addSlotToContainer(slot); } this.addSlotToContainer(new SlotItemList(tileentity, CRYSTAL_SLOT, 8, 88, 64, WizardryItems.magic_crystal)) .setBackgroundName(EMPTY_SLOT_CRYSTAL.toString()); - this.addSlotToContainer(new SlotWandArmour(tileentity, WAND_SLOT, 80, 64, this)); + this.addSlotToContainer(new SlotWorkbenchItem(tileentity, CENTRE_SLOT, 80, 64, this)); Set upgrades = new HashSet(WandHelper.getSpecialUpgrades()); // Can't be done statically. upgrades.add(WizardryItems.arcane_tome); @@ -81,102 +70,98 @@ public class ContainerArcaneWorkbench extends Container { } } - this.onSlotChanged(WAND_SLOT, wand, null); + this.onSlotChanged(CENTRE_SLOT, wand, null); } @Override public boolean canInteractWith(EntityPlayer player){ return this.tileentity.isUsableByPlayer(player); } + + /** + * Shows the given slot in the container GUI at the given position. Intended to do the opposite of + * {@link ContainerArcaneWorkbench#hideSlot(int, EntityPlayer)}. + * @param index The index of the slot to show. + * @param x The x position to put the slot in. + * @param y The y position to put the slot in. + */ + private void showSlot(int index, int x, int y){ + + Slot slot = this.getSlot(index); + slot.xPos = x; + slot.yPos = y; + } + + /** + * Hides the given slot from the container GUI (moves it off the screen) and returns its contents to the given + * player. If some or all of the items do not fit in the player's inventory, or if the player is null, they are + * dropped on the floor. + * @param index The index of the slot to hide. + * @param player The player that is using this container. + */ + private void hideSlot(int index, EntityPlayer player){ + + Slot slot = this.getSlot(index); + + // 'Removes' the slot from the container (moves it off the screen) + slot.xPos = -999; + slot.yPos = -999; + + ItemStack stack = slot.getStack(); + // This doesn't cause an infinite loop because slot i can never be a SlotWandArmour. In effect, it's + // exactly the same as shift-clicking the slot, so why re-invent the wheel? + ItemStack remainder = this.transferStackInSlot(player, index); + + if(remainder == ItemStack.EMPTY && stack != ItemStack.EMPTY){ + slot.putStack(ItemStack.EMPTY); + // The second parameter is never used... + if(player != null) player.dropItem(stack, false); + } + } /** Called from the central wand/armour slot when its item is changed or removed. */ // In case I forget again and think it should have @Override: I wrote this! public void onSlotChanged(int slotNumber, ItemStack stack, EntityPlayer player){ - if(slotNumber == WAND_SLOT){ + if(slotNumber == CENTRE_SLOT){ - if(!(stack.getItem() instanceof ItemWand) && stack.getItem() != WizardryItems.blank_scroll){ - // If the stack has been removed + if(stack.isEmpty()){ + // If the stack has been removed, hide all the spell book slots for(int i = 0; i < CRYSTAL_SLOT; i++){ - Slot slot1 = this.getSlot(i); - // 'Removes' the slot from the container (moves it off the screen) - slot1.xPos = -100; - slot1.yPos = -100; - - ItemStack stack1 = slot1.getStack(); - // This doesn't cause an infinite loop because slot i can never be a SlotWandArmour. In effect, it's - // exactly the same as shift-clicking the slot, so why re-invent the wheel? - ItemStack remainder = this.transferStackInSlot(player, i); - - if(remainder == ItemStack.EMPTY && stack1 != ItemStack.EMPTY){ - slot1.putStack(ItemStack.EMPTY); - // The second parameter is never used... - if(player != null) player.dropItem(stack1, false); - } + this.hideSlot(i, player); } }else{ - - if(stack.getItem() == WizardryItems.blank_scroll){ - // If a blank scroll is added - // The first slot is shown - this.getSlot(0).xPos = SPELL_BOOK_SLOT_COORDS[0][0][0]; - this.getSlot(0).yPos = SPELL_BOOK_SLOT_COORDS[0][0][1]; - - // The rest of the slots are hidden - for(int i = 1; i < CRYSTAL_SLOT; i++){ - - Slot slot1 = this.getSlot(i); - - slot1.xPos = -100; - slot1.yPos = -100; - - ItemStack stack1 = slot1.getStack(); - // This doesn't cause an infinite loop because slot i can never be a SlotWandArmour. In effect, - // it's - // exactly the same as shift-clicking the slot, so why re-invent the wheel? - ItemStack remainder = this.transferStackInSlot(player, i); - - if(remainder == ItemStack.EMPTY && stack1 != ItemStack.EMPTY){ - slot1.putStack(ItemStack.EMPTY); - // The second parameter is never used... - if(player != null) player.dropItem(stack1, false); - } + + if(stack.getItem() instanceof IWorkbenchItem){ // Should always be true here. + + int spellSlots = ((IWorkbenchItem)stack.getItem()).getSpellSlotCount(stack); + + int centreX = this.getSlot(CENTRE_SLOT).xPos; + int centreY = this.getSlot(CENTRE_SLOT).yPos; + + // Show however many spell book slots are necessary + for(int i = 0; i < spellSlots; i++){ + + float angle = i * (2 * (float)Math.PI)/spellSlots; + int x = centreX + (int)(Math.round(SLOT_RADIUS * MathHelper.sin(angle))); + // -cos because +y is downwards + int y = centreY + (int)(Math.round(SLOT_RADIUS * -MathHelper.cos(angle))); + + showSlot(i, x, y); } - - }else{ - - for(int i = 0; i < CRYSTAL_SLOT; i++){ - - int n = WandHelper.getUpgradeLevel(stack, WizardryItems.attunement_upgrade); - int[] coords = SPELL_BOOK_SLOT_COORDS[n][i]; - - Slot slot1 = this.getSlot(i); - // Puts the slot back in the correct position - slot1.xPos = coords[0]; - slot1.yPos = coords[1]; - - if(slot1.xPos < 0 || slot1.yPos < 0){ - - ItemStack stack1 = slot1.getStack(); - // This doesn't cause an infinite loop because slot i can never be a SlotWandArmour. In - // effect, it's - // exactly the same as shift-clicking the slot, so why re-invent the wheel? - ItemStack remainder = this.transferStackInSlot(player, i); - - if(remainder == ItemStack.EMPTY && stack1 != ItemStack.EMPTY){ - slot1.putStack(ItemStack.EMPTY); - // The second parameter is never used... - if(player != null) player.dropItem(stack1, false); - } - } + + // Hide the rest + for(int i = spellSlots; i < CRYSTAL_SLOT; i++){ + hideSlot(i, player); } + } } } // FIXME: It only seems to be syncing correctly when a stack is put into the slot, not taken out. - // Was this broken in 1.7.10 as well? + // This is because markDirty isn't called in the tileentity, I think. this.tileentity.sync(); } @@ -209,17 +194,16 @@ public class ContainerArcaneWorkbench extends Container { }else if(stack.getItem() == WizardryItems.magic_crystal){ minSlotId = CRYSTAL_SLOT; maxSlotId = CRYSTAL_SLOT; - }else if(stack.getItem() instanceof ItemWand || stack.getItem() instanceof ItemWizardArmour - || stack.getItem() == WizardryItems.blank_scroll){ - minSlotId = WAND_SLOT; - maxSlotId = WAND_SLOT; + }else if(stack.getItem() instanceof IWorkbenchItem){ + minSlotId = CENTRE_SLOT; + maxSlotId = CENTRE_SLOT; }else if(stack.getItem() instanceof ItemArcaneTome || stack.getItem() instanceof ItemArmourUpgrade || WandHelper.isWandUpgrade(stack.getItem())){ minSlotId = UPGRADE_SLOT; maxSlotId = UPGRADE_SLOT; }else{ - return ItemStack.EMPTY; // If none of the above cases were true, then the item won't fit in the - // workbench. + // If none of the above cases were true, then the item won't fit in the workbench. + return ItemStack.EMPTY; } if(!this.mergeItemStack(stack, minSlotId, maxSlotId + 1, false)){ @@ -261,204 +245,22 @@ public class ContainerArcaneWorkbench extends Container { * Called (via {@link electroblob.wizardry.packet.PacketControlInput PacketControlInput}) when the apply button in * the arcane workbench GUI is pressed. */ - // All operations on the items contained in the inventory simply call the corresponding methods in the tileentity. // As of 2.1, for the sake of events and neatness of code, this was moved here from TileEntityArcaneWorkbench. + // As of 4.2, the spell binding/charging/upgrading code was delegated (via IWorkbenchItem) to the items themselves. public void onApplyButtonPressed(EntityPlayer player){ - ItemStack wand = this.getSlot(WAND_SLOT).getStack(); - ItemStack[] spellBooks = new ItemStack[CRYSTAL_SLOT]; - for(int i = 0; i < spellBooks.length; i++){ - spellBooks[i] = this.getSlot(i).getStack(); - } - ItemStack crystals = this.getSlot(CRYSTAL_SLOT).getStack(); - ItemStack upgrade = this.getSlot(UPGRADE_SLOT).getStack(); - if(MinecraftForge.EVENT_BUS.post(new SpellBindEvent(player, this))) return; - - // Since the workbench now accepts armour as well as wands, this check is needed. - if(wand.getItem() instanceof ItemWand){ - - // Upgrades wand if necessary. Damage is copied, preserving remaining durability, - // and also the entire NBT tag compound. - if(upgrade.getItem() == WizardryItems.arcane_tome){ - - ItemStack newWand; - - switch(Tier.values()[upgrade.getItemDamage()]){ - - case APPRENTICE: - if(((ItemWand)wand.getItem()).tier == Tier.BASIC){ - newWand = new ItemStack(WizardryUtilities.getWand(Tier.values()[upgrade.getItemDamage()], - ((ItemWand)wand.getItem()).element)); - newWand.setTagCompound(wand.getTagCompound()); - // This needs to be done after copying the tag compound so the max damage for the new wand - // takes storage - // upgrades into account. - newWand.setItemDamage(newWand.getMaxDamage() - (wand.getMaxDamage() - wand.getItemDamage())); - this.putStackInSlot(WAND_SLOT, newWand); - this.putStackInSlot(UPGRADE_SLOT, ItemStack.EMPTY); - WizardryAdvancementTriggers.apprentice.triggerFor(player); - } - break; - - case ADVANCED: - if(((ItemWand)wand.getItem()).tier == Tier.APPRENTICE){ - newWand = new ItemStack(WizardryUtilities.getWand(Tier.values()[upgrade.getItemDamage()], - ((ItemWand)wand.getItem()).element)); - newWand.setTagCompound(wand.getTagCompound()); - newWand.setItemDamage(newWand.getMaxDamage() - (wand.getMaxDamage() - wand.getItemDamage())); - this.putStackInSlot(WAND_SLOT, newWand); - this.putStackInSlot(UPGRADE_SLOT, ItemStack.EMPTY); - } - break; - - case MASTER: - if(((ItemWand)wand.getItem()).tier == Tier.ADVANCED){ - newWand = new ItemStack(WizardryUtilities.getWand(Tier.values()[upgrade.getItemDamage()], - ((ItemWand)wand.getItem()).element)); - newWand.setTagCompound(wand.getTagCompound()); - newWand.setItemDamage(newWand.getMaxDamage() - (wand.getMaxDamage() - wand.getItemDamage())); - this.putStackInSlot(WAND_SLOT, newWand); - this.putStackInSlot(UPGRADE_SLOT, ItemStack.EMPTY); - WizardryAdvancementTriggers.master.triggerFor(player); - } - break; - - default: - break; - } - - // This needs to happen so the charging works on the new wand, not the old one. - wand = this.getSlot(WAND_SLOT).getStack(); - - }else if(WandHelper.isWandUpgrade(upgrade.getItem())){ - - // Special upgrades - - // Used to preserve existing mana when upgrading storage rather than creating free mana. - int prevMana = wand.getMaxDamage() - wand.getItemDamage(); - - if(WandHelper.getTotalUpgrades(wand) < ((ItemWand)wand.getItem()).tier.upgradeLimit - && WandHelper.getUpgradeLevel(wand, upgrade.getItem()) < Constants.UPGRADE_STACK_LIMIT){ - - WandHelper.applyUpgrade(wand, upgrade.getItem()); - - // Special behaviours for specific upgrades - if(upgrade.getItem() == WizardryItems.storage_upgrade){ - wand.setItemDamage(wand.getMaxDamage() - prevMana); - } - if(upgrade.getItem() == WizardryItems.attunement_upgrade){ - - Spell[] spells = WandHelper.getSpells(wand); - Spell[] newSpells = new Spell[5 - + WandHelper.getUpgradeLevel(wand, WizardryItems.attunement_upgrade)]; - - for(int i = 0; i < newSpells.length; i++){ - // Prevents both NPEs and AIOOBEs - newSpells[i] = i < spells.length && spells[i] != null ? spells[i] : Spells.none; - } - - WandHelper.setSpells(wand, newSpells); - - int[] cooldown = WandHelper.getCooldowns(wand); - int[] newCooldown = new int[5 - + WandHelper.getUpgradeLevel(wand, WizardryItems.attunement_upgrade)]; - - if(cooldown.length > 0){ - for(int i = 0; i < cooldown.length; i++){ - newCooldown[i] = cooldown[i]; - } - } - - WandHelper.setCooldowns(wand, newCooldown); - } - - this.getSlot(UPGRADE_SLOT).decrStackSize(1); - WizardryAdvancementTriggers.special_upgrade.triggerFor(player); - - if(WandHelper.getTotalUpgrades(wand) == Tier.MASTER.upgradeLimit){ - WizardryAdvancementTriggers.max_out_wand.triggerFor(player); - } - } - } - - // Reads NBT spell id array to variable, edits this, then writes it back to NBT. - // Original spells are preserved; if a slot is left empty the existing spell binding will remain. - // Accounts for spells which cannot be applied because they are above the wand's tier; these spells - // will not bind but the existing spell in that slot will remain and other applicable spells will - // be bound as normal, along with any upgrades and crystals. - Spell[] spells = WandHelper.getSpells(wand); - if(spells.length <= 0){ - // 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades - spells = new Spell[5]; - } - for(int i = 0; i < spells.length; i++){ - if(spellBooks[i] != ItemStack.EMPTY && !(Spell - .get(spellBooks[i].getItemDamage()).tier.level > ((ItemWand)wand.getItem()).tier.level)){ - spells[i] = Spell.get(spellBooks[i].getItemDamage()); - } - } - WandHelper.setSpells(wand, spells); - - // Charges wand by appropriate amount - if(crystals != ItemStack.EMPTY){ - int chargeDepleted = wand.getItemDamage(); - // System.out.println("Charge depleted: " + chargeDepleted); - // System.out.println("Crystals found: " + crystals.getCount()); - if(crystals.getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){ - // System.out.println("charging"); - wand.setItemDamage(chargeDepleted - crystals.getCount() * Constants.MANA_PER_CRYSTAL); - this.getSlot(CRYSTAL_SLOT).decrStackSize(crystals.getCount()); - }else if(chargeDepleted != 0){ - // System.out.println((int)Math.ceil(((double)chargeDepleted)/50)); - this.getSlot(CRYSTAL_SLOT) - .decrStackSize((int)Math.ceil(((double)chargeDepleted) / Constants.MANA_PER_CRYSTAL)); - wand.setItemDamage(0); - } - } - } - - // Armour - else if(wand.getItem() instanceof ItemWizardArmour){ - // Applies legendary upgrade - if(upgrade.getItem() == WizardryItems.armour_upgrade){ - if(!wand.hasTagCompound()){ - wand.setTagCompound(new NBTTagCompound()); - } - if(!wand.getTagCompound().hasKey("legendary")){ - wand.getTagCompound().setBoolean("legendary", true); - this.putStackInSlot(UPGRADE_SLOT, ItemStack.EMPTY); - WizardryAdvancementTriggers.legendary.triggerFor(player); - } - } - // Charges armour by appropriate amount - if(crystals != ItemStack.EMPTY){ - int chargeDepleted = wand.getItemDamage(); - if(crystals.getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){ - wand.setItemDamage(chargeDepleted - crystals.getCount() * Constants.MANA_PER_CRYSTAL); - this.getSlot(CRYSTAL_SLOT).decrStackSize(crystals.getCount()); - }else if(chargeDepleted != 0){ - this.getSlot(CRYSTAL_SLOT) - .decrStackSize((int)Math.ceil(((double)chargeDepleted) / Constants.MANA_PER_CRYSTAL)); - wand.setItemDamage(0); - } - } - } - - // Scrolls - else if(wand.getItem() == WizardryItems.blank_scroll){ - // Spells can only be bound to scrolls if the player has already cast them (prevents casting of master - // spells without getting a master wand) - // This restriction does not apply in creative mode - if(spellBooks[0] != ItemStack.EMPTY - && (player.capabilities.isCreativeMode || (WizardData.get(player) != null - && WizardData.get(player).hasSpellBeenDiscovered(Spell.get(spellBooks[0].getItemDamage())))) - && crystals != ItemStack.EMPTY && crystals.getCount() - * Constants.MANA_PER_CRYSTAL > Spell.get(spellBooks[0].getItemDamage()).cost){ - - this.getSlot(CRYSTAL_SLOT).decrStackSize((int)Math - .ceil(((double)Spell.get(spellBooks[0].getItemDamage()).cost) / Constants.MANA_PER_CRYSTAL)); - this.putStackInSlot(WAND_SLOT, new ItemStack(WizardryItems.scroll, 1, spellBooks[0].getItemDamage())); + + Slot centre = this.getSlot(CENTRE_SLOT); + + if(centre.getStack().getItem() instanceof IWorkbenchItem){ // Should always be true, but no harm in checking. + + Slot[] spellBooks = this.inventorySlots.subList(0, 8).toArray(new Slot[8]); + + if(((IWorkbenchItem)centre.getStack().getItem()) + .onApplyButtonPressed(player, centre, this.getSlot(CRYSTAL_SLOT), this.getSlot(UPGRADE_SLOT), spellBooks)){ + + // TODO: Sound and possibly animation for spell binding } } } diff --git a/src/main/java/electroblob/wizardry/tileentity/SlotWandArmour.java b/src/main/java/electroblob/wizardry/tileentity/SlotWorkbenchItem.java similarity index 59% rename from src/main/java/electroblob/wizardry/tileentity/SlotWandArmour.java rename to src/main/java/electroblob/wizardry/tileentity/SlotWorkbenchItem.java index 19f24a60..c83673f0 100644 --- a/src/main/java/electroblob/wizardry/tileentity/SlotWandArmour.java +++ b/src/main/java/electroblob/wizardry/tileentity/SlotWorkbenchItem.java @@ -1,8 +1,6 @@ package electroblob.wizardry.tileentity; -import electroblob.wizardry.item.ItemWand; -import electroblob.wizardry.item.ItemWizardArmour; -import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.item.IWorkbenchItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; @@ -14,12 +12,12 @@ import net.minecraft.item.ItemStack; * @author Electroblob * @since Wizardry 1.0 */ -public class SlotWandArmour extends Slot { +public class SlotWorkbenchItem extends Slot { private ContainerArcaneWorkbench container; - public SlotWandArmour(IInventory par1iInventory, int index, int x, int y, ContainerArcaneWorkbench container){ - super(par1iInventory, index, x, y); + public SlotWorkbenchItem(IInventory inventory, int index, int x, int y, ContainerArcaneWorkbench container){ + super(inventory, index, x, y); this.container = container; } @@ -41,8 +39,7 @@ public class SlotWandArmour extends Slot { } @Override - public boolean isItemValid(ItemStack itemstack){ - return (itemstack.getItem() instanceof ItemWand || itemstack.getItem() instanceof ItemWizardArmour - || itemstack.getItem() == WizardryItems.blank_scroll); + public boolean isItemValid(ItemStack stack){ + return stack.getItem() instanceof IWorkbenchItem && ((IWorkbenchItem)stack.getItem()).canPlace(stack); } } diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java index 5e6c4b04..a04d661c 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java @@ -56,7 +56,7 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, @Override public void update(){ - ItemStack itemstack = this.getStackInSlot(ContainerArcaneWorkbench.WAND_SLOT); + ItemStack itemstack = this.getStackInSlot(ContainerArcaneWorkbench.CENTRE_SLOT); // Decrements wand damage (increases mana) every 1.5 seconds if it has a condenser upgrade if(itemstack.getItem() instanceof ItemWand && !this.world.isRemote && itemstack.isItemDamaged() @@ -93,33 +93,42 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, } @Override - public ItemStack decrStackSize(int slot, int amt){ + public ItemStack decrStackSize(int slot, int amount){ + ItemStack stack = getStackInSlot(slot); + if(!stack.isEmpty()){ - if(stack.getCount() <= amt){ + if(stack.getCount() <= amount){ setInventorySlotContents(slot, ItemStack.EMPTY); }else{ - stack = stack.splitStack(amt); + stack = stack.splitStack(amount); if(stack.getCount() == 0){ setInventorySlotContents(slot, ItemStack.EMPTY); } } + this.markDirty(); } + return stack; } @Override public ItemStack removeStackFromSlot(int slot){ + ItemStack stack = getStackInSlot(slot); + if(!stack.isEmpty()){ setInventorySlotContents(slot, ItemStack.EMPTY); } + return stack; } @Override public void setInventorySlotContents(int slot, ItemStack stack){ + inventory.set(slot, stack); + if(!stack.isEmpty() && stack.getCount() > getInventoryStackLimit()){ stack.setCount(getInventoryStackLimit()); } @@ -166,7 +175,7 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, }else if(slotNumber == ContainerArcaneWorkbench.CRYSTAL_SLOT){ return itemstack.getItem() == WizardryItems.magic_crystal; - }else if(slotNumber == ContainerArcaneWorkbench.WAND_SLOT){ + }else if(slotNumber == ContainerArcaneWorkbench.CENTRE_SLOT){ return (itemstack.getItem() instanceof ItemWand || itemstack.getItem() instanceof ItemWizardArmour || itemstack.getItem() == WizardryItems.blank_scroll); From 73d973783dbb57aa89b240477fbec8c69b08966d Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 15:48:48 +0100 Subject: [PATCH 28/68] Add continuous spell casting with scrolls and increase scroll and spell book stack sizes to 16 --- .../electroblob/wizardry/CommonProxy.java | 7 -- .../wizardry/client/ClientProxy.java | 2 - .../electroblob/wizardry/item/ItemScroll.java | 78 +++++++++++++++++-- .../wizardry/item/ItemSpellBook.java | 2 +- .../wizardry/registry/WizardryItems.java | 5 +- 5 files changed, 77 insertions(+), 17 deletions(-) diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index b8ef9d67..cb2e1441 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -87,14 +87,7 @@ public class CommonProxy { */ public String getScrollDisplayName(ItemStack scroll){ - // I have now learnt that the server side I18n always translates to the default en_US, so I could just return - // a hardcoded name in English instead. - Wizardry.logger.info("A mod has called ItemScroll#getItemStackDisplayName from the server side. Using the" - + "deprecated server-side translation methods as a fallback."); - - // Displays [Empty slot] if spell is continuous. Spell spell = Spell.get(scroll.getItemDamage()); - if(spell.isContinuous) spell = Spells.none; return I18n.translateToLocalFormatted("item." + Wizardry.MODID + ":scroll.name", I18n.translateToLocal("spell." + spell.getUnlocalisedName())).trim(); diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index cd68ad7c..93deb66d 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -241,9 +241,7 @@ public class ClientProxy extends CommonProxy { @Override public String getScrollDisplayName(ItemStack scroll){ - // Displays [Empty slot] if spell is continuous. Spell spell = Spell.get(scroll.getItemDamage()); - if(spell.isContinuous) spell = Spells.none; EntityPlayer player = Minecraft.getMinecraft().player; diff --git a/src/main/java/electroblob/wizardry/item/ItemScroll.java b/src/main/java/electroblob/wizardry/item/ItemScroll.java index e70f730e..cd27e026 100644 --- a/src/main/java/electroblob/wizardry/item/ItemScroll.java +++ b/src/main/java/electroblob/wizardry/item/ItemScroll.java @@ -10,6 +10,7 @@ import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.client.gui.FontRenderer; import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -24,19 +25,27 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class ItemScroll extends Item { + + /** The maximum number of ticks a continuous spell scroll can be cast for (by holding the use item button). */ + // TODO: Make this configurable + public static final int CASTING_TIME = 120; public ItemScroll(){ super(); setHasSubtypes(true); - setMaxStackSize(1); + setMaxStackSize(16); setCreativeTab(WizardryTabs.SPELLS); } @Override public void getSubItems(CreativeTabs tab, NonNullList list){ - if (isInCreativeTab(tab)) { - for(Spell spell : Spell.getSpells(Spell.nonContinuousSpells)){ - list.add(new ItemStack(this, 1, spell.id())); + if(isInCreativeTab(tab)){ + // In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance + // is not required, only the id. + for(int i = 0; i < Spell.getTotalSpellCount(); i++){ + // i+1 is used so that the metadata ties up with the id() method. In other words, the none spell has id + // 0 and since this is not used as a spell book the metadata starts at 1. + list.add(new ItemStack(this, 1, i + 1)); } } } @@ -63,6 +72,11 @@ public class ItemScroll extends Item { return Wizardry.proxy.getScrollDisplayName(stack); } + + @Override + public int getMaxItemUseDuration(ItemStack stack){ + return CASTING_TIME; + } @Override public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand){ @@ -78,7 +92,13 @@ public class ItemScroll extends Item { return new ActionResult(EnumActionResult.FAIL, stack); } - if(!spell.isContinuous){ + // Now we can cast continuous spells with scrolls! + if(spell.isContinuous){ + if(!player.isHandActive()){ + player.setActiveHand(hand); + return new ActionResult(EnumActionResult.SUCCESS, stack); + } + }else{ if(!world.isRemote){ @@ -112,6 +132,54 @@ public class ItemScroll extends Item { return new ActionResult(EnumActionResult.FAIL, stack); } + + // For continuous spells. The count argument actually decrements by 1 each tick. + @Override + public void onUsingTick(ItemStack stack, EntityLivingBase user, int count){ + + if(user instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)user; + + Spell spell = Spell.get(stack.getItemDamage()); + // By default, scrolls have no modifiers - but with the event system, they could be added. + SpellModifiers modifiers = new SpellModifiers(); + int castingTick = stack.getMaxItemUseDuration() - count; + + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(Source.SCROLL, spell, player, modifiers, castingTick))) + return; + + // Continuous spells (these must check if they can be cast each tick since the mana changes) + if(spell.isContinuous){ + + if(spell.cast(player.world, player, player.getActiveHand(), castingTick, modifiers)){ + + if(castingTick == 0) + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.SCROLL, spell, player, modifiers)); + } + } + } + } + + @Override + public void onPlayerStoppedUsing(ItemStack stack, World world, EntityLivingBase user, int timeLeft){ + // Consumes a continuous spell scroll when a player in survival mode stops using it. + if(Spell.get(stack.getItemDamage()).isContinuous + && (!(user instanceof EntityPlayer) || !((EntityPlayer)user).capabilities.isCreativeMode)){ + stack.shrink(1); + } + } + + @Override + public ItemStack onItemUseFinish(ItemStack stack, World world, EntityLivingBase user){ + // Consumes a continuous spell scroll when the casting elapses whilst in use by a player in survival mode. + if(Spell.get(stack.getItemDamage()).isContinuous + && (!(user instanceof EntityPlayer) || !((EntityPlayer)user).capabilities.isCreativeMode)){ + stack.shrink(1); + } + + return stack; + } @Override @SideOnly(Side.CLIENT) diff --git a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java index 8e7cc4c3..eb785366 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java @@ -30,7 +30,7 @@ public class ItemSpellBook extends Item { public ItemSpellBook(){ super(); setHasSubtypes(true); - setMaxStackSize(1); + setMaxStackSize(16); setCreativeTab(WizardryTabs.SPELLS); } diff --git a/src/main/java/electroblob/wizardry/registry/WizardryItems.java b/src/main/java/electroblob/wizardry/registry/WizardryItems.java index e7bf125a..a6549f63 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryItems.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryItems.java @@ -13,6 +13,7 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.item.ItemArcaneTome; import electroblob.wizardry.item.ItemArmourUpgrade; +import electroblob.wizardry.item.ItemBlankScroll; import electroblob.wizardry.item.ItemFirebomb; import electroblob.wizardry.item.ItemFlamingAxe; import electroblob.wizardry.item.ItemFrostAxe; @@ -119,8 +120,8 @@ public final class WizardryItems { public static final Item firebomb = new ItemFirebomb(); public static final Item poison_bomb = new ItemPoisonBomb(); - public static final Item blank_scroll = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - public static final Item scroll = new ItemScroll().setCreativeTab(WizardryTabs.SPELLS); + public static final Item blank_scroll = new ItemBlankScroll(); + public static final Item scroll = new ItemScroll(); // The only way to get these is in dungeon chests (They are legendary, after all. Wizards don't just have them. // Also if they were sold you could buy four from the same wizard - and that's no fun at all!) From fec4b755bd4da9ffec52fdd0b7e690a0a2f1c8b0 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 15:49:13 +0100 Subject: [PATCH 29/68] Remove old unused textures --- .../assets/ebwizardry/textures/entity/arc_0.png | Bin 4071 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_1.png | Bin 4037 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_10.png | Bin 3619 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_11.png | Bin 3865 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_12.png | Bin 3836 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_13.png | Bin 3868 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_14.png | Bin 3891 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_15.png | Bin 3830 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_2.png | Bin 4126 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_3.png | Bin 4071 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_4.png | Bin 4167 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_5.png | Bin 3858 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_6.png | Bin 3756 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_7.png | Bin 3685 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_8.png | Bin 3611 -> 0 bytes .../assets/ebwizardry/textures/entity/arc_9.png | Bin 3617 -> 0 bytes .../textures/entity/stone_statue_32.png | Bin 507 -> 0 bytes .../textures/entity/stone_statue_64.png | Bin 574 -> 0 bytes 18 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_0.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_1.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_10.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_11.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_12.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_13.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_14.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_15.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_2.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_3.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_4.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_5.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_6.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_7.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_8.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arc_9.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/stone_statue_32.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/entity/stone_statue_64.png diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_0.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_0.png deleted file mode 100644 index 9d0c4a46faeed280fedd399375e97a5046b021bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4071 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9;Xep2*t>i( z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=fJs8ch)H+N;=>FK{3V_)jv*QMj^519 znfJU>{=@yhHt#2?oGvcJIzb%mTRF^!NbAI8uWiCNB`b{mfajgpy56Ovdlq{39E)GKfd;2p!)?p`XLf9KwKh8S z;hkD%XYgX*r+dR)-EG>Mqng^D&0o1v^Z5JMSNFZ`*_NBWHQ#!5?r+Jrx6ftWuRG?u z|Kr`$_Duuuj>Y#C_Km zFOJCAC$uYs+lSB4#xODI{f39iKHmdpw|npUG`m#CZ^n(?-=}lmiE^GidCy+&rMBtq zvU$>JCIZWrEqilk=jE4|m-F)QSnPUlnS1+O*6p%mvitwLXCFCaweh%_M^V6@ z+riVO`SN|2ocBP)>*?oh3+L&*jHo$#*vn9dgibBQ`_He2Gd`cyt&GIXwB}=TcddTJYpsUPid-j49r@6hSk(K z%Pm!Uzf@IKl)uJ~|Hqort z_aEP<3G0vKG6}^7-7T^@YFd~6Z^6W?O6ULXdF6k9UhyNB`pa{&=Y{TlakF~6#H=}6 zHdL&hrxSW&`M#Rs+5O+eW$ZUU`rw_O`+CpURZK}ehfED+ngdtbspeW;nVKr(*tKWR zsv|v{SPy44_s{RRP+6B~%X4p5ens7?XD7|Y|9&W*y?*192al7UZ~MG$>g~6?m%ff7ue{^EJf3|2Ate+gzKL*kwB_H9Ba`;{)GbzhFFEI2pZ$gFHFa(WOK*jgo_r~` zHB;k+=23T<<_}AvO=6}+U0av7KIaAN#yyurYMv_1ojv=V{g;c9llk+bf~%4yhb&*P z>fxSaAKn??%w1mgN0z_B=Q7t{u8iO-Yv1kKabNr4g!V^__nQiCh^L-=H0OwDx7Lao zfxjQOPunDZKjzz&!?g!nj%co&+f}q{&8sP^PS1}0EF&y*`P8YZi|V&z+-u&?^7^tw zKauaUPyW4FuYAW`cL zt5z(NzJ6R#e``z6$A6W?$*pi%_o}@7$2YsA<-ZB|ai5Fawjz4bs^~4Q zTP)v|>-79&nHJ6Ud-jJN{$4R+SDuJmU9y66TIkv8c|Lwh%$^&`grsdL}Y z&_D9`pHa_l|3^Kl&r`(CW|#%7ydCM282rreAI`Kqh*Q2`o9FPA6gdBCcldog*P`OJlVv^>IL(_KL*VfJdHRDKS zsrI70m2V4=d_O#6|N2LJ%vP^jG{+~_+4XSP#Wi=@YPOob`);0i=e?qS)TCL#!M*)f zQu96tu8efd-76|~M@uW?MV4v6XQ^|mXI`IhBAPcjumAU6A->-|ZmT8CPKRXbveYGh zwtN)7ZOsP{iSG+SBCjmgP=D3;d#}*3J2yYgkqj+fp~W|bXdWk-^yU&|!r?_KDo@-#7?{0;uT~b_4-^2==j)v`6 z!*Oe4sqVYOGxiE?mJ)k<;ey=v>b&Muxno;qNjj=coxJkY%+TPeH&ixi_x-4=xTCNv zL?6F-ovUlE zlpo&lJLQ$o&QiPf8jm!$Wf~im>#lYhywfWU-l23=Z=>nE&x;FAEMNL8_1V=mTWr>= zg$7;>m{`2`QdOk?*JHJP?Sf45W(J`mJ2z``+#BHkSXB62hLz@|IT4m3CIN z$qTq^S-WnA=#(i}OFC{nx#C)!HO;{>aj*V~oVeA$rGLZ-&6!y285--neomvsqu+^l zjxTv;T5?oSzx8mP_f^)Fr&qn=Iu(>!T57rZnNC)CdEABjUQA7cCD}3a`VR)p_|WB&Uv3*wfgkx(>iOnPS=lLbIf|1$hw_BcznAiJHMWAVE4}p zE0^ipy=s@XdCev(rt>OfgRb4BH~!ZqmD)U5e`xZ%(CY#sQCxqTuGpkqS#v77D!kn* z%X3qiI!BU;jbY-i5czVxnKDIN+uw&zdo_9IO3}^x)r&n1RISpF?pd3ac6ILcA7|Fb zpRCJvfA!gXTCNtG|K6=hf4-{jblYHXd--QEvAQ-#Kb~FR)=hXR_QfM==h8QuxTlqz zK3Q`5W$b%PqrgQqz8c$3#Y=qOut4m)<*s{W&tpDybRBnDd@aA#S$~i0VJQ>SJ=K4| zm2GwE@%ow_Ua)u9-0YcKuHNK*QE;+lmGY*Ao*Va>EcISq|K;MQ-DM(wAH7_d~((i4!H7_~;$jYOuCRdlQU+ntuZo*@>J%(GRYzU5wUB4pS({Ia? zSCj6kJ*%`Ol#>v-np-ujwp#Onf5p4 z>cQ0u&c3~0;avIqtXliM-o}4SU#{wJztD3ld4BAfxV-_Pf!BBcS(NGAb@YYt?prn% z0YM(k;rd~@TB>YTL758EFT{Gt*hd%sSgvg)W}bNH$cGL4f86ZS&Fz%73ZCuV>ASQ= zS@_-Ce^cCSH-10H$A3TKO1Rg(wNs>@qg#XG&W@hO}S zGpe@@{e0=srhP9x(~IW^aXAK^xPA2;uk6aTxhrSyF1Fjd_Qf_%v!&DTY~K8)+%9H{ zchmCaT7Ca&A{WoocpBt?|9-9Sr@wO_Pk+?+kbK zF0?Fpoa=6~O;rEq6MM~Hmue!{DwhVApYwnIJhpJ=jdY>vKHuoRyM4ZEUuk{#<#Ra4 zbk^EQ-GNHGBDm|!=Dv)6Yiwwf^MU2#TH~&*ujlrM|M^lB8m(9Coquw_Mfm4ge3wry z>egoM{`x|BcF_F23lpNNlOC-Vz5Kb;I!P0^`)irG@hRv3wxw^@ zww;Pj@2N{aZj~{&`n^Nlh3n#L*G+j+eD;Rs5=Xm*6V8A6`Yw;pWZuJXw&uU@v8=x? z{x@>zt1C{+CZ=4fid9=2xOtXX?&=(~!d0CQeR+}#+>65=m>TbH{~~g(`mfXB`_r0F z2KP(u`dq$uXGHOrw;g7Cj~=OIc5Q8`|9WdxQtR~nRv8(SeszZ{{yMEa^J!IQ)R*V# zx98m1n`rQaJy&l&H@RTYlH}0_VKhQ3k=UjDISXznK>vVz_hrdd?H_HPeOHuD@?%v_9b7rVECd zMHw&ZjYD@?J(RFJ^ySj+qPKTnJ)N_~?bf}Wb}oXmKK%ILQrrkn%uUMq>;Ect3r>%y<$ zhksigc8l^opA$AA`=!Z!={NQZFYI>RI_K8~um8VXUetEi=|0T(;ZbbfKKi( z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=fJs8c$aJb8+ZhH1{vb~m$B>MBM`z|1 z#5^rMUVnaX`TKpZQ*&=l+mLdA@7#%nx)*s8oL{l>9AR^Ql@==XDq*j~vZa!@>RvA~ zj`P2K?uqmAv+X9F5tC*Icx{Y5%W&`^R5Cwy(cY^5woNL)mzxe&FtnbeY&z9#7jl15kE^P___cHtH`HNpz|gz!F;3JbcZ}3d?>1tfdDKt|tNNHY9ql!vY ztl-LpOS1Q@Hr>Kd-Eg;}OY3`bMa2x~+pjpydj+zjRPUI0z1Ssq$aitedg;WsYxVU7 zuin1xou1CFqR4l~hJ(kcM8|iQg-W6Pw0}2}o<7brI3N4u!MUj_K?c&6zUNjcKQg}? z9>SX{e5uf5Nzjs8!YaQMFEfPkCCrh!U!=5IGwAKx`Rg`pfArF1&fa-JHxf)&-<;5} zgvr###;3U0`1!fHidySRohy0b{ua!7bb^QZe$4g;JHbf@{y9qI6#p%#d0;XvU$WG- zo&DM`i;5`2R2RvL^7Bp6s|xmUX{i3Xd)Q*Bj&zdL{k@y>PD+1dmV7nkB(wR9Jylxn zh8rd|mdBcGvE{ue8oZ=F^7yrA#vLTR_Rr!l z+vYTZbKjn8=db5+C2`99TXKf~oS&h^jTgIuT@2S>&QqD^clykms#h|ymzQrYj_t6P z^5yFldGY(FhVR9%+-w4ZSMs|bo^IKk-melB-N-VNZN|?6frb}1d`x-lPTiD|+;*cp zZQ6GEsC_B*w=a8a$?RE{Fr#nwpF07oFN<8-Y4F@&%GQd1`%m?pnbM&yRiVrJub?gJ z@Ok0azH$-5Gx}3qt)-*`8r*oTwo14N>LpA(y6gKi&Gg#2kLIP>n;+-l;bl8F?Z)@j zhEZoqxfKf@?C$?`Ao%~QHmBmxhY}g10-t<*_#j&6Pha#g*`?<{UgH$E{J2fB$EnrJ z*_Kz*V{5hLUir7?Z})H4ef;O@dzYQ*Tj%>6e0YPkdtuH@;l~q7TMn&?V!NGiT05EL z!{<}YhC-SiTlFVJ9_!~9KIq=6(8XYPYRb$d^JF;JJQhD)^w~&$Iu~F5JpIp)*n=hd z&bBSQI$im}ro+zyUsy=I$Z#p_SP*>hxQb(%N5aPAzNYp63mBi?`14g3 zGbC6FRB%`UPt(7zRlGG% zF6D!CZkLJ`FN?uS=VVDIT`5NypO=qP8Ll4w`eetE_@ESiC!y8~)o)kVh%^~qD%bTr z%iW}WB`LVOxy@O!mG6p|`EiCTakC61(#2K3DeSLXb?8@B^1%w@89xGNXmrhBS#dP2 zwdA8%!!Jhj1%;i4UGo22j|Ltn-mh0sk|L(OKJecQk(YN1|9x|r_w}pQ+w*npylXlA z__k)5EDBcg=%~sGJ1M+p^OBtJ8-)`^0Eywy;(3|dkBB@ zg&9W{_B1y-xi9ni9BE~nSTremwSTei$)$cW_Z9J@AR~85#W2tH2pKDv#4jez$+;>~!AshNLMC4I5s?2nB~mq3=DW-%jR~%X zZmpg&T^SYuw92Xtg5TQ8tkJHy8`zHTg6-SMah$(QVXij!M?x@`0 zD$92IN#VV)y>AXUE?l@|vbfmO?&_%>-cLgH>zk6K+GU#5?(PY!EtEG`^a)(jbjZCS zN^8xeyt-{Fj9&|+3k2t8K3gH+5P0Z7d#5k2THtzvw89w*r(~Qt)@rC-lyFYx{lLk$ z_C|we+tVMJQ}p^)+vOcsYi~{vU|e+Rjy_tK=}r*;MkW_Wa56#fEM(Ef2Ii9y##Px#ZBR%)II9 z74Ba*arSbFKD)rce$ZV)UQnd;lf?Q;&$sIu8Rov$QM2!DWYZ1X9G9r57%! zx~UTTr-rlg?StL(9@Tdlv<5H~g`5y{-SBZ|sDfLA)vJPx3CArK{@Nk#=zQUVKu*ca zXAWD>X+7I>WLfy;KXG|3hP}Qllc&ZR)p+cxi2S-yxP4N|#r1V3*hHpp*l4(tG3=bW z+4~K%Z7hw>+g^#=r*wDEl5d*?n>kyQq|{WMG-P~yl|Y;Rky=G{FDf9+`I5@WM_`5^b|aoadK z&J%j)H9s$1`zW?Sn?tRstxv!yMojDOo`qFEg}QVY^%5rpcTQIK%*}|6$`)N+5TQGF z&x)#_#Uhsvh&V|~7tfQ{Idw>U^c2&mN9xmh2IUmhuw(I-9V@K+WXO^B#woGhZ9?E9tNGul6&zm ztt8D>C`5gCMR{RunC%}%sm-BEOF143Ows!#zR@f9UcmI$TW=$JgcG_rpGEl2WZ~0% zKaY{|8Ha#ckFRZ))XN7Q;p_4ppZ~EreCOlkJrPr7es4Fgd(|5fdo$;YQjVPp&!QJC z7j4>71CvM#z{kwp+vVQ#c}k>ftKt=*K0d>jk2X9{+vvYY{O&~;>zrF;&3|P6=v!9lDQ6=U+%blBsBcu-q;PdJVm4h%9Lj= zQs#Ahdn)=?(7RgeE}hi#x7og4I%qvl@YIbniwrx@iX@9<993()Tw4-!&7~x)wdC4W zsXJGnq&ssZ{j&IO#$NfPxQ@rSFk#0L^Zf!*kFK`I&l0+9<*#+|lydvAoeyTK)_$pa zmwP%fR3>fKYl)ob7YXs+^0RsWUU(w^+`G3`|X(Sz2@uK%7nxU5#2_48Q!?lg@F z%3d=ieVneu2Y%P@zFon^*}m-LR2`?b!@ge`rJAMQ*UKnAwm#h!(X;NFLVSm0&$HZn z((5PuTH&CUZm?a;>!&@tq)c}5Y1sh76=lozeRrJK*ni4L8M_WGcifYE=Am>*hf(`M3n}G{o&GQTg;^eY1fke-?X$l5yo(Io0xt7 zI_@NG>3UAK`5DUlB(?IFd&-wiov&eGvqkN|wKRD@%OfYRxi(MCp1H^*C1KM&r6n^n zPR*5L^_6#1bXX*xxl=Fy|KVjD4$GbTJmJm^DZ#$A&mx3o*Ks{r8IZb^3^g|+r4C)6oYh`Y zbTMUx)-CHj=9h}1UkL2wyi~sN#lQ7WR=LM?r|dl8Gto;$Px|c6_ghW*lCG^^B6DTu z#tRX1Ibt`z@@D1ktovTrKD{XSxBcda&#s>Mxa`cypP8T2%?khdwEo?{_CK5QL8ki1 TsgCIk3=9mOu6{1-oD!M<52sIV diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_10.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_10.png deleted file mode 100644 index 82ec1d74a10731b3de0ef3edbea861bbaab9b681..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3619 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 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_11.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_11.png deleted file mode 100644 index f57e4badb0d6f26e2831e8cded97c6f280379ca9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3865 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 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_12.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_12.png deleted file mode 100644 index 43c78d9362425b586288ec8db8679bc475f5f412..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3836 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 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_14.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_14.png deleted file mode 100644 index 9e17a14404471492da4e35e0d5ba02a1dea2bd47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3891 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 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_15.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_15.png deleted file mode 100644 index d3fd0a9690d1cec728bb33a9d82c2b4a6895e98d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3830 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 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_2.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_2.png deleted file mode 100644 index a281efed09aa442639a8fb6e9bc0bf4a101ea322..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4126 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 sSNHRcSKEFv-?pei( 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 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_5.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_5.png deleted file mode 100644 index 486881b14ac0ae8f80295ceda41933dd919d12e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3858 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 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_6.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_6.png deleted file mode 100644 index 4038e71e9ff05c110a6c0666d8038ec3a3c310fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3756 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 X1-RTz59(uJU|{fc^>bP0l+XkKVF8#* diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_7.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_7.png deleted file mode 100644 index 383ef6398be750db4dacaaf67a1efffd1abd5bdd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3685 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9;Xep2*t>i( z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=fJs7>%~H+(vN{6;?MBM{j2L z#Dzf|3tL#&d3X(&9|`94Pxf+MA^&S4 z|2&Vk)4kT-@~Ul!&vem#a(mLG>jINZCNENP$X2>_%flqVcw6$LjmN*8xl?(!`uw~0 z>SyPAoL!WbzMZ)3-QzcVzeWB3dLw&nZc$NC&&4NCR4Pi|U!M2#Q*+#()%Kt2{~vkQ zk$vp{r^z|@_uYMYdAV(E`TX_we=48VWu91H|Kt0fKYRQ4rd=#PZ+o5Tjjmu-PS3;S zws~j&bG?yD&tOXa__eW$d)}do_IKXSY~QExtD5QIDo#b0{=YZVqxLUvt`uvaEqU9p} zQ(Vs(wi)~ulv)1!P79}VkLmr5b(^;y;`a@(`nxK>{$JE#(Pz8j%z|HEy&CrENv!Qb z=ATW>j|!FwX)7OY>o+uY$Ys-ep_zBdG(1pJva+`Eb9zQnQ?Rv8saVd|tLGArF(noi zUD}p=dyZZ0t#5B{+wS_FDI0z6)s3QKx$%FB^fGd|J{^!+DEDC7LE{%6A9?t5&v=+T z$7Sc=Il3#BhsGA`uk7J@zE1RR&760ar}O^ZaJ|#<*|gX{XayFZ&n{{FMYI$uk(wMo6M=IEoDk&okdW%hnu8yIvsp(g)N>efeYd%I`y?_c}k zwm$oG?z_kK|39!QD(cxEssCs8e@kHA^|9FJxx*Tb?;6tz|5q(|SNS8f`)PLX{k2DL zTsS=4_s@pw>!Ky@t4d6~p{cOZclH^!m2#zyNqn1wKG&uF>@Po`I=|9=chr-Y^L2mE z4xTP+zi;Qs=NoJ8XPrB}bM+C+1LvPf&9mD4;01Sj?#sI8S`3D6iF5gns~t4H(V-*0 zpzn99*s0@3#1v+KK5L%vWtC;Pu~}N^?bEjct}I-!&in4M9rwEh_;$xWYTERfD~)IM zS~iU%bIMq|Bb=Hph93CKYW4ZQwc(+)@zpoKUGiP6_u{*wE`@Z_mzrR{C{Js|bB2;XH+mGBEgpu@oC?sOyxgTRo>bEX#_!y5-g`%PCjCBn0m{|M|7wyv1eSbFUjL z*VBlawkzr2q)kngsj`-DQ$xS6t`68TM_A+Ot^9;~y$_ssHXd^-4%b_gQ}ydh=CN(2 z7k}TqV}k^j|1(L&uy!Afh@qTYg6S2V55?reDV-dJe%(rH_=FKfS;{vv1Qb31eNF2%eky~X2RBeb65oX6SKFAr@kyz>28Ms@!JwapV=r-wb;WF~%gR=Ai> z_Via%cd5PmJh$fVS*dfk9!yF!Wj|UGuPvLY_2D^JmFN|fS3<3K(w1F)#2EQQ>tIAq z)WHQWmLvpRRGsVf%Ot07@x18tdF{O%dMkD}%nI4PAb3*t=Lw09vX54@7jL+y8hZVL z@cYky3$Cyi&7JaCu0P)Of7!(;M?`0~naRHTmGbM+isgqD=LZe(cSLZqpPPAB{=9SvjwBYilULonnasI8!@5D_Fx{q4C znpki_H|TWJxgF)b$M~g>?n#I;xZZWa_p{!Sz4Q3n?`rKxx;bgnqBgymWt~kc1in|R z$$X1DI7vaY^hoVL%jN$kTD;o$A#}f1>AfD-xlCO_E8E(3wWYG&HRE7=WcOc+?`OfC z`z%&6U-S-&=1#kM^g%&Q{yS4s$7%UL=86jU{r=;;@29L0cazTbIL*E)J((@h0YW9m z0{OQdsJNhO6nH^1tNXW&WZy5|Zawa2D$`7g{`)Oiw8&-o3j23o?-m?6{@CvRiJw1m zJ1tE=bBXE9+?)~F-ZV+C)K*CK$_9sx zAFXIVtXQ5Dw#ZNJ>tdDp(-uj5|CwfyWuCRj%&~ukwtAi8VbRW@JI_x}6PVe(;%R%D z@5$7et6VR#b*>6}S9SaGisgp`4>yIUo?AV8V$`HlAxlr~TJr0H^!JJ~-VeJ?mK0t| zez@Z9&zlpT*(}rM$`y5fIN`ges?poRD-{+m9vc-KJujBOqma?P*w^t|!&di2(avJu zfB(vUW*2Yk#aQm4_At)vm1_^x0 z+F|$Z``Zr-zOUS^AbLUidzGC`(ekEQJ`*zIKd!u%*2&8IdC`qe+rR3S`2Tx1|4`!h zMH7#AuDVim=W+ZY#oJdxmhKYG?W?Xe-+pXX6Wa>!rMDi%-RE+z^$0n8e340i;>>-b zr=t%)ex9P|IcNF|VcqPAI7?QpU!|`%nD+g0w0M-t?+99uM>N` z7WjARd52!Suwg->Tl=h8-|nbdf6@rYVVy*|%MZ7?>sNgIam=OPY_A#T zy8h}}l@;rDR;#96*}LeW=uGWruCqV&tXt^q?7!#!$ATMtr_+`geQt_#ab=C2_Qg9V z=V*(woxY*+E}dO#o-BH>X_KouEAuI@D$y?sgO^QEzr0$k;D$S^;=9jh=UkU<%Dil3 z%e8;SzKC)qnN7Mp^DPoz{aMhdxl;43SCy*Svy(~Ry&g?gm%klbcJP|bOB>Cr>&~XV zZ3?;D6v@3VIQ*peUB#2eC;41$rG8zI{a$TWb9KGu>}e~L0+-L4_-9IFw8m6X6P0N! zs;r%UGkpu=<(TEZaLz3D^4pnmYs)NQC+*hv;n!AQpVYYH{{GheU*l$apE}2GD77vm z#H}rS_2#KHc9)kf@LrYRDJuTuspw7Sq}7X*L#J-(n!MKN)NHVs4dfb+0~wtGI5vZ-QK_Ki|s6V zo7kVbU)H=iu=4s!we{y2rDKCzroR(!c-`w}z`O}xKn#!Df z{Uyup*foZ4qJi%J>brh_GS%MOY~p`;)r^xnUmgGQx}mapO{nNLzTb1s%`^S|EHdlI zQ`y_5wR@);?c8^(XwnnUPd@jQZOl?1JvpG&Id4wm%d1jFVDAh z?=+2JeZoF(#-}rPna_SI3)uX9o7kE4op#x_chCNOepRe8;i&yR7xwK}%T_&mwso1U znTbVeQp$k~o3E@6|8m0SXeO5n?WgiQk+3CzZRfIr{hQnpev<$@`keMD^+E z26qH1Rc#gfQ=xTv-;K3KXU-nC{P%iw?wb3*j&oaa%`E>iH8;c+d+zpUx2dF^)ug#Ucmv~p(C&)2(j{~s?re*W&8zWYn!5)xKP-v0N=e)X~XU2h&G zU5!=WE+t)knZe*o&XtH6#otS7Ugf4b1^isk`gr}BOIvRq`F-;%%l3DVPI58l7T2XR ztEU_Hs!YE2+DNi@*3m6zr!Do>Qvb|gGbjHOgR`0sFW=6Mf9JHeZmOz2c;utKX~}Q# zDbIJ`E%QD2PFD8UEurhBD)a0%Kk<)?TC)B6k$}2|pYCLJ|9j+=wolIX)2F6(Kb_lg zufioc*M9iWHos9*@9WhP6;;oSdvaT+cX4s2)^h(j_&M~he`(bhsj~S?j4U!=)$m7e zeZeMop+~e7y*Gy8>i@L21x83}p5FC4F&(DTN&2>8aUb)Vh zJHIs9|K#oJu6-XbyDq({`u?Y^+M!dw6!-sq;kx(n%J+MMzP)Q)^zB=d)AuA}h4n92 z@B5gpBeiSpzoVMvIq%v0{m;$PrdCOj(=}uw)o1uj?-8xM%+R6Bmi0GwfrV}Qg5vg59L~wvd2KCU&pZ#03T8g@Z^pZFgDbP7 z?uqbcXPWA6USwobBRcolp4sN|;jeaIE2@5Vto7_#>4oOHzp4&h{IKy^MqJ!6^X>n1 yci*W|F8LJwY~$41&$hog_ET5&+y8HW_z(RN3hBLZPMd*&fx*+&&t;ucLK6TETXA6k diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_8.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_8.png deleted file mode 100644 index 0dc3a0e319d52baf64b686dc2f6a4f6c9ec57ccc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3611 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 MPgg&ebxsLQ0F8Meh5!Hn diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arc_9.png b/src/main/resources/assets/ebwizardry/textures/entity/arc_9.png deleted file mode 100644 index 4ffae58f91400bb5e189a08f2bb7f708b87d60a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3617 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 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/stone_statue_64.png b/src/main/resources/assets/ebwizardry/textures/entity/stone_statue_64.png deleted file mode 100644 index 2a7a2ad9e80833ba547596f6e51d94c9e9bf3a51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE#A&U%;gjC0aE$R#mjHf+a978H@y`5n=>5T%9 z%k21b1rBZxmH9hP{U{7}ZuibeNzK6A;9HOC5NrunX z>2rjZXRqzQvuREF`s>*p&bxNc>Ta_O*glgXA#(r8&`)b;oJg`&Kfn6Ire*aePQ`^6 zl~yj<^?O$L1lPay>knRS+?2PkOXt=0$SYCRCgS&H{(jTW^8KG*R(St=w1ks`W~yY; m{e4ZQwv`Mtg9qfFFxs!O-oI6A!o_e Date: Sun, 24 Jun 2018 15:50:02 +0100 Subject: [PATCH 30/68] Retexture flight wings --- .../ebwizardry/textures/entity/wing.png | Bin 1471 -> 1555 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/ebwizardry/textures/entity/wing.png b/src/main/resources/assets/ebwizardry/textures/entity/wing.png index da24e164e25920c944fd82ff1e2013841d85a2fc..f7081580309cc7405376016e3ad042cc37ee1ff0 100644 GIT binary patch delta 1452 zcmdnbJ(*`hAlE}KNl`K8mx9laPK?&6FZXnD42d}Wc6xM<%vH(b_0P||vFf`n&cS%Q z(_;rm=!d3`m)aLh=FQ~wdNo&ew)dR?y)J?6VYMqxxn{)&9F4xZe2WX$mPH#jZ&nj1 zD|6J~m>|&cMKg3M7boXRu1;sCH(Prj&;9(-VD~ArkWaT32FX{&oy$l&_hLCho@%@1PQ;RLb)5OP)c@H^bWf@Oc5U;C1dj##uS;lnCNM^J z?^L{SU3^8IMf2uj)>&eAUIg1;sWU$!c{*|KiPaT9Hzh4lY5c0nTitP_t+lSVMvi<}I#`|2!sPv5b~ZtMM~cex+7#+3_fyZLQ{O@V1z#K8p@WWKE2&lsR6 zud#u38{3up9YN-QcGfrj?!K};D^b}wEmlv%GvVeOS)n(%Y?8V`^_%~$>De705S3gK z{Yl_^UTc)WjNHjr_}wk|Gv4&CdwS)0@~a=GZi#p(n`_^=&2^=3Im5lfTvZNIT&2rA z{)A=qd^efV=9JG;6;$xOaQ?4{l6Rv0i@)BA4N$sZtHU4T;C6XVncSuN7pn7r92GHn zKc(<{^Q|D2x_zH>TFU1iXxqy2t(@n?#SPC54hLVk&+}0(uW`T7Ltp6#24%*t)1!{r z&hA>)>oxzY*h+b>!uqTY)7Cwm5;>c($;vtD`y#d|#!HWd_eZGhKi{M}e@D=<-K%?^ zYo7^7zZDyDuvTfow@x{`W}T{{h%SMYqcYTVcGBSUMWk=;jY zg$G%6RLJPT2nN) z{LwAAg?G zI_GrlwhF(M7QGY8z;;zfNWPj^J%8bJmc^{4M^&~KtyZ#Ay1+h(d1~l|;3eNybKSeQ z#QQ(f7OG(7aZaz{)p%>mJ6u2J~aE9$FigUtTiLl-lt^F zyK$&=bMmWx?O4rv1Lb$$<_pxv9s6C_6g6YfufW#3`usnUx`QF-4=Dz+#vkI^Jc#|)4g>r z6_+{HvKe!~rQUJxy7EtC(*4ZDe}!$i>3k(8_Z()eb~83{7d_j{Syj&(lJD^KuF=n0 z*H!hNsp*wXJEk;Q^*5g4n#8$cf55?=$_M{FxAd#sD)vlv?e&|wN((=a^M`fcnDsHU$fB+t1IN zHIX$XF)=_{xrv9%O?yk=iqCANMH8OYG+m83tsj1!t>j#zrBqq-oOcp_XX=^1{C{09 do>j}8a(bS{iZ7oRFfcGMc)I$ztaD0e0su;C&L02( delta 1367 zcmbQtv!8oHAlH3vadCG2jA$3OiP1Xs%APKcArXh)PP?Bk5-M`s{`;l zq801cZ2f$H_WtP7w_Q8t7G2=l*{#UALUf0uV{Ams?arR_6Z_dep5>lVx!$Qm+JQq+ zj6LBF*Tw#6(+~b_UpYr<_VyWTnx`;Hny)zLl=qC^tJvT0qJ-GBsO)^k3w#_mcUkmK zd#+Iyw|LVg=B;+kl{HfyG#$11sCB$<>W+S{Re$%cSXUn}ajNIG^xiGSpO&q-c6qvn zm1#&k+vg6oISd~@+FfXAuidkE)`uzm;V%wN^*-_UZvQ$4-gnL^uV1RJI^1aIYw$4m z#`L;Z9=_EKCW#Xi<8Ck5_r_?)dBvx1|NV#)F0L!qcNLsi+OWw1L{<3D$&9C3{~?x@)y5&1>)4NK9=Tus&~p62TqmrdWe>019h zQ74mkA)?l%4dbUSZx8GF0vj!2sIDLr zW+{5-j}z0Rt1Jf{xtvQMajf_$VrF?_liH2}omv;M{(FVNJc7ja}RJyN&Y#o6gs8y;pm?B}wu4qM`!}^`|S| zW-jtvrS(?r&z&eC4P<;?peKYZq{UlR6V?XE(<%NR~Hi)`au!aDhS%W{*0 zCzapaU|RM}<>U&JgZz9!O(qQy`~cGqh)YusI-cuS`62 z-=^f*@?%~Q+r{dZf=V^d1%)U0;3ANwjFJz<+N z_hc)xUF$>@tF|LMw_kLP)eGFYukq={%Sj)DSFQ?*6mneO|2;^mZZW6-lD_-Q!pwVT zedyl8Vr~{NJ$uE<)d72(^53N^3AMjH(V%9-T`-|(y5csbtL$q0^_Q}m{%X$1)hk-n zrx~^~Za>%6X9-pN8OkDk);n~yzL z;N3MgUWrGNo~dLl^RtOn*1LM*Z0>@X`=?thb=N#(?6k;nXJhq>NOEvX&|)%uyeLgw z^J>_}J!SKfzFcK4yHh0|v%yKiVUl|GGmYcdCj=f@`ojO(%&R}r?lW_Im1X?n_x0AH pO{Yqy-9A`ZcmC7 Date: Sun, 24 Jun 2018 15:51:28 +0100 Subject: [PATCH 31/68] Retexture leaf particles and move colouring to code --- .../wizardry/client/particle/ParticleLeaf.java | 2 ++ .../textures/particle/leaf_particles.png | Bin 701 -> 803 bytes 2 files changed, 2 insertions(+) diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java index 11efd7bb..dbfab7a5 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java @@ -20,6 +20,8 @@ public class ParticleLeaf extends ParticleCustomTexture { this.particleScale *= 1.4f; this.particleGravity = 0; this.canCollide = true; + // Produces a variety of browns and greens + this.setRBGColorF(0.1f + 0.3f * world.rand.nextFloat(), 0.5f + 0.3f * world.rand.nextFloat(), 0.1f); } @Override diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_particles.png index d24657c93072d5423f8974590e23d5a60be1d10a..627b30ef100913d0a5ad752c5c417e34b85e75fc 100644 GIT binary patch delta 773 zcmdnXx|nT(Ry_m5e+EZ4hJRBS7#KJUJR*x382Ao?FyoGi*>4#b7}!fZeO=ifv5AZG zu%xGN@n>LQ+TiKp7!q;#ZJ2Gou%ke2c4U#baEo?HO!16&XZ|1X;!0VyV}Wa6iWiea z3xfs^J-+ywdOH0nQsWRfrxdj62qCSf-Y%sqY%5IUO zy&;7^R_iy~QrsSQ! zL%rU;+Ss*op~Q}a8!~Pj)r>P{zRkP0V^83&a%0cT0`Zrjj0>)2X%==omJrX64Jcze zB&?^Q>nG0eq1S!hpN7qx`(M5l*ZHu=Y}YE5SE83S`jQ0#{XFz!POH_M%~7$G=Ra}J zrRDM8%6o{@UIqhoLOxgb(Hzs>ONSk(X>$6X#2j8VHUAH7NN@DTjZ!M`dvjx_eW=U*U-#Pc% ztji{)awl@!8h7MR3HR+d@x9O{eRe%Ji`BBZXF2sI3C*87S5`o9#>}Zft}H5^K^8OT zuHAd?OwOTGTLkC&?i4y4*||Yn!E=%m!)&j!rQr>!2hXZJQU9%-xhZGb!-Urpe3d5p zObt3^^YLCuxam6cPt&J(y70%nUA^7k|C+t*|8wjecP>X}UQX4|{u|h0UC#W)J+M$} zSDjTHTU)}-Jiqzt`MaXBywr{Nmxi{wf<;;49ht3qPL|$N^X|>qU|ubLELUcC zlkVsD{Yv`$A*$62LzNDlJnfhnRzLqeYo0;+u8@unul&aEH^mv4r!IS7e`}51%YLPt h@>e(P`rkLMKlg6WRi&^wy$lQt44$rjF6*2UngAVcUsC`8 delta 671 zcmZ3?wwHB+R{ej5{|x^Z>|H*Yfq{Xuz$3Dlfr0NJ2s7@OnEjT4fq}im)7O>#K9`iJ z2>-tjhIj@BCNEDH$B>A_Z^L$X-F6VMP3E~Asl8}rQ-N~KZ+|Anr@}%vPG#j52yO^Y zTRr6`V<`8}Mv;|IReh80w76Vl>AAXcmdNVWvc2yuxKz^WnfG1IhKtS73LV3F zM`x^=wD~a~M~oKd-iyyIR#+-IJox>m;iHb(|;jhc9mPWu7Nx)JMz|c;{jo>Xg5Q@jzenUpHS-?r(3O?dG_A z;K#N2NB?^bcn#(q-Mgp$*j#msUN6;+v2R+mH%485n_6VfmaxMx-Osw;fKA3i-FcEk zx>{)DLM`p}EQd`NY+XBrGx@;D3*u&-2E0|j57^l+xK{ewkhkrHz=ngCbA#sl9%3t~ zU;dt9OZetzjR(p$3ZHE#UtC)!uz0z0;OnRzY0fGZO=lTd843**%~`%Ls=vDHoyWx2 zzhATD%-!7|G=t5}SM*Jx{KV;zIrB6+%|F+<-1g4M_sg}`VEz^(|KoYn^iQQ?vtRdU zdaPhj{IF_`)ydSHi4aWG3g<5&_`f?YJv;QmAx!(D6WwwjgqpvmUZS}hZ81C(T zdjHRxpMT$mg$sTDewW+xHRqpo3G*I*U40})|Hq_X>n?OiaqfyLJJ`McxShijW!2l? z1REc9w{fZdn(*Kd`@Wd_)ohK^?N@~f$};^t-mD;G$NAIa#)F^B*WJ;0%To8vdq<3V h+rOU@i$6ETm+xr3J*9o|BnAcs22WQ%mvv4FO#toaI|cv% From ff87729ee8a4a06d0781a2c7a9e9ad5a479a1c01 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 15:52:59 +0100 Subject: [PATCH 32/68] Missed in 75e5de6 --- .../wizardry/client/renderer/RenderArcaneWorkbench.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneWorkbench.java b/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneWorkbench.java index 0d6bf0d1..c48bd903 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneWorkbench.java @@ -44,7 +44,7 @@ public class RenderArcaneWorkbench extends TileEntitySpecialRenderer Date: Sun, 24 Jun 2018 16:02:34 +0100 Subject: [PATCH 33/68] Rewrite raytracing methods and optimise their usage --- .../client/WizardryClientEventHandler.java | 63 +++--- .../electroblob/wizardry/spell/SpellRay.java | 97 +++++---- .../wizardry/util/WizardryUtilities.java | 201 ++++++++++-------- 3 files changed, 202 insertions(+), 159 deletions(-) diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java index e9ea54fb..ce053d6c 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -208,7 +208,6 @@ public final class WizardryClientEventHandler { Minecraft mc = Minecraft.getMinecraft(); WizardData properties = WizardData.get(mc.player); - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.world, mc.player, 16, false); RenderManager renderManager = event.getRenderer().getRenderManager(); ItemStack wand = mc.player.getHeldItemMainhand(); @@ -218,45 +217,51 @@ public final class WizardryClientEventHandler { } // Target selection pointer - if(mc.player.isSneaking() && wand.getItem() instanceof ItemWand && rayTrace != null && !(event.getEntity() instanceof EntityArmorStand) - && rayTrace.entityHit == event.getEntity() && properties != null && properties.selectedMinion != null){ + if(mc.player.isSneaking() && wand.getItem() instanceof ItemWand && WizardryUtilities.isLiving(event.getEntity()) + && properties != null && properties.selectedMinion != null){ + + // -> Moved this in here so it isn't called every tick + RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.world, mc.player, 16, false); + + if(rayTrace != null && rayTrace.entityHit == event.getEntity()){ - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); - GlStateManager.pushMatrix(); + GlStateManager.pushMatrix(); - GlStateManager.disableCull(); - GlStateManager.disableLighting(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); - // Disabling depth test allows it to be seen through everything. - GlStateManager.disableDepth(); - GlStateManager.color(1, 1, 1, 1); + GlStateManager.disableCull(); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + // Disabling depth test allows it to be seen through everything. + GlStateManager.disableDepth(); + GlStateManager.color(1, 1, 1, 1); - GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ()); + GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ()); - // This counteracts the reverse rotation behaviour when in front f5 view. - // Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example. - float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX; - GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F); - GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); + // This counteracts the reverse rotation behaviour when in front f5 view. + // Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example. + float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX; + GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F); - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - mc.renderEngine.bindTexture(targetPointerTexture); + mc.renderEngine.bindTexture(targetPointerTexture); - buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex(); - buffer.pos(0.2, 0.24, 0).tex(9f / 16f, 0).endVertex(); - buffer.pos(0.2, -0.24, 0).tex(9f / 16f, 11f / 16f).endVertex(); - buffer.pos(-0.2, -0.24, 0).tex(0, 11f / 16f).endVertex(); + buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex(); + buffer.pos(0.2, 0.24, 0).tex(9f / 16f, 0).endVertex(); + buffer.pos(0.2, -0.24, 0).tex(9f / 16f, 11f / 16f).endVertex(); + buffer.pos(-0.2, -0.24, 0).tex(0, 11f / 16f).endVertex(); - tessellator.draw(); + tessellator.draw(); - GlStateManager.enableCull(); - GlStateManager.enableLighting(); - GlStateManager.enableDepth(); + GlStateManager.enableCull(); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); - GlStateManager.popMatrix(); + GlStateManager.popMatrix(); + } } // Summoned creature selection pointer diff --git a/src/main/java/electroblob/wizardry/spell/SpellRay.java b/src/main/java/electroblob/wizardry/spell/SpellRay.java index 79b2f310..41c65e52 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellRay.java +++ b/src/main/java/electroblob/wizardry/spell/SpellRay.java @@ -70,6 +70,8 @@ public abstract class SpellRay extends Spell { protected boolean ignoreEntities = false; /** Whether liquids count as blocks when raytracing. Defaults to false. */ protected boolean hitLiquids = false; + /** The aim assist to use when raytracing. Defaults to 0. */ + protected float aimAssist = 0; public SpellRay(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, boolean isContinuous, double baseRange, SoundEvent sound){ this(Wizardry.MODID, name, tier, element, type, cost, cooldown, isContinuous, baseRange, sound); @@ -147,6 +149,17 @@ public abstract class SpellRay extends Spell { return this; } + /** + * Sets the aim assist to use when raytracing. + * @param particleVelocity The aim assist to use when raytracing. See {@link WizardryUtilities#rayTrace(World, Vec3d, + * Vec3d, float, boolean, Class, java.util.function.Predicate)} for more details. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public SpellRay aimAssist(float aimAssist){ + this.aimAssist = aimAssist; + return this; + } + @Override public boolean canBeCastByNPCs(){ return true; } // Finally everything in here is standardised and written in a form that's actually readable - it was long overdue! @@ -157,49 +170,7 @@ public abstract class SpellRay extends Spell { Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight() - Y_OFFSET, caster.posZ); - double range = baseRange * modifiers.get(WizardryItems.range_upgrade); - - // The first method will hit the first block it touches, passing through entities as if they weren't there. - // The second method will hit the first thing it touches, whether that's a block or an entity. - // Note that when it hits a block, the exact position hit is returned in hitVec, whereas when it hits an - // entity, it just returns the entity's position in hitVec. - RayTraceResult rayTrace = ignoreEntities - ? WizardryUtilities.standardBlockRayTrace(world, caster, range, hitLiquids) - : WizardryUtilities.standardEntityRayTrace(world, caster, range, hitLiquids); - - boolean flag = false; - - if(rayTrace != null){ - // Doesn't matter which way round these are, they're mutually exclusive - if(rayTrace.typeOfHit == RayTraceResult.Type.ENTITY){ - - Entity target = rayTrace.entityHit; - // Do whatever the spell does when it hits an entity - flag = onEntityHit(world, target, caster, ticksInUse, modifiers); - // If the spell succeeded, clip the particles to the correct distance so they don't go through the entity - if(flag){ - // The most pragmatic solution is to use the target's centre point for reasons explained earlier - double dx = origin.x - target.posX; - double dy = origin.y - (target.getEntityBoundingBox().minY + target.height/2); - double dz = origin.z - target.posZ; - range = MathHelper.sqrt(dx*dx + dy*dy + dz*dz); - } - - }else if(rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - // Do whatever the spell does when it hits an block - flag = onBlockHit(world, rayTrace.getBlockPos(), rayTrace.sideHit, caster, ticksInUse, modifiers); - // If the spell succeeded, clip the particles to the correct distance so they don't go through the block - if(flag) range = origin.distanceTo(rayTrace.hitVec); - } - } - - // If flag is false, either the spell missed or the relevant entity/block hit method returned false - if(!flag && !onMiss(world, caster, ticksInUse, modifiers)) return false; - - // Particle spawning - if(world.isRemote){ - spawnParticleRay(world, origin, look, range); - } + if(!shootSpell(world, origin, look, caster, ticksInUse, modifiers)) return false; if(!isContinuous) caster.swingArm(hand); // Bit of a dirty fix but I don't think it'll be a problem! if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); @@ -253,6 +224,46 @@ public abstract class SpellRay extends Spell { return true; } + /** Player and dispenser casting are almost identical so this takes care of the shared stuff. */ + private boolean shootSpell(World world, Vec3d origin, Vec3d direction, @Nullable EntityPlayer caster, int ticksInUse, SpellModifiers modifiers){ + + double range = baseRange * modifiers.get(WizardryItems.range_upgrade); + Vec3d endpoint = origin.add(direction.scale(range)); + + // The first method will hit the first block it touches, passing through entities as if they weren't there. + // The second method will hit the first thing it touches, whether that's a block or an entity. This method now + // returns the exact hit position for entities as well as blocks. + RayTraceResult rayTrace = WizardryUtilities.rayTrace(world, origin, endpoint, aimAssist, hitLiquids, Entity.class, e -> e == caster); + + boolean flag = false; + + if(rayTrace != null){ + // Doesn't matter which way round these are, they're mutually exclusive + if(rayTrace.typeOfHit == RayTraceResult.Type.ENTITY){ + // Do whatever the spell does when it hits an entity + flag = onEntityHit(world, rayTrace.entityHit, caster, ticksInUse, modifiers); + // If the spell succeeded, clip the particles to the correct distance so they don't go through the entity + if(flag) range = origin.distanceTo(rayTrace.hitVec); + + }else if(rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + // Do whatever the spell does when it hits an block + flag = onBlockHit(world, rayTrace.getBlockPos(), rayTrace.sideHit, caster, ticksInUse, modifiers); + // If the spell succeeded, clip the particles to the correct distance so they don't go through the block + if(flag) range = origin.distanceTo(rayTrace.hitVec); + } + } + + // If flag is false, either the spell missed or the relevant entity/block hit method returned false + if(!flag && !onMiss(world, caster, ticksInUse, modifiers)) return false; + + // Particle spawning + if(world.isRemote){ + spawnParticleRay(world, origin, direction, range); + } + + return true; + } + // Private helper method, no-one will need to override it since it's pretty much the whole point of this class. private void spawnParticleRay(World world, Vec3d origin, Vec3d direction, double distance){ diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index d9578fd6..d334e2a2 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -4,13 +4,13 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.UUID; import java.util.function.Function; +import java.util.function.Predicate; import javax.annotation.Nullable; @@ -553,118 +553,145 @@ public final class WizardryUtilities { // =============================================================================================================== /** - * Does a block ray trace (NOT entities) from an entity's eyes (i.e. properly...) + * Helper method which performs a ray trace for blocks only from an entity's eye position in the direction + * they are looking, over a specified range, using {@link World#rayTraceBlocks(Vec3d, Vec3d, boolean)}. + * + * @param world The world in which to perform the ray trace. + * @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye + * position and proceed in the direction the entity is looking. + * @param range The distance over which the ray trace will be performed. + * @param hitLiquids True to return hits on the surfaces of liquids, false to ignore liquid blocks as if they were + * not there. + * @return A {@link RayTraceResult} representing the object that was hit, which may be either a block or nothing. + * Returns {@code null} only if the origin and endpoint are within the same block. */ @Nullable public static RayTraceResult standardBlockRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids){ - - Vec3d start = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); - Vec3d look = entity.getLookVec(); - Vec3d end = start.addVector(look.x * range, look.y * range, look.z * range); - return world.rayTraceBlocks(start, end, hitLiquids); + // This method does not apply an offset like ray spells do, since it is not desirable in most other use cases. + Vec3d origin = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); + Vec3d endpoint = origin.add(entity.getLookVec().scale(range)); + return world.rayTraceBlocks(origin, endpoint, hitLiquids); } /** - * Helper method which does a rayTrace for entities from an entity's eye level in the direction they are looking - * with a specified range, using the tracePath method. Tidies up the code a bit. Border size defaults to 1. + * Helper method which performs a ray trace for blocks and entities from an entity's eye position in the direction + * they are looking, over a specified range, using {@link WizardryUtilities#rayTrace(World, Vec3d, Vec3d, float, + * boolean, Class, Predicate)}. Aim assist is zero, the entity type is simply {@code Entity} (all entities), and the + * filter removes the given entity and allows all others. * - * @param world - * @param entity - * @param range - * @return + * @param world The world in which to perform the ray trace. + * @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye + * position and proceed in the direction the entity is looking. This entity will be ignored when ray tracing. + * @param range The distance over which the ray trace will be performed. + * @param hitLiquids True to return hits on the surfaces of liquids, false to ignore liquid blocks as if they were + * not there. + * @return A {@link RayTraceResult} representing the object that was hit, which may be an entity, a block or + * nothing. Returns {@code null} only if the origin and endpoint are within the same block and no entity was hit. */ @Nullable - public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids){ - return standardEntityRayTrace(world, entity, range, 1, hitLiquids); + public static RayTraceResult standardEntityRayTrace(World world, Entity entity, double range, boolean hitLiquids){ + // This method does not apply an offset like ray spells do, since it is not desirable in most other use cases. + Vec3d origin = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); + Vec3d endpoint = origin.add(entity.getLookVec().scale(range)); + return WizardryUtilities.rayTrace(world, origin, endpoint, 0, hitLiquids, Entity.class, e -> e == entity); } /** - * Helper method which does a rayTrace for entities from a entity's eye level in the direction they are looking with - * a specified range and radius, using the tracePath method. Tidies up the code a bit. + * Performs a ray trace for blocks and entities, starting at the given origin and finishing at the given endpoint. + * As of wizardry 4.2, the ray tracing methods have been rewritten to be more user-friendly and implement proper + * aim assist. + *

+ * N.B. It is possible to ignore entities entirely by passing in a {@code Predicate} that is always false; + * however, in this specific case it is more efficient to use + * {@link World#rayTraceBlocks(Vec3d, Vec3d, boolean, boolean, boolean)} or one of its overloads. * - * @param world - * @param entity - * @param range - * @param borderSize - * @return - */ - @Nullable - public static RayTraceResult standardEntityRayTrace(World world, EntityLivingBase entity, double range, float borderSize, boolean hitLiquids){ - double dx = entity.getLookVec().x * range; - double dy = entity.getLookVec().y * range; - double dz = entity.getLookVec().z * range; - HashSet hashset = new HashSet(1); - hashset.add(entity); - return WizardryUtilities.tracePath(world, (float)entity.posX, - (float)(entity.getEntityBoundingBox().minY + entity.getEyeHeight()), (float)entity.posZ, - (float)(entity.posX + dx), (float)(entity.posY + entity.getEyeHeight() + dy), (float)(entity.posZ + dz), - borderSize, hashset, false, hitLiquids); - } - - /** - * Method for ray tracing entities. You can also use this for seeking. + * @param The type of entities to include; all other entities will be ignored. + * @param world The world in which to perform the ray trace. + * @param origin A vector representing the coordinates of the start point of the ray trace. + * @param endpoint A vector representing the coordinates of the finish point of the ray trace. + * @param aimAssist In addition to direct hits, the ray trace will also hit entities that are up to this distance + * from its path. For a normal ray trace, this should be 0. Values greater than 0 will give an 'aim assist' effect. + * @param hitLiquids Whether liquids should be ignored when ray tracing blocks + * @param entityType The class of entities to include; all other entities will be ignored. + * @param filter A {@link Predicate} which filters out entities that can be ignored; often used to exclude the + * player that is performing the ray trace. * - * @param world - * @param x startX - * @param y startY - * @param z startZ - * @param tx endX - * @param ty endY - * @param tz endZ - * @param borderSize extra area to examine around line for entities - * @param excluded any excluded entities (the player, etc) - * @return a RayTraceResult of either the block hit (no entity hit), the entity hit (hit an entity), or null for - * nothing hit + * @return A {@link RayTraceResult} representing the object that was hit, which may be an entity, a block or + * nothing. Returns {@code null} only if the origin and endpoint are within the same block and no entity was hit. + * + * @see WizardryUtilities#standardEntityRayTrace(World, Entity, double, boolean) + * @see WizardryUtilities#standardBlockRayTrace(World, EntityLivingBase, double, boolean) */ + // Interestingly enough, aimAssist can be negative, which means hits have to be in the middle of entities! @Nullable - public static RayTraceResult tracePath(World world, float x, float y, float z, float tx, float ty, float tz, - float borderSize, HashSet excluded, boolean collideablesOnly, boolean hitLiquids){ + public static RayTraceResult rayTrace(World world, Vec3d origin, Vec3d endpoint, float aimAssist, + boolean hitLiquids, Class entityType, Predicate filter){ + + // 1 is the standard amount of extra search volume, and aim assist needs to increase this further as well as + // expanding the entities' bounding boxes. + float borderSize = 1 + aimAssist; - Vec3d startVec = new Vec3d(x, y, z); - // Vec3d lookVec = new Vec3d(tx-x, ty-y, tz-z); - Vec3d endVec = new Vec3d(tx, ty, tz); - float minX = x < tx ? x : tx; - float minY = y < ty ? y : ty; - float minZ = z < tz ? z : tz; - float maxX = x > tx ? x : tx; - float maxY = y > ty ? y : ty; - float maxZ = z > tz ? z : tz; - AxisAlignedBB bb = new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ).grow(borderSize, borderSize, borderSize); - List allEntities = world.getEntitiesWithinAABBExcludingEntity(null, bb); - RayTraceResult blockHit = world.rayTraceBlocks(startVec, endVec, hitLiquids); - startVec = new Vec3d(x, y, z); - endVec = new Vec3d(tx, ty, tz); - float maxDistance = (float)endVec.distanceTo(startVec); - if(blockHit != null){ - maxDistance = (float)blockHit.hitVec.distanceTo(startVec); + // The AxisAlignedBB constructor accepts min/max coords in either order. + AxisAlignedBB searchVolume = new AxisAlignedBB(origin.x, origin.y, origin.z, endpoint.x, endpoint.y, endpoint.z) + .grow(borderSize, borderSize, borderSize); + + // Gets all of the entities in the bounding box that could be collided with. + List entities = world.getEntitiesWithinAABB(entityType, searchVolume); + // Applies the given filter to remove entities that should be ignored. + entities.removeIf(filter); + + // Finds the first block hit by the ray trace, if any. + RayTraceResult result = world.rayTraceBlocks(origin, endpoint, hitLiquids); + + // Clips the entity search range to the part of the ray trace before the block hit, if it hit a block. + if(result != null){ + endpoint = result.hitVec; } + + // Search variables Entity closestHitEntity = null; - float closestHit = maxDistance; - float currentHit = 0.f; - AxisAlignedBB entityBb;// = ent.getBoundingBox(); + Vec3d closestHitPosition = endpoint; + AxisAlignedBB entityBounds; RayTraceResult intercept; - for(Entity ent : allEntities){ - if((ent.canBeCollidedWith() || !collideablesOnly) - && ((excluded != null && !excluded.contains(ent)) || excluded == null)){ - float entBorder = ent.getCollisionBorderSize(); - entityBb = ent.getEntityBoundingBox(); - if(entityBb != null){ - entityBb = entityBb.grow(entBorder, entBorder, entBorder); - intercept = entityBb.calculateIntercept(startVec, endVec); - if(intercept != null){ - currentHit = (float)intercept.hitVec.distanceTo(startVec); - if(currentHit < closestHit || currentHit == 0){ - closestHit = currentHit; - closestHitEntity = ent; - } + + // Iterates through all the entities + for(Entity entity : entities){ + + entityBounds = entity.getEntityBoundingBox(); + + if(entityBounds != null){ + + // This is zero for everything except fireballs... + float entityBorderSize = entity.getCollisionBorderSize(); + // ... meaning the following line does nothing in all other cases. + // -> Added the non-zero check to prevent unnecessary AABB object creation. + if(entityBorderSize != 0) entityBounds = entityBounds.grow(entityBorderSize, entityBorderSize, entityBorderSize); + + // Aim assist expands the bounding box to hit entities within the specified distance of the ray trace. + if(aimAssist != 0) entityBounds = entityBounds.grow(aimAssist, aimAssist, aimAssist); + + // Finds the first point at which the ray trace intercepts the entity's bounding box, if any. + intercept = entityBounds.calculateIntercept(origin, endpoint); + + // If the ray trace hit the entity... + if(intercept != null){ + // Decides whether the entity that was hit is the closest so far, and if so, overwrites the old one. + float currentHitDistance = (float)intercept.hitVec.distanceTo(origin); + float closestHitDistance = (float)closestHitPosition.distanceTo(origin); + if(currentHitDistance < closestHitDistance){ + closestHitEntity = entity; + closestHitPosition = intercept.hitVec; } } } } + + // If the ray trace hit an entity, return that entity; otherwise return the result of the block ray trace. if(closestHitEntity != null){ - blockHit = new RayTraceResult(closestHitEntity); + result = new RayTraceResult(closestHitEntity, closestHitPosition); } - return blockHit; + + return result; } // SECTION Rendering and GUIs From 55ae4b1161c5e58e2fef32d43c5cb8d0afba23e9 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 16:08:28 +0100 Subject: [PATCH 34/68] Miscellaneous cleanup and commenting --- src/main/java/electroblob/wizardry/Wizardry.java | 10 ++++++++++ src/main/java/electroblob/wizardry/constants/Tier.java | 8 ++++---- .../wizardry/entity/projectile/EntityDart.java | 2 +- .../wizardry/entity/projectile/EntityIceShard.java | 2 +- .../wizardry/entity/projectile/EntityMagicArrow.java | 6 ++++++ .../wizardry/entity/projectile/EntityMagicMissile.java | 2 +- .../entity/projectile/EntityMagicProjectile.java | 1 + .../java/electroblob/wizardry/item/ItemSpellBook.java | 2 +- src/main/java/electroblob/wizardry/item/ItemWand.java | 6 +++--- src/main/java/electroblob/wizardry/spell/Wither.java | 3 ++- .../electroblob/wizardry/util/ParticleBuilder.java | 3 ++- .../java/electroblob/wizardry/util/WandHelper.java | 3 ++- .../electroblob/wizardry/util/WizardryUtilities.java | 1 + 13 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index dea4cf36..42b156ca 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -63,6 +63,7 @@ public class Wizardry { // IDEA: Improve the algorithm that finds a place to summon creatures to take walls into account. // IDEA: Replace all uses of Math.cos and Math.sin with MathHelper versions // IDEA: Triggering of inbuilt Forge events in relevant places? + // IDEA: Abstract the vanilla particles behind the particle builder /* Minor bugs that need fixing at some point: * - Player skin hat layer shows through wizard hats - Wizard armour breaks rather than just running out of mana (I @@ -78,6 +79,15 @@ public class Wizardry { // TODO: Switch from IInventory to IItemHandler (Or don't. It's only useful for automation really.) // TODO: Have particles obey Minecraft's particle setting where appropriate // (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java) + // TODO: Interfaces for various things, like 'stuff that can be put in the central slot of an arcane workbench' + // TODO: Go over all the worldgen code, use IWorldGenerator + // TODO: Implement a continuous sound system using MovingSoundEntity, allowing continuous spells to have a long sound + // loop as well as a start and end sound + // TODO: EntityMagicArrow needs attention + // TODO: Go over particle spawning on projectile impact and make sure hitvec is used wherever appropriate + // TODO: Replace spell IDs in packets with ResourceLocation strings + // TODO: Forcefield needs looking at, esp. with regards to projectiles and explosions + // TODO: TileEntityArcaneWorkbench needs looking at, esp. regarding inventory and markDirty // NOTE: Add melee upgrades to loot tables when they are added. diff --git a/src/main/java/electroblob/wizardry/constants/Tier.java b/src/main/java/electroblob/wizardry/constants/Tier.java index 6c7d8958..8d9c0e77 100644 --- a/src/main/java/electroblob/wizardry/constants/Tier.java +++ b/src/main/java/electroblob/wizardry/constants/Tier.java @@ -10,10 +10,10 @@ import net.minecraftforge.fml.relauncher.SideOnly; public enum Tier { - BASIC(700, 3, 12, new Style().setColor(TextFormatting.WHITE), "basic"), APPRENTICE(1000, 4, 5, - new Style().setColor(TextFormatting.AQUA), "apprentice"), ADVANCED(1500, 5, 2, - new Style().setColor(TextFormatting.DARK_BLUE), - "advanced"), MASTER(2500, 6, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master"); + BASIC(700, 3, 12, new Style().setColor(TextFormatting.WHITE), "basic"), + APPRENTICE(1000, 5, 5, new Style().setColor(TextFormatting.AQUA), "apprentice"), + ADVANCED(1500, 7, 2, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"), + MASTER(2500, 9, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master"); /** Maximum mana a wand of this tier can store. */ public final int maxCharge; diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java index 02eafdb6..cec42cf3 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java @@ -15,7 +15,7 @@ public class EntityDart extends EntityMagicArrow { super(world); } - @Override public double getDamage(){ return 4.0d; } + @Override public double getDamage(){ return 4; } @Override public boolean doGravity(){ return true; } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java index 483d1c55..936acacc 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java @@ -17,7 +17,7 @@ public class EntityIceShard extends EntityMagicArrow { super(world); } - @Override public double getDamage(){ return 6.0d; } + @Override public double getDamage(){ return 6; } @Override public DamageType getDamageType(){ return DamageType.FROST; } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java index 64091a91..bf2e5166 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java @@ -252,6 +252,9 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE this.ticksInGround = 0; ++this.ticksInAir; + + // Does a ray trace to determine whether the projectile will hit a block in the next tick + Vec3d vec3d1 = new Vec3d(this.posX, this.posY, this.posZ); Vec3d vec3d = new Vec3d(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ); RayTraceResult raytraceresult = this.world.rayTraceBlocks(vec3d1, vec3d, false, true, false); @@ -262,6 +265,9 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE vec3d = new Vec3d(raytraceresult.hitVec.x, raytraceresult.hitVec.y, raytraceresult.hitVec.z); } + + // Uses bounding boxes to determine whether the projectile will hit an entity in the next tick, and if so + // overwrites the block hit with an entity Entity entity = null; List list = this.world.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox() diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java index e2ccd32b..60a3e60b 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java @@ -13,7 +13,7 @@ public class EntityMagicMissile extends EntityMagicArrow { super(world); } - @Override public double getDamage(){ return 4.0d; } + @Override public double getDamage(){ return 4; } @Override public boolean doGravity(){ return false; } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java index 0045eb34..93e5b9ef 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java @@ -70,6 +70,7 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I // Depends on the horizontal distance between the two entities and accounts for bullet drop, // but of course if gravity is ignored this should be 0 since there is no bullet drop. float bulletDropCompensation = !this.hasNoGravity() ? (float)horizontalDistance * 0.2f : 0; + // It turns out that this method normalises the input (x, y, z) anyway this.shoot(dx, dy + (double)bulletDropCompensation, dz, speed, aimingError); } } diff --git a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java index eb785366..b43d5889 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java @@ -36,7 +36,7 @@ public class ItemSpellBook extends Item { @Override public void getSubItems(CreativeTabs tab, NonNullList list){ - if (isInCreativeTab(tab)) { + if(isInCreativeTab(tab)) { // In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance // is not required, only the id. for(int i = 0; i < Spell.getTotalSpellCount(); i++){ diff --git a/src/main/java/electroblob/wizardry/item/ItemWand.java b/src/main/java/electroblob/wizardry/item/ItemWand.java index bdc1d183..d772ad55 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWand.java +++ b/src/main/java/electroblob/wizardry/item/ItemWand.java @@ -167,7 +167,7 @@ public class ItemWand extends Item implements IWorkbenchItem { text.add("\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wand.spell", discovered ? "\u00A77" + spell.getDisplayNameWithFormatting() - : "#\u00A79" + SpellGlyphData.getGlyphName(spell, player.world))); + : "#\u00A79" + SpellGlyphData.getGlyphName(spell, player.world))); text.add("\u00A79" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wand.mana", (this.getMaxDamage(itemstack) - this.getDamage(itemstack)), this.getMaxDamage(itemstack))); @@ -208,7 +208,7 @@ public class ItemWand extends Item implements IWorkbenchItem { // Conditions for the spell to be attempted. The tier check is a failsafe; it should never be false unless the // NBT is modified directly. if(!spell.isContinuous && spell.tier.level <= this.tier.level - // Checks that the wand has enough mana to cast the spell + // Checks that the wand has enough mana to cast the spell && spell.cost <= (stack.getMaxDamage() - stack.getItemDamage()) // Checks that the spell is not in cooldown or that the player is in creative mode && (WandHelper.getCurrentCooldown(stack) == 0 || player.capabilities.isCreativeMode)){ @@ -238,7 +238,7 @@ public class ItemWand extends Item implements IWorkbenchItem { float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(stack, WizardryItems.cooldown_upgrade) - * Constants.COOLDOWN_REDUCTION_PER_LEVEL; + * Constants.COOLDOWN_REDUCTION_PER_LEVEL; if(player.isPotionActive(WizardryPotions.font_of_mana)){ // Dividing by this rather than setting it takes upgrades and font of mana into account diff --git a/src/main/java/electroblob/wizardry/spell/Wither.java b/src/main/java/electroblob/wizardry/spell/Wither.java index bd356785..3cacf432 100644 --- a/src/main/java/electroblob/wizardry/spell/Wither.java +++ b/src/main/java/electroblob/wizardry/spell/Wither.java @@ -23,6 +23,7 @@ import net.minecraft.world.World; public class Wither extends SpellRay { private static final int BASE_DURATION = 200; + private static final int BASE_DAMAGE = 1; public Wither(){ super("wither", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 10, 20, false, 10, SoundEvents.ENTITY_WITHER_HURT); @@ -40,7 +41,7 @@ public class Wither extends SpellRay { this.getNameForTranslationFormatted())); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), - 1.0f * modifiers.get(SpellModifiers.POTENCY)); + BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.WITHER, (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1)); } diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index 880b437f..d88cd00f 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -72,7 +72,8 @@ public final class ParticleBuilder { /** Single pixel particle.

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

Lifetime: 10-15 ticks
Velocity: (0, -0.03, 0) */ LEAF, + /** Single leaf.

Defaults:

Lifetime: 10-15 ticks
Velocity: (0, -0.03, 0) + *
Colour: green/brown */ LEAF, /** Bubble that doesn't burst in air.

Defaults:

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

Defaults:

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

Defaults:

Lifetime: 8-40 ticks
Colour: white */ PATH, diff --git a/src/main/java/electroblob/wizardry/util/WandHelper.java b/src/main/java/electroblob/wizardry/util/WandHelper.java index 6c47c18a..a98788fb 100644 --- a/src/main/java/electroblob/wizardry/util/WandHelper.java +++ b/src/main/java/electroblob/wizardry/util/WandHelper.java @@ -260,7 +260,8 @@ public final class WandHelper { /** * Applies the given upgrade to the given wand, or in other words increases the level for that upgrade by 1. This - * does not account for the individual or total upgrade stack limits. + * does not account for the individual or total upgrade stack limits or any special behaviour; it only deals + * with the NBT data. */ public static void applyUpgrade(ItemStack wand, Item upgrade){ diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index d334e2a2..6cb52655 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -545,6 +545,7 @@ public final class WizardryUtilities { * private. (You could call {@link EntityCreeper#onStruckByLightning(...)} and then heal it and extinguish * it, but that's a bit awkward.) */ + // The reflection here only gets done once to initialise the POWERED field, so it's not a performance issue at all. public static void chargeCreeper(EntityCreeper creeper){ creeper.getDataManager().set(POWERED, true); } From ee3fca35bd3d363963e619485e5ae5b20bd592da Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 16:12:40 +0100 Subject: [PATCH 35/68] Particle tweaks and fixes --- .../wizardry/entity/construct/EntityForcefield.java | 2 +- .../electroblob/wizardry/entity/projectile/EntityDart.java | 2 +- .../wizardry/entity/projectile/EntityIceLance.java | 2 +- src/main/java/electroblob/wizardry/spell/LightningRay.java | 2 +- src/main/java/electroblob/wizardry/spell/LightningWeb.java | 2 +- .../java/electroblob/wizardry/util/ParticleBuilder.java | 6 +++++- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java index 1a77659d..7ad68328 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java @@ -67,7 +67,7 @@ public class EntityForcefield extends EntityMagicConstruct { .pos(this.posX + radius * Math.cos(yaw) * Math.cos(pitch), this.posY + 3 + radius * Math.sin(pitch), this.posZ + radius * Math.sin(yaw) * Math.cos(pitch)) .lifetime(48 + this.rand.nextInt(12)) - .colour(brightness, brightness, 1.0f); + .colour(brightness, brightness, 1.0f).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java index cec42cf3..1ab9c0f0 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java @@ -36,7 +36,7 @@ public class EntityDart extends EntityMagicArrow { @Override public void tickInAir(){ if(this.world.isRemote){ - ParticleBuilder.create(Type.LEAF).pos(this.posX, this.posY, this.posZ).lifetime(10 + rand.nextInt(5)); + ParticleBuilder.create(Type.LEAF, this).lifetime(10 + rand.nextInt(5)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java index 2a6094c0..5666ca18 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java @@ -46,7 +46,7 @@ public class EntityIceLance extends EntityMagicArrow { if(this.world.isRemote){ for(int j = 0; j < 10; j++){ ParticleBuilder.create(Type.ICE, this.rand, this.posX, this.posY, this.posZ, 0.5, true) - .lifetime(20 + rand.nextInt(10)).spawn(world); + .lifetime(20 + rand.nextInt(10)).gravity(true).spawn(world); } } // Parameters for sound: sound event name, volume, pitch. diff --git a/src/main/java/electroblob/wizardry/spell/LightningRay.java b/src/main/java/electroblob/wizardry/spell/LightningRay.java index c2eb74a6..de680000 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningRay.java +++ b/src/main/java/electroblob/wizardry/spell/LightningRay.java @@ -85,7 +85,7 @@ public class LightningRay extends SpellRay { }else{ // Particle effect for(int i=0; i<5; i++){ - ParticleBuilder.create(Type.SPARK, target); + ParticleBuilder.create(Type.SPARK, target).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/spell/LightningWeb.java b/src/main/java/electroblob/wizardry/spell/LightningWeb.java index 548bec0e..72b2cc67 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningWeb.java +++ b/src/main/java/electroblob/wizardry/spell/LightningWeb.java @@ -163,7 +163,7 @@ public class LightningWeb extends SpellRay { }else{ // Particle effect for(int i=0; i<5; i++){ - ParticleBuilder.create(Type.SPARK, target); + ParticleBuilder.create(Type.SPARK, target).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index d88cd00f..24bbae18 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -355,7 +355,11 @@ public final class ParticleBuilder { particle.multipleParticleScaleBy(scale); if(!Double.isNaN(vx) && !Double.isNaN(vy) && !Double.isNaN(vz)) particle.setVelocity(vx, vy, vz); if(r >= 0 && g >= 0 && b >= 0) particle.setRBGColorF(r, g, b); - if(fr >= 0 && fg >= 0 && fb >= 0) particle.setFadeColour(fr, fg, fb); + if(fr >= 0 && fg >= 0 && fb >= 0){ + particle.setFadeColour(fr, fg, fb); + }else{ + particle.setFadeColour(r, g, b); // If fade colour was unspecified, it defaults to the main colour + } if(lifetime >= 0) particle.setLifetime(lifetime); particle.setGravity(gravity); particle.setShaded(shaded); From a49756ddaa8c5514c98d83dea6b9e31023291097 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 16:13:04 +0100 Subject: [PATCH 36/68] Add vector-based position and velocity methods to ParticleBuilder --- .../wizardry/util/ParticleBuilder.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index 24bbae18..839dc831 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -6,6 +6,7 @@ import electroblob.wizardry.Wizardry; import net.minecraft.entity.Entity; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; /** @@ -184,6 +185,19 @@ public final class ParticleBuilder { return this; } + /** + * Sets the position of the particle being built. This is a vector-based alternative to {@link ParticleBuilder#pos( + * double, double, double)}, allowing for even more concise code when a vector is available. + *

+ * Affects: All particle types + * @param pos A vector representing the coordinates of the particle to be built. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder pos(Vec3d pos){ + return pos(pos.x, pos.y, pos.z); + } + /** * Sets the velocity of the particle being built. If unspecified, this defaults to the particle's default velocity, * specified within its constructor. @@ -203,6 +217,19 @@ public final class ParticleBuilder { return this; } + /** + * Sets the velocity of the particle being built. This is a vector-based alternative to {@link ParticleBuilder#vel( + * double, double, double)}, allowing for even more concise code when a vector is available. + *

+ * Affects: All particle types + * @param vel A vector representing the velocity of the particle to be built. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder vel(Vec3d vel){ + return vel(vel.x, vel.y, vel.z); + } + /** * Sets the colour of the particle being built. If unspecified, this defaults to the particle's default colour, * specified within its constructor. From 53aa19d1a14b7f3cec29ef26f3c898c1e9f43798 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 16:13:40 +0100 Subject: [PATCH 37/68] Fix darkness orb spell shooting thunderbolts instead of darkness orbs --- src/main/java/electroblob/wizardry/registry/Spells.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/registry/Spells.java b/src/main/java/electroblob/wizardry/registry/Spells.java index 7fcc7da8..64abadc4 100644 --- a/src/main/java/electroblob/wizardry/registry/Spells.java +++ b/src/main/java/electroblob/wizardry/registry/Spells.java @@ -24,6 +24,7 @@ import electroblob.wizardry.entity.living.EntitySpiderMinion; import electroblob.wizardry.entity.living.EntityStormElemental; import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; import electroblob.wizardry.entity.living.EntityZombieMinion; +import electroblob.wizardry.entity.projectile.EntityDarknessOrb; import electroblob.wizardry.entity.projectile.EntityDart; import electroblob.wizardry.entity.projectile.EntityFirebolt; import electroblob.wizardry.entity.projectile.EntityFirebomb; @@ -311,7 +312,7 @@ public final class Spells { registry.register(new SpellMinion<>("summon_wither_skeleton", Tier.ADVANCED, Element.NECROMANCY, 35, 150, EntityWitherSkeletonMinion::new, 600, WizardrySounds.SPELL_SUMMONING).soundValues(7, 0.6f, 0)); registry.register(new Entrapment()); registry.register(new WitherSkull()); - registry.register(new SpellProjectile("darkness_orb", Tier.ADVANCED, Element.NECROMANCY, 20, 20, EntityThunderbolt::new, 0.5f, SoundEvents.ENTITY_WITHER_SHOOT).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellProjectile("darkness_orb", Tier.ADVANCED, Element.NECROMANCY, 20, 20, EntityDarknessOrb::new, 0.5f, SoundEvents.ENTITY_WITHER_SHOOT).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new ShadowWard()); registry.register(new Decay()); registry.register(new SpellBuff("water_breathing", Tier.ADVANCED, Element.EARTH, SpellType.BUFF, 30, 250, WizardrySounds.SPELL_HEAL, 0.3f, 0.3f, 1, Triple.of(MobEffects.WATER_BREATHING, 1200, 0)){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); From f8eecfc6d5120178dd21719bafa0dd13e87f660b Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 16:14:17 +0100 Subject: [PATCH 38/68] Retexture wands --- .../ebwizardry/textures/items/wand_advanced.png | Bin 506 -> 461 bytes .../textures/items/wand_advanced_earth.png | Bin 470 -> 450 bytes .../textures/items/wand_advanced_fire.png | Bin 473 -> 490 bytes .../textures/items/wand_advanced_healing.png | Bin 461 -> 474 bytes .../textures/items/wand_advanced_ice.png | Bin 455 -> 454 bytes .../textures/items/wand_advanced_lightning.png | Bin 485 -> 450 bytes .../textures/items/wand_advanced_necromancy.png | Bin 470 -> 485 bytes .../textures/items/wand_advanced_sorcery.png | Bin 468 -> 466 bytes .../textures/items/wand_apprentice.png | Bin 456 -> 456 bytes .../textures/items/wand_apprentice_earth.png | Bin 459 -> 442 bytes .../textures/items/wand_apprentice_fire.png | Bin 447 -> 459 bytes .../textures/items/wand_apprentice_healing.png | Bin 443 -> 459 bytes .../textures/items/wand_apprentice_ice.png | Bin 445 -> 435 bytes .../items/wand_apprentice_lightning.png | Bin 449 -> 432 bytes .../items/wand_apprentice_necromancy.png | Bin 443 -> 510 bytes .../textures/items/wand_apprentice_sorcery.png | Bin 441 -> 457 bytes .../ebwizardry/textures/items/wand_basic.png | Bin 405 -> 418 bytes .../textures/items/wand_basic_earth.png | Bin 404 -> 406 bytes .../textures/items/wand_basic_fire.png | Bin 396 -> 439 bytes .../textures/items/wand_basic_healing.png | Bin 394 -> 420 bytes .../textures/items/wand_basic_ice.png | Bin 397 -> 403 bytes .../textures/items/wand_basic_lightning.png | Bin 400 -> 363 bytes .../textures/items/wand_basic_necromancy.png | Bin 394 -> 361 bytes .../textures/items/wand_basic_sorcery.png | Bin 389 -> 422 bytes .../ebwizardry/textures/items/wand_master.png | Bin 517 -> 469 bytes .../textures/items/wand_master_earth.png | Bin 477 -> 480 bytes .../textures/items/wand_master_fire.png | Bin 478 -> 467 bytes .../textures/items/wand_master_healing.png | Bin 477 -> 492 bytes .../textures/items/wand_master_ice.png | Bin 504 -> 463 bytes .../textures/items/wand_master_lightning.png | Bin 512 -> 496 bytes .../textures/items/wand_master_necromancy.png | Bin 447 -> 492 bytes .../textures/items/wand_master_sorcery.png | Bin 488 -> 465 bytes 32 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_advanced.png b/src/main/resources/assets/ebwizardry/textures/items/wand_advanced.png index 02a3044e4b906970dd0eaae4898d5cedfa6301b6..578a9128e169750c776e789bbc72c80446b3613d 100644 GIT binary patch delta 427 zcmeyxe3p5FPW>tdhUX`ixH2#>a29w(7Bet#3xhBt!>loS1Y7Q3FL+V@B2Uoj z#gl+rI(mLl+)W%}j#@1qhTa0J)*g*eUg>+4XP$HBh8y+vf%#VND!$9Tf7ejY_FX){ zdwXV)Uf1c(T59{u{mR}2+`F2%{S$Lzmxh3;)RUd^JG3k`RvkYmsJL`8fAHKtU=zAA(x>pD!kbMx%%QTPpC!M~Vz!Y}N)KtC zc_VnkHW}xz)jvxQ*B9;F$ea>+Y|FBVCq8Rb=-X*rkg9(0HG*emmF$d%bsP9)FC5Rg zZD2Kbq02(YqZKcvn*GoSIW5J>c45DptB8jnYgE^#6Bhg)%P!AR@l^KxcKw6|N5!F6 z(K3;1+fuT$f6O#yd*#+5#ChSAQ;Uk{A&W8w4&!USXa3miI3>cc{q-i5P`+=yJ&b47 h{uJv@t^2+(K7x6odtCm+4Gatn44$rjF6*2UngDJ}vqS&@ delta 472 zcmX@h{EK;lPW^v|{|ojmpUl9(z**oCSEak-aeC=wM~}&g636S`o1OIK-{$|~R^lxeL-x)SU3&Qfa!I?-95guT z+5?%#b>pq2az4Iix#{v%5rr*GVOJMj;Z04w;wjvSKdmQb^CFmNYbl6Z!GtI z`0(5Q{O5l^57$q#;x{q3)ctK{eRHa>OxOVr6Sd~tw|9zqH@^OT?DhBj4Uvtz^~;Ku zz7(9U9v5UN{3q;Ego04-$@%4HH}=2&CT=&|enyx6WDm8ekDu>o{L+xVglS5^tNZyE zqnJ0$i+%idx%h$>rHP>%2 ztTip?aZYylTzxVLvE0Z0EUp~3|&Ftpfxx(x> z{dQHJc$>$;e4{_=+HLy}H*Q}&eCe3}B7S*|%O)qEe>SCD$js`7jdTCAsD iR!?Z-lGjoF!XWI@fAvU_jtm0>1B0ilpUXO@geCxpM} diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_earth.png b/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_earth.png index 940da730367d437338d53ae40053beaf773fa7b8..1c165aafe0e4d594f4d0a2dc6056976bdebe364d 100644 GIT binary patch delta 418 zcmcb{e2961R=orR9|O;--)yoB3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_Hg-X6 zIgyYnwG0f5{+=$5Ar_~XPTuS7lqk|Jf0k{x$dA?u6B8%1@E$yR^x#9G9XnlfeXm}) zcJGnU#i;*|CZ?X2EdmxQjj0p(rk`1JWS7>&seA`BIhHEc?|*e*=Dp8*oD!B zrz>yn{oY--SFLWol0&`dmZr}y&66%F9Sd6Y_u6+JCr0ay8Eg&Bf7y$EmIwQbn)oVz zpCfiOHTA_e)`pcI1^enJyXAj1@jYyuJ$>iVOv%#drNMJ{hNsyECON&l^K!kjOkUa% z+hk||DJ$$veRk?iomGG8YSH@RUdo|q*~Q0~tjf9`c2;-C0}~AkUMEKD<R+#LnL3|<8P6`(5Z1Z89Q9|*>}9=+j-LJmh`ptkqmZP8#cwTN3w;4wqTc9hJ;H}Nvu(Uz$w*t_5v5f zIC?K$5Zdze#-)%8mqcHUh8E)ID;^Kcv zLTJTG>#a@fI<_9iiZpEM{$^e&;rf*{Cs%K!?i~ez4>K$u7;e6r7Tk)_ieP6Q)=3?!ihH-^sQ4Tin=;lmoqf1`p4y=KY6>3uF6dY t{qiDtCWb2$oHaLbxHNF-Sy^q6mo(}8BlY0>A_fKq22WQ%mvv4FO#mUzxIO>? diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_fire.png b/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_fire.png index 2acb5a5754c80b6f130b489e4917a39136d3d80b..08af07878cba619c28abc7696048e7ede02d56cf 100644 GIT binary patch delta 458 zcmcb~{EB&kR=orR9|O;--)yoB3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_Hg-`t zuGQPJvKSZ`%ROBjLo813owV26DNv$)ezD-EG}U`ii%vMjWbtHbEYB(YB%hJdwLo>z ze+7+28D1S39Z^jMoH9a93(hJoD%m(Yu<6oq)81WQ81w5dx3XQdE}iz7?|J3D`uv9gn`BOQ0X(W$MQ zJNK?_-94?EaNk!yl}`l~i(5U1!$42bncbmS(1AfNYyJ_w^E2f# zlqVZAa!6KXJ4RR3hcKpihbsMLiqYL1EXsJ}rjCzopr0Ao?VTL1t6 delta 441 zcmaFGe3N;CR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(pS zAo%_44mJh`#xzeC#}JFtODFqlG$+a&x98V4p0>r@{AQ}M;7?=qqDn8{vsL-p^^2x- zzn&cvGv~>p2M-=J6-|n{QWUgfPcnP^)juZ_cW>~`oULh7&!_Y$|M5<{TD$$vfB*S) z$iDvv_ZD;8bqs43CvQn|FwR)P7|uJ_n14!K{6?u=x-lQP%B_=ZvsL%{C4B*nC-+CD^FfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#SY-v- z%=u2-zRJMBnC|J~7-DgH>12Bkr$CYR`t9>9I82`?2=19C#k0IZz~e>1bcGkWswS=q zoTj^4S>9f?>}pXZy|lWum=un%KhqISZE>74DgIq*9~r`JXgj1Bnk4{;d<-o4RoI?j5!>jqf=c zJW#xU#bU*TL*eh(1X%8}??ug~n*yvKc`|bCpjt&jYOHVXTm>=|Bf!saiPnKH=g4*0|Nttr>mdKI;Vst041`+ AH~;_u delta 429 zcmcb`e3p5FR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(pS z&bj)*w&@HEj8UF0jv*GOmrma6?UX2SwBCG)PqTt76T5iki5!9VLPEUnF9hv)G9{*| z>rV#PFYO$TRS)$9%X4!wIlC4p=6W1l;M1|qZh_Gy#d&S@0UT%htBx~2pYz=IdF6xo z{=d0jD$0v9-2QE6dsjgB@`U!9m^=UM?i~Iu@_yA^?uccImxcN6{L`=zeR!1bLfio( z-k*$j-Z^k?5^ryL7H4|<>@IFe=J+*CQ!Z{f7BMC0%D*|fA&fU{zcKCnrg%+lMtqdY z)>$ha-;Un-ja6f*K^j~A(t@p;Cqo=|tqRm^UH(5NZ8@9Adt2c-UrbA{M@@9!vsY%$ z6wBRzeq23qjmKn>T;U#3kN39QRm`ts%xsHTrnvB=g8Nd%ByH(g>t5>?ukwGOqNIIV ze@bfal`N+J8GAmPmJ10APApvBF?WMXFyqD2xn=JdT$JuJt-G*wN6(@goZf2Y-xHaC nJem0Y3{%R2Lz&^?zgP|S*6iB)C&`n6fq}u()z4*}Q$iB}5n8@@ diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_ice.png b/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_ice.png index 653e67ed1f11bc6558a5fee7c12d15ef0b886f60..851321d33d887e53bb951c1d3b40b34bcf0df703 100644 GIT binary patch delta 422 zcmX@ke2jU5R=orR9|O;--)yoB3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_Hg-`J zu~~92Vi*`0gFRgwLo7}&4c_m~lqgYWSD5K(lJT1TThj-F*VCKt zAFH6r7C8~oysh^N*xPxFS^~TT;+FDFy3`q%(zMrCuC;z;{8wN78XNn2-z(!E%f-X{!Ipwa*M4w3>Rb|?pYt}rEc}>s_T#OQP1D0g7^Xd*ZLrGB=&aSLqe@xk)6X2v zj-Had!be^3Vh)DM$<58t}|w5(zGA>A*`yk8smE!G}1E%m{o|kNv43=#Wc9VefFt&@KyS;;RjW4WtX6NF-IOI2;LE&7rug8U-Lf-g zt1B&P?dIY2Z_mg~?PYOnP~c$R80X4(M%}^YHhXgaJ9qor_tO?=G|1<*-}yIx{rbAn bh4bfs?DbiHzxpQw0|SGntDnm{r-UW|CiJfH delta 423 zcmX@ce4KfLR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(pS zD9@R<#DRfs?&aq_Zbu~X)-Zv5@-Yj}Bz?8!Va zow+(2mQ8t+_IlGI4?WXp&6$BpKJRv3)j85MvGwKV3m#`@)LS0j|NCFnz4xEK9kQSQ zO*|tf*^@!Zz5T_{hQOFEfrZgcmDM}#tO?0YwM(}rg!t=)ZE+m|4+7l zc!y16seyEjk>p zEfnMV^GQqFWak5&i;cUl9{Bok38Ty6i*LB<{!eeXS)`Ztf2qhNy`N8<**!ifcqHXB ie0wnW?H-|DoG&wLKV13Qe}I93fx*+&&t;ucLK6TRYQ$;) diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_lightning.png b/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_lightning.png index e39320073e39b6b1a41c8c8d47ce51baec271bc6..3130ba90f496e00ff53d0deea582950941224532 100644 GIT binary patch delta 418 zcmaFLe2961R=orR9|O;--)yoB3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_Hg-{Y z5syV_9t;c&vY8S|xv6<23?SfKl$uzQnxasiS(2gP?&%wlqL<3fz`&^H>Eak- zaeC?G-Cld#SLV&QDf}W^TS$QYx9Lm! zJC9=T2H3ALp5tDcUK}np&G-3EcmJ6O^ruOjTIlydDZ?bI=j_^|oZU03Z#$(lFfLh@ zX)*2W?y!fx^?@33@f_Q)p36J9F(+-+W{YWOUxa%wy%hC%x$BR{RLOGd!ZW#Blh;jP z>(|i{k~o|3|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(pS zWR~zT|2+c(W09weV~EA+rIWoiS^_27<{w_Na^}CIXSlSlOL20ZT&g*DQ-IH8ohMQo zH_cYljy!$OOLNVC9o>kVAI_gTW_#U@*Zvfb^Owku7Rk2F^}nrb-+!-tZma+2^NRfr z{~8q;cXZ5~G?i0=r}e14fr@f&tWBKtj{Up-?R78^5&L~f&0K%}+|S9AZk99HbF(-n z{*3tD^(pdx zm+HP&#-3GKneX2@&J(HkJKTKv!-lQ9{%mH9%I^79B{@G_}bKu1!c1~O;o;m?p?dew#;R%jGOGEpJivv(fJx$uw~P! zBQG{|9Zhmsd~piX`~L@A9i}ZW&wT$bF|%;q#&djMU+e7P@QCrzy1QX^#*n2KEw9Usv`=tg?c- zYC;@rehdr@vY8S|xv6<23?SfKl$uzQnxasiS(2gP?&%wlqL<3fz`*F~>Eak- zaeC?G^IlAWBFE~5g&t<~rTQt(+S@QuWNp-r!u$2Rd|xjR&%DUIh3l4!tL`H4j6iKi zHY4v-Qd7SKt?)^jQ4$>y+*r?Mefsp@cR%NTt`+|mdCFi>h?Z*fO+&qJ#yjS4h)oj< z(2EKgsuZr9B_76;B;*Sr^6vGQ)Q#l&E@IZ3ZqdAaV{ zSiHsU?PA|`)9Ro8%qcfGXufaVF2j}tvn^drHdFjGBBwnn@=D-v)RAzJ_YKZ8dGooE zKjd`WN?)~wg*}Q#`fKZa4{rL^FTkt*BqpQv%U8Ko>(?@foNd}H<8qjDWv_dM&b;8Y z&#Uhhmu}`c@crt}`8U*l$WG}?o!dKICwqZ+86VSAwZ@{!5e2X8&TomIyUxEVM)78&qol`;+ E0QF11fdBvi delta 438 zcmaFLe2sa6R{ej5Ck(bnmw3!$U|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_v+!_9 zvM>sK{mQ_=nC$7|7-DgH>EylMO@Siq^R=6%Ub~>}(#U#|y-B1cZ)+@s=t{N zdh?8au!g+$^VUoS#uqcISWan#{??7kzE{3)n-D`qtsYlo!Iw3WU;LsqLVpUeWn@cE zy75EB-vOib;{`ppm2lu~b|UtoSdRgkI9{8Vrd!^)6X>CP&j)btISEDh5> wT{^Jg#>sZ!1zr=qs>CjRIMKPbWgnC9n}#jXQ$86nFfcH9y85}Sb4q9e03#K~N&o-= diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_sorcery.png b/src/main/resources/assets/ebwizardry/textures/items/wand_advanced_sorcery.png index 135cf8401f7d153fd138d50013805ac09407f2df..d4b862c435e81a282cb9f650865e0304161f52a6 100644 GIT binary patch delta 434 zcmcb@e2IC2R=p>K8H4D<*?;;N7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=tg-?^ zjPK+=>oG7e#(TOrhFF|lI(fghQ=!Pw^X5$|+J6N71&dxZ?orKtQM){&iY4)I^sTJT zOBdeUxL-ko?r$wwb8Hr>>z zD?PB&>8XR@QwPC^nLC+ppW7DAE-2`FUCG3Xor_I1C{%RSs;I-e{+Tvt7q{|h-#f=} q`~Hg84!ipJ9*9l)+PnLe@aIcCES-zayk%fuVDNPHb6Mw<&;$T9A-^dA delta 436 zcmcb_e1&;}R{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(pS zVsTOUX&wUuW1^>vV~EA+rIYK3z1TA?U9dX*pUb~D$KGnXZrt|zLebM* zGIyph>%Ge>4m#m_vU5((X~)2Srn+wr>^6xz+c^KQQtQo%`aFOC`R~8~{JXFA;e7YM ztWkGni!`JtwMKGE^tLX^y>WQ!)!wz2QXc>O#Cq@HoYL+|$)Ao1GPqejcwR00{YS5} zT-y5^@jHW_xt{4RX~*f3F*%xd*X8vmG&#RIzWpk!>C0&V{Tqf`NIly-1Q|Vb!Qug=k zcCQZFaD3IXEbI2#PhS>K{CW9|oAtdhUX`ixH2#>a29w(7Bet#3xhBt!>lhd-JB7%$o1 zAjR5lb5JuTU0(6Kx!(7A6YiS_)cf+?ta5hK4FSpI zg4=9Il^Bm0PmQ~~W?TJ|g)BXWKfJb!e5)?JSMjz{A*;I7%!A!KF=~#?@`>*j#9M~0 zeEe?h-_@IJR=n888^y`m)>JR>VwKabRTt(wI{NN2_qAEak-aeC?GjowU!BFFc?4|-9udsoh?gDq_0&65?F+m&~;?D)21zryhq zD;FAezmU)1jfx8DFj%-^!GRnD&Vv?5RQEasb)C4b;F(ZXAGi18!RNL6{@nY`_+RH2 z_m-X8&dDo0dEZ@dgK_JEGsaOoisxlm?kfi^R~LA5;PNf4KhE7B^zJMQvT_ersOH?U zp7Xj3=XHLzZQm|gSosNxPGdh%m!R{D>jA6F-1Cc8Y0cTHQ@!W2#%$LH3AcAlm5cqZ zIF~RyC~!EGx9Q5e=e<_-k$H}xp*xHuzjZ3{wJtaNvX@1>B5cwGgR|?5HW{h=2$%P| zU0-6aR&Z@o?&ti1;|#hQo5iM7mP8!+7A@)h(L%GU=^mR)iQlPU4tA9#`KvnC=G?IO z+;Q&AnRn@FK5Z2>N6vOFI&g}QfiISw?_T4nQ*(jw^F>!MWMHnz2=vdFO**`{He>S#aV1B Q0|Nttr>mdKI;Vst0C7C7Z2$lO delta 427 zcmdnRe42TJR(%nJ1H+Qr1&hV!57v&`q2E-hP9< zL-*pCxt^1{g`X~(5_98fBD;5zYFR+mwEMq>p1H3%o*0=`e`BBe`Hw5V|NdH6HIMz@ z;$>n?$sjeLcX#w z)a=+{=^H$M-?P8R&c5+-S~ZHe@)#p@3UdrkFEouxLfeM&~|TAQ?@9dTSScWy2* zu3WmRgHNH^*2?>1&dT}q=bnfjn9sH>GidvMeaH3Fec!HA`4tzX`mtl(=G5E!4~3|H znwDGq=g*()OY*`MazUz};vX3`7o5<4I3b=%H}2WJbCR=X2DT*z%ym36X~+KlgK~4< zHp@Joe3@^ZNm6G=$NRXJdvz~!zIG-`ge+p-q04P{Z{g3B-l(@7f3Ei#?+#Vj*u8wt lZdLKQ`ekK8eR6Mv9~^64qtdhUX`ixH2#>a29w(7Bet#3xhBt!>l#Fk@or8PAgeoie_;vT4>F|%UA9dRkCU!_h06(>@2*x zx{lQ*EO);}NkwI?Sg?|VyJ^iE=1q$hg*e3<8L2c~7PwK*o^`$IcyYzK&(-%2bN{!w z6~Ey4>SUXPVS()0JNB8GrRCq;%pd5_EqXA+WBPR`KMl>mlcnFTFPp30(N+>UEB?{f zpN*4tsnu`tdA7D;_q-S7+{P7$*^XXzo;Q2;mVYOAY-ZdT!Q-jE!+)uTx11yM8C4^u zj9JbRRXq0HyI&UlwWp!l%{`>E{pN#)?zKXw4 zu+V0hc-eT(*@n37Y6nkBx=pvssH{myKA#h_fM>V$q#C*JiF^H+Or|q9#6HQqyD#zG z*<(>(yjEUG5;tOMZWMnYxpdX>BndV%W3}M9dyg2aF}UBX7JAtf#OuN?(0}^muXnji z=X;2U+|`w6bF4PeaxSa4ww_kQ`YUc))rT#YJuRlM&Rq7&vc1^y(b1%{OYGG)%-q=Z zIlo|P!}YbD*VmqO=$||Fy7e<>#ig&UdO3gm*|fU%aiQf+`}3OwV)7oHsjU+fEVSt~ zFjGAIm+xZf+^TmBVf*E`-CJnA)pPdKNlul=UwSy-TN->W?F3tx_uR>cm)VJZ;bu~- WdnBY_pTxkxz~JfX=d#Wzp$P!FN4*aK diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_healing.png b/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_healing.png index 5633f1532a25814c0f5665f1248fa439cc9af975..7de1b623daa699e84f46f4b856d57b74b7c35ffb 100644 GIT binary patch delta 427 zcmdnZe42TJR{ea2`3&>C-+CD^FfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#SY-t) zCA*oX2{JG+MtHh7hFF|lI@#9yaDYhL{gwc$P#ux2DVLUdvv)Hd{hC(9`Im9#E&GSB z7Bo*@uz({emQ}Pwz_7Gn0-JX0v|o)Jv$j2OmtHD=WySG&M;^hb$**SWJ^wW4bHRDr z1NP0oxvv=cdw%F%VV~Dj9w(!7&nf=Y!e5&%3ig~9+!V$C<)X>O9k(6hW`E8Tn65k} zD*izAUZ&M$yc|q=n@$T<1+IUZ*61d@Z=d0ocl?GkbqeQk860Df&KnHrQO`*G(>K*)3&Z zoh>Q+`?!CsueB75#o>2 gk#BMN(!V&%9Xd02zx*o1z`(%Z>FVdQ&MBb@0DU2=`~Uy| delta 411 zcmX@jyqkG~R{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(oL zDx!YDAdP{6(ZkclF~s8Z(#iY1nHVM7=1=Z6*?yXNc@!5@bjv%Atb!d+iwajP`@<}g z#kuIeVtYo0PR7}Vs!P`{ROB#p+~lb25_M+vlF2HMvL~q28w9_Wwy(JV{ONDT|2j|g z7ey&5GOU_?$hhZ%S?NkqAt8=lA&xN3@Tg|#8_V?E*-x`Ltq#yX+%3*f`r=Rd?*|Uw z{`Ksf+O}xgwqp|`XLRjnT(9BvJwoSnlbhUC--){07$R=}k;v)TwvyRHWliCXm1V!S zi-y0#B%etYie(E#~hoFei{Roo2o TTjnz`Ffe$!`njxgN@xNAAjGuK diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_ice.png b/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_ice.png index e596af7ff745073403371827d2d1f8ff57518b5e..9daebb7953734a5e1f56163b858fed57098e793a 100644 GIT binary patch delta 403 zcmdnXyqS4|R=orR9|O;--)yoB3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_Hg-`t zQMG;P^BEWz9XwqeLo7}&oow&zR4CFmU;3KR5?-sP1%(AWU+3;zyk8;1Fh*+e(f5L1 zM5DN5lrAh)Xj+ytfn{%q3YY7T_1Y?3)128{=Pp~aV#oD*tH+Jc=S=^+kNscdt#}1N z!R7y5o;~U4EIg2+q_%zULYZglG(uM0c*?b}@WIxzu|;dM&%N7iaaOJOpu^|h#S1Ry z2fw;fF}G?-yjD_ver522DNHSM&oJ(t#(co%@1@&ovnt zk=}Qk&$Jynv-fU~g1=dP-GN<+h4Xwb?_QlfulPe{@!C26McL}kIUdnpBt1?0kFTSV zpm0M%!Yr@FXPuHly_W{v*w(wcX@Tg}y=C0a{Jjb189Ac@1qCCmBBwV9PJ4P|&x~cA znX}fd(U)t#tf#Xqe8v^Fc$;rQb`8@HPB`Qy*U-Mn_*(lu=K04aUU(aKcq0!30|SGn LtDnm{r-UW|8kMqF delta 413 zcmdnYyq9@`R{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(oL zF82F{@d*Y7MlVkn#}JFtODEfUJ28s1&DUm|8IW){W92lac8->JOV=NKsQ2uV{0H?b z61tc8PbhLN(w&v7;S?(^b&4%mg?ov^8cq8R>qG>XJ5D)J|EB7-EWgeBY76-f{+jiT zN*`x1EGdeVDLc@x&Pzp3czyN6j|*8>@w?6`d$9AYty{Y3C)LT;KUrSfU9j}@^y)JQ zrTTZPFZsqVnx0rIF|%>y2k8%8i%R;A8t|-0_jtM~#J`*2im>}$Uc&{e86JJFwD6dA z>+9`BD0Yka6EAe%%3C}AFjw5i3Xc%2*ux^LpSUb_+IR8At(X0>U#=Rz zeRBT+UvtAcFNg5dqBBRo{T5z*amAucslAdc&XYo>fB0=PCw6+|?Hij4pB5P7N`61m|%Mz#ZJ>Y45@PpZn%kY=1`HZ!);_ItU<;^SlIkTu@dE`!u?O(+f#&>np WA3T`7ua1F%fx*+&&t;ucLK6U0?6{Hu diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_lightning.png b/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_lightning.png index 1626715be95669854e90fcc0b56343d914c7e488..4fda22fdfe623e3a110ec30758948c143b4cc79b 100644 GIT binary patch delta 400 zcmX@eyn%UwR=pI1EQ7+IW|i#>3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_R#`z& z<S|xv6<23?SfKl$uzQnxasiS(2gP?&%wlqL<3fz`!Wt>Eak- zaXL9+fq=oJ)gQ0y^!~s8-VWbcjNg`h`d^)vn^;l*`=RaO?&tXuWp8dBJmA#z?9sBF zJm&B3rC0p;s(&~>jIV9`okK^Y4;(mfV8j0#nQi6&cS`)2Dk7O@S8--Tb(XcVC)=Ki zPaO~MJ(uU%|1K{1M@fn3$Ht6&t^fCZ;@cAMuFEdixV!(Ju~2G5-_)!1Vv34w=co4_ zGF4<&bDG5(aS@d45Q_HUZ=pg!sA zA>m2)7qPIhEi2b3^eM>`xiYQ&_K$zBoF^GcFeLhxmOTmjA`c3322WQ%mvv4FO#p6z Bv4sEt delta 417 zcmdnMe2{s9R{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(oL zrg!S&E^!71Mn6v%#}JFtODEfUI~9r?tFI3}6?14;0HZ!E^&sN~b zHFdkM*#3h13u9E&rL7AU4GqMD1)R8>Pp$UY7jihWL&cyz_;nBayyxEw;vURj`cLUo zn=;dfkX?t3Ixf7wctpDIL|H=j_O7YRB46G=@c!bGjeAaB+0uQ-x$#;6bHWA|2Jd1$ zp`9#OlcwEXy(H-8-og~tXU@70SeIHIPm*BU78S*noHr|twc+7$o|{RrEA19BcbtFw z#G>y0yY%kTtHs=Hi3atvyiPXVJvVddC9zt4Z~c#Lmp#vz>^>BtUv$P~XQs(6wZDdq zYp3N+t`{zs_+dNihwZF0ezz=ZbTgkdbLaEoQ2Ev(yEJ$YYr;R*>~9GUyGo3+pp_=-6!|m2xB;Peu}gE{JB!6yBqDk aFnhB!eCL>WZUF-W1B0ilpUXO@geCxG+`$R} diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_necromancy.png b/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_necromancy.png index 83f0ded1d16c7b94f3203d23513da3910c914ca5..361060692e7a61f719368d2045fb847059cf8705 100644 GIT binary patch delta 478 zcmdnZ{EvBpR(&6XKEv)A=J!Gw7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=tg?cp zEUv}(KQk~e$YzE_lsM<-=BDPAFo1w_QEFmIYKlU6W=V#EyQgnJie4%^0|R4{r;B5V z#p$KNzTQlMBDVg_8!v5~bJSpgpPB1!j#Hs|G27~2>3=c5wdIxk7vZK`EfQN+yUOqO zSi~`>XwDy%E6WX*`AQW>Te>9rm4x*lw|zga`h4X9`-6AHRxNrnr(fT1<#OW~**k|n zi*Hi7QL-+x;!J_WO>vtko8F16Sj6MGAv66qi|FFsq;-91s~eo_=lT9gz2~;KeaGhh!({%hseHuv|2 zxk|qNEOa#amP@ex?H2icRYx+(ppYDy@ z5ANRGkfYOR@%+kdR#l}1I|~}_w4FZLxNj#zzZv(BCeX6> f&+V=9Wxa>gLzYZ(tNt0V0~8aUu6{1-oD!MIq delta 411 zcmeyzyqkG~R{ej5Ck(bnmw3!$U|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_v+!_9 zD%c7OsxUAxdU(1xhFF|lI@!?MDN&?tzQ2gc!iTdiOmYk{*^~UC)>q@^n471%zicykOWQamB)>{@s_& zt-D_BW<6{m;k7j7)Z_YxX9C|j+&_JhKkk}|(6p<;%YMxio_4f$@kQg8{hTpZeUAT; zzGJE&^U2%d$@Gtb{MGMWuRSVU`r4|Qx5MS>9sBc10gsh(H|^V+{rHS>prGK#eO(6I z6^t3zzu4txZ{1)l)jC1(ZHoMQ+ T|1g??fq}u()z4*}Q$iB}X(O{w diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_sorcery.png b/src/main/resources/assets/ebwizardry/textures/items/wand_apprentice_sorcery.png index 9e5f37e39d8c76b81404383fc79eafd0d1a6c3c3..9a85fa38ea827cd2a4aaf4a80f1358e5f7acd003 100644 GIT binary patch delta 425 zcmdnVe3E&BR=p>K8H4D<*?;;N7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=tg-@} zQfGZXMldiihIzU;hFF|lI{CaeQ=!1o`?J~=gq0R2sEQrhEw@i@kyz7T=5O*Z1!8x( zw!hF{;TI?>-10aAMFh%ScGOe{JEh}^qOnhvoMQe5;B}EDHn|6T`XR>YXu+sb7<3N zWB!v0N{e)*790@CNUG_ONZwG)&ahpFS(PF4YJ28l`2*S}d(UN7-MXn{e#&Sfq}u()z4*}Q$iB}mqD_6 delta 409 zcmX@fypwr?R{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(oL z#@{w$l_vuOqnoFTV~EA+rIYu2GZji4v%h~>p}2E(bH)nQg$s{9R9WHpXqtD&Z}vH} zvU}S8G0QHp%qYmoJh@=yBEvWIt3Jxf~F-pAbYpI27YAF%iS z%i1Nc$K{|l_vm%*jCS6c-TDQ>Jb_`?r%a0b&cu6z*KXkx9{@FFe*%(aPHc@*v<8k zYgY9!O-nVLaN6_2`}FYo>P)Bm-mh8CzqZo6o}0bQ%5r(k^zNv&xtHXHzf}HQ_Bp?x zyFu3M2%of(-J|rskLN9Qahkczvz#f={acTulH%Ov%SNYHf0R3C^Qxo6V}a74FKc}I zSdW1A;Vr~m$+kt@BT8sts5UF?b3e#OLO{s&EsaT=1zV*&+ZHN+9aV`kv~NZ SZx|RD7(8A5T-G@yGywoMv9<>Q diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic.png b/src/main/resources/assets/ebwizardry/textures/items/wand_basic.png index 3b21bdff7cac1534c710afbd052b1f43739b8be2..f4df48d66a18bb2cf2073d0a847f8ae053b69926 100644 GIT binary patch delta 385 zcmbQryoh;%R=q!iJ40L%jFVUUwYabKv*q6ZsN3_{_QCvwdPQDq z!A$Awg1PBWmdUUC&b)(NuC1_G?V=IyuRbLy_4tY%l}DeRY^`ECZSvxT-O&@>hE>0g zMCdZ0G_$1g;-Fcp@_vRAKlUZ$eZ!jQzj_aFD6bJ8CQ`@*h=|8`Mi;o9iF z+xm6JjfYF_a|>+?P^eO#?k$xke_wq`=97>)&nG@t3n=_&+Sv8khw-$@2_s&u=_V#` z1g=KSEj+hSML{(q)!6A-%-XA0ug7==aLv^cz3^?C-<)EdBKC$oQ!+2+iyizE%HU~L q{$N$?;wc9b7*0vO{Z=IYi+PpU1ZU4M#smfi1_n=8KbLh*2~7a0)utu@ delta 372 zcmZ3)Je7HZR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&m_R3 zAeAyxMUsJmQOVQAF~s6@a>4=ugGq~5Zr}Iwe>|I8oAmZ~#v3Lqx_H^=%l_Hva?QOv z&$bsd?s{ww)%02e};yW>Yp|JKl5K=N6$QiIh7we z7UmyiY>Tb_W+)`erl+UJvu3{DKk;zBl!|Zf?3kG!*SEP}?=!wr@nz};MuW3_ZB9I& zx7#;%->>*Gbz*|f0h80-1x7MEK8UU3lr#`bHr6|95$n)%wgN;%@P056{`)>t?N@wU z)8xc|-_&_3Mep|HE?c&Y$3;>=;J}CZv9C;-&pg}HmG@|Jr31s^dX5MG@{5)$hR3=9lvT7Ue$nE9wE*@1!i@N9FQ|A|cQeG{fR aGw!OKPl1B0ilpUXO@geCy@(4Nfz diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_earth.png b/src/main/resources/assets/ebwizardry/textures/items/wand_basic_earth.png index 83c3e104cda6cc6798c7aa0257efa19e0b55aed6..02caa3b4200f43e8f8bf2763d5f01f08b7e67c6a 100644 GIT binary patch delta 373 zcmbQjJdJsRR=q!iJ40ru;x|CeKJxx;5qL2A5TlqibzYk{qKJT1$b=pmJtG>fN+ZCgwyF>0IT={<6HhYmH zPr9+DpWY(DFR`4H^PUubxWVZ&sebMOm7ng-PI|hnF;Saliinyoh|r4m((K{c;+7Wf z^yo>_%A9@AqLiI)PCBprdi6Gqr8B1RO}J7Oap#S0;?`#k_deWxTf8~@ij=^`p1A-3 delta 371 zcmbQnJcW6JR(%nJ1H+Qr1&}eUGiIC zgGkAbH_I$Cf1Ju-J^wkPV*lhLY4iFw_!n6`dii#$g3KBI83%svUVUZu#VztJ%&ZH1 z60D~`e6`KKwJz+?5gYEDd6tcxKhJaeoY~JdCC1xpoobn$^IplomDi>`wvb@W=v`vI z%jeA0th0Z-wz?ggIyFh~=DGBvg)+}>G6qHU%YW}J4XGBC==sjKzW0e&_KU9*JP&{G d{CaR7BdH=O_D8I;0utg6 zRM&lFU|@9dba4!^IK6bTwKub)Nb7kImCkI{NDi^t$CO%okLFB0lr%dx<$zNCL9Nm? zx|e^wV)9H*T^^m0C>Y?md37|4yx_Hlej9^sLFGeRBY5fsHx(}0F7>SFTzQ+d_>c6B z`#a)Z=_Pfl*xnRd)+X&9Ew}16pH*Guk_%TtUzOkf^7Gy0&rc1{@tHjpp0Ueo>D<~c z@v|#lS5%bnfBbOKHD%I^uX|(9=;<9;zw-c3MA_q*a|aA~4wM(v*LG{)W?ba(@=+gy zftvEXZ?aKwvz#wx@zlS|j_dcF=o`Cqt7z|~Sx$%dUj7=&@WZmz;8W*aKGjWyk3x*> z!enMSwAoxba3$2JbZXE^i>@%{oi&Yx=M+;FSTwBeA2GL_u79GwSkb{zbIQqvOS7Ej z6#sE!Z|D#>_;A@AhT>#~s)M`tuDWB!#keI(;>?bqnK{n;8N7M=UL0G^_hk9c6ijv&3FDq|_<`=+Ur zY&hrLX!QKFUUr5`(*KMHmfOC`M2DYpowe4kbid+~DH4(zt@C2#CaGQj+xByocB@~= zrK?(1wQH9woszPYIl@b|{rF`6Z@ml{7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=tg-@D zjGLWfTNoG^4Lw~PLo7}&4Yu|^93b*9FIs-%G8pPr2=kWC%QO?ztrYialhJmdG5ncCEj+83s-NcuV{GxUA?C4 zR>Do4bveR2GZ)>D&uOkQ6cf8HU_0;djT}Qw#&ebemLJ~7Y{^Sr@ILANi^zAvmd|H& z%G`>GZ_51H{IBU0!YLf>tg# zu%#wsmFcofsU<8e3};2-Cs>8AGW}^P&NM~A|EW<%sjC01Wr>rl8J@IwaBbhmQ)bJ* tVD_1}H;b-oun4d$*m5z$r+lG(dfkMlI-!XZ85kHCJYD@<);T3K0RRwvrHudp delta 361 zcmZ3&+{HXWtNuU3e}?}H_AZ~yz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns~;XW`*A z;of|h=Mn=0qqwJwV~EA+rIQW44+n^}?w{fjy~~s7;K6lH>IcOItSnMaeq($6ME=F4 zqf7rU+`YJI-QA;S7tR*ZVJX?5q#AvzsgXzaiB*dTdv^SndY^vo`=oA?bkC{?EhhsEx^KP{nEvcuiWz8k=H*@>ulb(&xz4|uNA+4x9OKy z(aBGIKOAFIJGtM?z%%LJMTIZ1oVDSz;^w~IJtM9@L362r(FLiM?^H!j?)`V*&+P2p zCs`i5du863yJ#NWR>Bbd`p<`|*9oqs3a8)OR-4>*TbpR--gPh|B+q$2L)H57`<_-G Slo%Ko7(8A5T-G@yGywn}n47Nv diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_ice.png b/src/main/resources/assets/ebwizardry/textures/items/wand_basic_ice.png index 9ed786eb38adae363d66e7297d0410977a2383b6..3ed19add894f14f0982ef5a4ff49b7818ffdec0a 100644 GIT binary patch delta 370 zcmeBWp3FQ!tKO5rj6w9_>_2@B3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_R#|>| zqt8+t77PrG3Z5>GAr_~XPPX+v93as;e@e%+yrcydH?Ce)oM~l|aHj(w zDOrT5FYNGc&s%!wh6b0AqRG;&^3Gd#aIAOsDBSQZ?0iXmP~9(F;-+=`673*G}bI_pNw2i@Y?TUpO0tctugU< z=w#=;*f`SR{?v<}actT8xeF%$$!4DWM4s2?xX}5HOD3ETTKipNs&-rM?F>nc)|_{J z9+SPFcKtIC=klB~IZ5#5{nMSfx7T>F8%*`$JHOmo;-Hv;|2x^OU$zBmO7u@GxsbDN b`@;ARmc9+*oA&NsQrzB` z=Ncp1!pG-#uJO{rg-%PmSrrA3Oq+C;Yn$rgnDz;e65e*#&wE+)(E9nl<9k2&OV&5e zn!AqSOY?*nu?xjMnPt0@a-*h{uR3!~`BUVB$(yD5)+je=Jd3nr{K6Y#s}t8*Zr`!) zon*`$=_s~!uMgFD*mKPMsmvg@eR|dW7rXSNKQEjk_x|Fy#i{mljvR|>7Fjoi>yGU{ z{e|yOy;ND>6z;cR@}JkKELJD&r7HR~=OueB4O#Hk{fe~i;cdBFc&0dQ((n*h=R>?okl{H Woqy33HXQ~A1_n=8KbLh*2~7aJuAw~u diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_lightning.png b/src/main/resources/assets/ebwizardry/textures/items/wand_basic_lightning.png index 8d6a61183f8ae5f7a2ef4e93927fff2fed434f5e..7fae895e27b5df0a5b8f7d5eab2d08b371a7009b 100644 GIT binary patch delta 330 zcmbQh{F-TkRy_m5e+EZ4hJRBS7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=Y~q{} z(w8b9Ol4qT_~Gf|7-DfcIbnf-!KBq6{~bR5Uq5c=xdSd;YW~I-|MSb){;Yp?XzBmy z>+hx9*paHu%&j>qTP-(vN7-w>!;ky#Oa9xq!En!WA(eX!^=xcxZL#eAhI@V=Kd7)! z<9NZtcfxJFdwF|QBtJZP$lSJDexK2ty>&Am-fjGOgniNSnJ?|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(p0 zD{We`bsYl(qpYWkV~EA+rIQW4nGz+A*Qd92db_YMo8aud)$)#S6R)1T!22sY9KGl2 z*zH@KTrf3fxDo_h47XRp)5hbc#nA7fI8WM^<^cl~wP zE`Q$X$6pUz*wq}h_Sm!EYkRhx)_HEnFmrl!jDClC$AihA_~yQ=2rb`xprf{xL+|P4 zn7ez{EqL$sQe}Pf^|A#SlmBG1Tb;C*ve>5Cm+PfDf9Yk}%Q;(lPj9+l6u@;-WSPs! zvtiNyXKS~%obp`SB=he1kxe>}E-_y6YHe>n9ow^8SApaCH@2$VD@4wud4#<9Iw|*s aczJmJgqxz@w=*y>FnGH9xvXtuUxr$mus_3K&G@-DSzTrdouZhiOQ*Szo1KRBfp`CqtZ zUQm!BEM=0RRbbk}^*`axrq>Uu3k6ENtau+P^6n?L+&_%PGzgrC5#d2{C9{V1qkDX+KTTkq;~t(F%AmXw{XnDc4p z-=rjWh81FWw(M3}ZOJy{cG)-OwtebfqdK4EK1y4B^H@rhz^{2BecX5Wr=44}>sRXI zkX26?t*HL+{^Wk4H(iSyJhlw`yH06 zi!(iljSoD-ylb0gwe@qE+&4n|j>WXua#cP&>pFLPzkib_&xG~N4a;{H7)?P2j`zS SrZO-vFnGH9xvX_2@B3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_R#^d7 z%fs`}t1&Pz8hg4phFF|l8f@!*I6%afQ#ZbBmmiMA6nq^w%wnSaR~+fi+M_}<5THB6T;oGh~HSd`8p zpDWU)<)<%o;*4NtY?`grkI{Asm7M`;3SN8W+c>E`uN%DCo)3Sw=Ghc-0 zJq;*l3RyerkVNy827v{wPX$&MUtM)_{Z4@eEK;Fb3$}*#N+i#C%Eut7IO);7xTZ^y vECTAqzjb$Ji!iX5nk=A8FV^$gLk`(ut2t~O*~U|{fc^>bP0l+XkKmqDj; delta 356 zcmZ3++{!#btNuU3e}?}H_AZ~yz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns~;XW`*A zor0_eUy8UFz5&5Hv$8VRq7XFGZuXW=8K5=3BMq zZ&})yt*o^=h8ak$iT@e(67^*6`&_ z1|98Fx*8hapDL_4=lQ$V% zh;p7~(9!O*NTlI=xA|`OD^Z)Lsuf+iv-r03`e*!$m)^>laQJK1%+t4ja{bafu2w0# zXIrE1r}ex!lj==4YQkfg?oX}S>a*Q^*i$Gv%abbs&dv%=EglmT%M>{d<}DJuInj=1;*Nv$w+jNN1g!t6_x$n0pBD1^ zAI>M$E6&`>c5w^$&d*jda~+EI_q?9bcfD#)_X16$t!}HrPUg%wF`p^C{nrDQSxT2@ z<{9`-eEB4e|9)qAz_lZ@kN5xnAv@==OMcv&q%*1?RCOO{PCaz#so-W+0ls#|#04>x zE~dH-hYS~qa&K0BAjDSR`X_Epp6KoBos$x_%?Vc%xiuqp*@E-Vb0f0P{+hUS&w>u? zh8x~e=RT&1-}5@~YvObF>WQ@#$D&GZ|1*CslQPw%yL-Wc^UkYQB~7qqu&~^&c2w_&%8j=i v4Q-`|RTI}sTe4@FZnbP0l+XkK=`_P# delta 485 zcmcc0+{!XRtDc*In}J(YWDh$70|RG)M`SSr1Gg{;GcwGYBf-GHz+U3%>&pI+k(HN8 zG52d!7Xt(1Bu^K|5R21GC;NJYBucc-Kc90Tkn@?AsgKiw$MJb75^2E?l6ZD<@9f@I zq?j@DU677wa1^K2+9tD|xs#K28i*{rG{LbY@WKi+&6aw_s0GanD`PsQWf+H7mCM(h zx72_B^gw;z$4@UKzpK8p`&IeJ&*sI|xO=SA?CMnSbMKjuCtflu?D~B3eP<`=O&8zvDOs{7!Z$tQpV@3{XX{6& z`gTZVNd}i1EPF1y!b)QDa_u9J3;%rn%q1@J;aB;Kmc_D#p+QzTn+~0wwsiT!4OxHw zC4Wz0x+!S>o2}luKR;)~l#_ohzdU37%glKbbK{&3nvIJOXq{Rmaf_=UKQ7^b%i=&A zP78(mcMP^?EE0d$oMB~%*6yaqGF&yAWNJ6c sy<&S2lUpJaA^($k@An%Q7F#lydM;e(IAwDn0|Nttr>mdKI;Vst0C zA@3db7Z?~Ab3I)gLo8134f6G73KX%;_cp3z(8EmEeMdEE7d8$6`VV|RS0_&%@vob7w2 z|DvU)S6yq-dUSLP*_LR5SFpny;v4xs-b3 zqbU(x6AVsByo?b#8YFA-hlAmU%?V?3ehZ_|FQpg~^fN77uX8Q>%$QPs`^-vZw#%Dl z>J%pZb=Vle^X#x{ec?s+^SPo72EtN|3?km8Gp3!5u-~w~(sin*J=by7mYoa?e)}_T z{wVwS`F4^1{28CC3&JX#XK)+n{=R;1VI0@7boanBQ$9vz8f-p4!^u2beYtu~M#`y( z*xN~6i@unKzi8-PAntad`$Y|d`pxv?I_24`+B-Tl_Sv`wG^=>e5wUbV82^TWA(nkX zyGO8V)DB7I$VVn8%C^~7WF2H!xa-E7mu2gJFa>^|`1<7(gUJjG3=E#GelF{r5}E+< CLAf>n delta 445 zcmaFBe3yBGR(%nJ1H+Qr1&tkSG%<^<`46!(UbkbgLr$mus^Cx@FxY!=i!75l96CnR-(!xoP_7w{1&lD=z z$|g7ObbwK)lCFO}Lqo&)p5}~qyVs?xdi7tNhwb64Z5y^IY;rgGcs@>hdESRu%aeZV z8;)d(CI9+%@fzzDUb(Hj3UhT9)%^eVe9^x9U2R@nbK@LE-wAM>4C6Z)R(7N3#Jr~) zwr+Huq~bW+;l{bZ-HeR$C7+)Z3cJ4DbGPH6va~d_k4lI06Z%uwp@mhSD0vS08IsJ2(oZoDA#N+?#E6+P2```#=A`&*AbALsZa(`Of6j=NJ(#5p7x2~yvtFB~t_e@DvGLZMDg?90-V28>;whl?F zYIf0OX<`<7x)&{OFVovr{`=?29eebasY>&DDy=x}a)bZDy9Kuu(q6(5D`d044 zg&ge$uR6cKuNK7b%({JNOVp{)TXv^w&YTjWppe(|O<2abBy7IC=9;xDebhduGsp99 zl3_R&T*&uYUq}4<)aUhiSsfi6JyJ$%C%6PmcL@+TFJ(AuvVYR<6E@#lq>!rRNz*Di1HD-Vr(BpmKODK}d6(Iy541_n=8KbLh*2~7Z%4ZDf} delta 446 zcmcc2e2;m8R{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(pS zY1Os)7e507W45P@V~EA+rIUTNT@pna=1-SQJ<%Jsru-g2KuFiH=VwYp;mEKL=Tz$WI-t#&4?lJ%8 zdAd}?Zn2?Nw)OMglZlKTOO1c*IpAielCXO2LbIK@U6)M1dOf|W+WFPGym2DGXNu0I{ z!ta8YT#^*J-rq2P`sU>N{C){@6Gn-b{RSrcU*1ta=ly0q(`6IRl+8lx);)Xm^-ANZ zM`x>|HO+UdU)Z?QiE;0`7f-69P247bJ1<=GZckb9;kb<}{(af~s7;Og;f4|xrbl7X zA4PklXGy$O-1eSdqW|cWb+7NSh@Hr~l(xj)DaY3R{Fy!9H|h!q3a(r^QR9Spg7Tu* zR(W^5H-rkwu;^NH`FV>x@xPrBS+MsHV{YZ03q^aF{igSO%~zjvgMop8!PC{xWt~$( F69AGx%Zva3 diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_master_healing.png b/src/main/resources/assets/ebwizardry/textures/items/wand_master_healing.png index a67c6dcab3dec26cd0e5e495f339d807f566a01e..a98e8e5a8a353d29438537fa1edbb6ac7d8a45fa 100644 GIT binary patch delta 460 zcmcc1{DyggR(&r+H$&s`R~_993=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_R#`z_ zPMui!tqcr|m7Xq+Ar`0iPV(1iPLw%rfBuczY!S0ACu@s0pY&9xPrd$kuU65b2|>#0 zy^~#Krri14+wBq*GjXqPq_C=H+G%UkQ_tcnWjtp5E&Ny?GcVtE|NG}Z?e^bi{=acr z+VZE@|2{NRh?iTRYGb2%HlBO?GCd8E!d1~tB9T$S3SFm9o_6-JJKn64#OPFQw~ukw zF711+;aOdqiloi5o1Q#noBi8UDm!_`yg0+Bzj$`7F&R4fVT|TR(2hohiCtl@`N4hY40kJMZpuGRfMoYhUm3``RvM#kGxk zvP;!^X5HK0>lYfzX1e-Hdsk|)^FE(&^-Xv82v(&Ps!udq`Exrzb3kd?i6db~izOA_ zFOMv=6m;599qhSv5$9op4i}{q--37V{{&pt&`UqJ_Z0JouL|sHs{fQ-g_l>?w!GJ3 zoH09I?pmp>@_{v(?;jm|zTjpMjI6+>I2N R%fP_E;OXk;vd$@?2>>a^%zyv@ delta 445 zcmaFEe3yBGR{ej5Ck(bnmw3!$U|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_v+!`q zi2u0hkjKElnC0o>7-DgH?<8xF!vP{~`?X!Qx%k2|3JU^aYEldX7B(N2bqToSXkN-^ zVZFEqrUc7Ol8ks8P@RLt|z4|B`o)f4_gYpZ%Zn z?rhumYgaE!%gQ+Y*mM4ttxWxAE0`Yq-WTE=9i%L~0y+55$ zKJm&4raSQmgM}3CEm-KaG)RA4`2#k;^EPVF=7&Bi+A1#Dy6|ZE1J=*jm%mn{7AkyQJRt_(b{RrJ1wJ7i?X& z-+02#m3d~}{5m&pUyQVxt2Y0S?D}uO`Lt70S5#m|Z?%ayG&& zG4ku9BK=mb$p^Bt>+hU6uxUY3%fow_;#mVDNPHb6Mw<&;$TI CV8%26 diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_master_ice.png b/src/main/resources/assets/ebwizardry/textures/items/wand_master_ice.png index 529cf9328427410b1d9fe658c3e3371806fc326f..6960135eb5e7af67fd9a3ac4b7f31e912e16271c 100644 GIT binary patch delta 431 zcmeyte4crNR=orR9|O;--)yoB3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_Hg-`J zRn>EyUJMM3F`h1tAr_~XPTK3;lqhnv-k;-}qvA8}Uf#XDYPt_E39$0#PIGi&sZH<> z{wn{2UBofjnUggy@q<&dN1(Hal3tp#p5p|C8|;B%2kUb^H5b(^vX0&HeO~cS z*dhbtMN&SDI_ukCKNs5PG%>fl@pm%&_Ml_-0{z#O<`sC%ozJkK`WIu!UEwX)7>)?@ z1t%*`d$wG2>iZ7$`Z>R}GS;3Hi(YbalO+Go|H~F#oAvF$iW|bxm+n0LzsM=J<@}ka z-L><&DpTLANm27Rn*9IRpVh+lbHcK>?asMoUj8C)&58&eH>6U3V-^)-p}l_s#&`}<%}o;0|SGntDnm{r-UW|`Ube^ delta 472 zcmX@l{DXOdR{ej5Ck(bnmw3!$U|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=k_v+!{7 zG9A0yK9zxivDMSXF~s8Z(n-D@L5U)5^ZjFP#CUmVEoKtuRD6{6?vO-FV}4?zDvNGY zm)KVRRdbb1e<#f7z3FskhoJc3qXM@)6;=v-QNJkPG0m}lNm84%rS6g48go{kxmjy} z{VJ z)|@{|U4=HT*tE)YWxth7|BNkG$#y414n!uz-EVg;IC%P^_%V03lJf5>(m$R0`?8Ur z^YG2r!Vk>7R{nQbYx=o<=I=1+2JVgCSBxvug*RWz`4^yY;IsMrH^1Ajud~p1$nMpz ziS*0AH@Re?%73o=9q%{0tuStwEJhIP0k6ex}A*6{-oU5!|FTZ fLz3$8|4flvXUr(BoxsY#z`)??>gTe~DWM4f#i-d4 diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_master_lightning.png b/src/main/resources/assets/ebwizardry/textures/items/wand_master_lightning.png index e3f1dad04c645c9df2fc57c08cfc9d2599465b8f..be99025dedfe3a429a5fdeea6b436453bae1105a 100644 GIT binary patch delta 464 zcmZo*`M^9ut6qYEkAY{^Z#G#51_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmPd8@s5S zCg(+IkdSOMZ_m7G)Uj>t<+9qw4l~irZlyQ;Ee{%8 zlMFhomMm@c6xu8H^nzA=$@K60iY?|8%l#>Cd3E?@L!({liRrt$EcVzu{d!lmf3rBx zs)poFiw2e(w${_PU)5T=$W?3Rp|9dQS7*OYSzn~1ubX7#b5lOafz`q+&x7Ih#?uGC zi3xLSzo~zo_v6M*0jJQq1QQR%{Ge|>O}Bkl6!I>3#^|7!ZzRs?e6Qu(^>vpsI`_%l z$d8Tu{7Yt%{L4=NxGfObngJH_r>aB7T7gtO@zTTJbwO7Q&^RjA#XP#)~hTNw`I~lxY>CIMm ze-SoOJ-#7-bBhtP_fO2?XQ?7tm3j`eEYCLh~wtG#h|eF MboFyt=akR{0H4LaO8@`> delta 480 zcmeys+`uwHtNuU369(I(OFZT=FfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL-|S$Mbv zG^g?kon&BO?DceU46!)9bh2%BRH8)N`s0r$EL2zg!Yt%0n#7)29?Pefr?-p6XbFpH z>{A_Ct0|W@2K-_C%PH&E{*SS6l5*Ze4yQBhZBh1%)UVYaY2G(?%Ce(!-tXT&tzG|n z=l$mo8~;yP^XbLq+q`}E_{E<8NDO1F$&Y;y&AQG~k~Lx0vM%|wtE->LP2M-ZaQ*w- zfMTOn0U8~dvsT@b-?UYBL0##wwcnTz+)h}Rwwco*#oS?M+_PVQS}u3#UaI&j@RjKh z`}PC8O5bl!@>@RjvBjeL*Sl8ryY*DpGMJ?Yue!SG$07M$Hq|#>Q@*g_6Gd0pzq%AQ( zN9^R&qD{Z_RD!)~w^kT1=n5*^6kjy)WyrbxZ*`;n)FypBo2;6&v*CwZs~>-wB%kp2 ow&=Tm?hI{HH~l$n^`AwEapj)N5o`1r7#J8lUHx3vIVCg!077%vkpKVy diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_master_necromancy.png b/src/main/resources/assets/ebwizardry/textures/items/wand_master_necromancy.png index dd729046236c7fe00779b50da2ed880a9081b807..b7f06fd63e292d2920566d7f392d26e230857d47 100644 GIT binary patch delta 460 zcmdnb{DyggR(&6XKEv)A=J!Gw7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=tg?c} ztSNdPj~N&kWHUn|N}Tg^b5rw57(l?eC^fMpHASI3vm`^o-P1Q9MK6_|fq^l=)5S5w z;`GwV_TEl`636P*r7m^Xulw$l@Q=~3>4cKz2F3cOwtWrJ@(b3kzi{EogDaP|cO3ZF z>*uQ^>e5`cb~b0*Jq^z#PjfY5rED(Ej5}w^|NgVh`_G5$`!D^Sv2C%@iu3EezG&C! z@t^kTV>YX0Q@<`6dar)M`hV6>mrs&w-Xbe{IlW**wcFQy&I@Ox>uxxF^v~j17p4k) zWY5_1MMLEC8ufbaJKMB9UPibXMa0D}jLz?RXJEOBcmlh0?ql%w=g&RQZz?n=`i^j`?nak65lZXi1+=G3zWHREMvkPm zMy9n^rnS|ZHB*l?UT!|!_*mKW(0P$vUzeTPBF->lR(5dSm1EHzuDsihl*aCS7;2Pq z)Tn7ux9qbA87uv+&S}^lFWkG}g+~B`=;P_)7-DgH>7?`8E{P&-^Cz}GmJ%ypuHQE4Qp#c9lSyLnn~Y7XH%(aD zt8?|n5B@w)oj-!t#KL?ce7rP_HX6FrO_g8Y+96V2RJOeS+~F~YksKbG!yJyNzn3i@Y71EUb0n^O`Dp&q XrQ2ZUS1UaR1_lOCS3j3^P6K8H4D<*?;;N7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=tg-^a zEbaMb4;UC2<2+p)Lo8134f6G73KX#w4oq>G(9ENvt2Fh|R>_Lpc4qk(^*X;f3jA$X z2w&UPA?7O2-Ki0^gIk58No?y(1uktN7R|#4JM7Wq_juXnst@me?r7)! zqdwyt2SeP;My-$~JMJvpcAxoqw7$W%_Y?GG%~aSUIppuVEIqHJx3PWdgPT5GwXV#&T7_MK7Sk;BG>JEcS@RdxcKf5+h&%iTxZFd#Jl_Bi6ECwx5WlL zi&r}A{_DXL;dbk+b&B7%iYE^Pm6TSm*ywoak5u8ggO=q7d83(p(w}Jg{>)~|+q+gY nMUs=hVJBb4OE2$-^$Z<7Gu3jH_zf8t7#KWV{an^LB{Ts5b0V)c delta 456 zcmcb}{DOIcR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(nc zFSK~xb0r1_#!^og#}JFtODB74xCBZZuTS@2dur$s&LtVBvt;GWr1J1hJES*moG@j^ zR-v;^t*ol43vXzqIE!uC_(7xSWK-h9iyF>`%Eu<;*m3jJKQ#?&7W&+_AT9 z$KE!Puqlt{do8+ey(C6Y{2EJ}+U)1i6;iJvXU8pAzA-rReAB|tGpwGAXSO@uQvD=c zbWtu?q#<+GercY^p${xh37_wDUU72T{v{txxfiA%(%sP5^mW3o?gy;G%KduWBFi2! QFfcH9y85}Sb4q9e0HXHNfdBvi From fde5935adcf9b1b21c8b7c5f0f4bf8f5843d087d Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 19:11:59 +0100 Subject: [PATCH 39/68] Add visual first person blink effect --- .../client/WizardryClientEventHandler.java | 142 +++++++++++------- .../electroblob/wizardry/spell/Banish.java | 4 + .../electroblob/wizardry/spell/Blink.java | 3 + .../electroblob/wizardry/spell/PhaseStep.java | 3 + .../ebwizardry/textures/gui/blink_overlay.png | Bin 0 -> 25925 bytes 5 files changed, 97 insertions(+), 55 deletions(-) create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/blink_overlay.png diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java index ce053d6c..39cf3b92 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -44,6 +44,7 @@ import net.minecraftforge.client.event.RenderLivingEvent; import net.minecraftforge.client.event.RenderPlayerEvent; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; @@ -66,9 +67,29 @@ public final class WizardryClientEventHandler { private static final ResourceLocation sixthSenseTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/sixth_sense.png"); private static final ResourceLocation sixthSenseOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/sixth_sense_overlay.png"); private static final ResourceLocation frostOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/frost_overlay.png"); + private static final ResourceLocation blinkOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/blink_overlay.png"); private static final ResourceLocation pointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/pointer.png"); private static final ResourceLocation targetPointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/target_pointer.png"); + /** The remaining time for which the blink screen overlay effect will be displayed in first-person. Since this is + * only for the first-person player (the instance of which is itself stored in a static variable), this can simply + * be stored statically here, rather than needing to be in {@code WizardData}. */ + private static int blinkEffectTimer; + /** The number of ticks the blink effect lasts for. */ + private static final int BLINK_EFFECT_DURATION = 8; + + /** Starts the first person blink overlay effect. */ + public static void playBlinkEffect(){ + blinkEffectTimer = BLINK_EFFECT_DURATION; + } + + @SubscribeEvent + public static void onLivingUpdateEvent(LivingUpdateEvent event){ + if(event.getEntity() == Minecraft.getMinecraft().player){ + if(blinkEffectTimer > 0) blinkEffectTimer--; + } + } + @SubscribeEvent public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ @@ -129,6 +150,11 @@ public final class WizardryClientEventHandler { event.setNewfov(event.getFov() * 1.0F - maxUseSeconds * 0.15F); } + + if(blinkEffectTimer > 0){ + float f = ((float)Math.max(blinkEffectTimer - 2, 0))/BLINK_EFFECT_DURATION; + event.setNewfov(event.getFov() + f * f * 0.7f); + } } // Brute-force fix for crystals not showing up when a wizard is given a spell book in the trade GUI. @@ -354,66 +380,72 @@ public final class WizardryClientEventHandler { @SubscribeEvent public static void onRenderGameOverlayEvent(RenderGameOverlayEvent.Post event){ - if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET - && Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.sixth_sense)){ - - GlStateManager.pushMatrix(); - - GlStateManager.disableDepth(); - GlStateManager.depthMask(false); - OpenGlHelper.glBlendFunc(770, 771, 1, 0); - GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); - GlStateManager.disableAlpha(); - Minecraft.getMinecraft().renderEngine.bindTexture(sixthSenseOverlayTexture); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex(); - buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D) - .endVertex(); - buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex(); - buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex(); - tessellator.draw(); - - GlStateManager.depthMask(true); - GlStateManager.enableDepth(); - GlStateManager.enableAlpha(); - GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); - - GlStateManager.popMatrix(); + if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET){ + + if(Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.sixth_sense)){ + + OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + GlStateManager.color(1, 1, 1, 1); + GlStateManager.disableAlpha(); + + renderScreenOverlay(event, sixthSenseOverlayTexture); + + GlStateManager.enableAlpha(); + GlStateManager.color(1, 1, 1, 1); + } + + if(Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.frost)){ + + OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + GlStateManager.color(1, 1, 1, 1); + GlStateManager.disableAlpha(); + + renderScreenOverlay(event, frostOverlayTexture); + + GlStateManager.enableAlpha(); + GlStateManager.color(1, 1, 1, 1); + } + + if(blinkEffectTimer > 0){ + + float alpha = ((float)blinkEffectTimer)/BLINK_EFFECT_DURATION; + + OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ZERO); + GlStateManager.color(1, 1, 1, alpha); + GlStateManager.disableAlpha(); + + renderScreenOverlay(event, blinkOverlayTexture); + + GlStateManager.enableAlpha(); + GlStateManager.color(1, 1, 1, 1); + } } + } + + private static void renderScreenOverlay(RenderGameOverlayEvent.Post event, ResourceLocation texture){ + + GlStateManager.pushMatrix(); - if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET && Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.frost)){ + GlStateManager.disableDepth(); + GlStateManager.depthMask(false); + + Minecraft.getMinecraft().renderEngine.bindTexture(texture); - GlStateManager.pushMatrix(); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); - GlStateManager.disableDepth(); - GlStateManager.depthMask(false); - OpenGlHelper.glBlendFunc(770, 771, 1, 0); - GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); - GlStateManager.disableAlpha(); - Minecraft.getMinecraft().renderEngine.bindTexture(frostOverlayTexture); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex(); + buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D) + .endVertex(); + buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex(); + buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex(); + tessellator.draw(); + + GlStateManager.depthMask(true); + GlStateManager.enableDepth(); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex(); - buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D) - .endVertex(); - buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex(); - buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex(); - - tessellator.draw(); - GlStateManager.depthMask(true); - GlStateManager.enableDepth(); - GlStateManager.enableAlpha(); - GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); - - GlStateManager.popMatrix(); - } + GlStateManager.popMatrix(); } // FIXME: Something in here is making the first person shadow ward rather translucent. diff --git a/src/main/java/electroblob/wizardry/spell/Banish.java b/src/main/java/electroblob/wizardry/spell/Banish.java index efec3bcf..469334a2 100644 --- a/src/main/java/electroblob/wizardry/spell/Banish.java +++ b/src/main/java/electroblob/wizardry/spell/Banish.java @@ -46,6 +46,10 @@ public class Banish extends SpellRay { world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); } + + // Can't be bothered to route this through the proxies! + if(entity == net.minecraft.client.Minecraft.getMinecraft().player) + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); } if(y > -1){ diff --git a/src/main/java/electroblob/wizardry/spell/Blink.java b/src/main/java/electroblob/wizardry/spell/Blink.java index 1668f32b..8aacc347 100644 --- a/src/main/java/electroblob/wizardry/spell/Blink.java +++ b/src/main/java/electroblob/wizardry/spell/Blink.java @@ -43,6 +43,9 @@ public class Blink extends Spell { world.spawnParticle(EnumParticleTypes.PORTAL, dx, dy, dz, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); } + + // Can't be bothered to route this through the proxies! + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); } if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ diff --git a/src/main/java/electroblob/wizardry/spell/PhaseStep.java b/src/main/java/electroblob/wizardry/spell/PhaseStep.java index 2a7ad268..05f9a9f1 100644 --- a/src/main/java/electroblob/wizardry/spell/PhaseStep.java +++ b/src/main/java/electroblob/wizardry/spell/PhaseStep.java @@ -76,6 +76,9 @@ public class PhaseStep extends Spell { world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); } + + // Can't be bothered to route this through the proxies! + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); } return false; diff --git a/src/main/resources/assets/ebwizardry/textures/gui/blink_overlay.png b/src/main/resources/assets/ebwizardry/textures/gui/blink_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..d71610b635b18261696047000a3e984c91a9d58b GIT binary patch literal 25925 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 literal 0 HcmV?d00001 From f6a24038cc6cfcac71bad5ffbd3554cb4954b5a2 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 24 Jun 2018 19:14:48 +0100 Subject: [PATCH 40/68] Retexture spell HUD, add different textures for survival/creative mode, and tidy up the GUI code --- .../java/electroblob/wizardry/Settings.java | 9 +- .../wizardry/client/gui/GuiSpellDisplay.java | 108 ++++++++++-------- .../wizardry/util/WizardryUtilities.java | 50 +++++--- .../ebwizardry/textures/gui/spell_hud.png | Bin 29809 -> 20225 bytes 4 files changed, 102 insertions(+), 65 deletions(-) diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java index 0c747916..f409ecf5 100644 --- a/src/main/java/electroblob/wizardry/Settings.java +++ b/src/main/java/electroblob/wizardry/Settings.java @@ -168,7 +168,10 @@ public final class Settings { /** Set of constants for each of the four positions that the spell HUD can be in. */ public enum GuiPosition { - BOTTOM_LEFT("Bottom left"), TOP_LEFT("Top left"), TOP_RIGHT("Top right"), BOTTOM_RIGHT("Bottom right"); + BOTTOM_LEFT("Bottom left", false, false), + TOP_LEFT("Top left", false, true), + TOP_RIGHT("Top right", true, true), + BOTTOM_RIGHT("Bottom right", true, false); /** Constant array storing the names of each of the constants, in the order they are declared. */ public static final String[] names; @@ -182,8 +185,10 @@ public final class Settings { /** The readable name for this GUI position that will be displayed on the button in the config GUI. */ public final String name; + public boolean flipX; + public boolean flipY; - GuiPosition(String name){ + GuiPosition(String name, boolean flipX, boolean flipY){ this.name = name; } diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java index 10088ab2..583d418b 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java @@ -2,7 +2,6 @@ package electroblob.wizardry.client.gui; import java.util.List; -import electroblob.wizardry.Settings.GuiPosition; import electroblob.wizardry.SpellGlyphData; import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; @@ -30,11 +29,22 @@ public class GuiSpellDisplay extends Gui { private Minecraft mc; - private static final ResourceLocation hudTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud.png"); + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud.png"); - public GuiSpellDisplay(Minecraft par1Minecraft){ + // Measurements + /** Width of the used portion of the HUD texture */ private static final int HUD_WIDTH = 128; + /** Height of the used portion of the HUD texture */ private static final int HUD_HEIGHT = 64; + /** Distance (in x and y) of the spell icon from the screen edge */ private static final int SPELL_ICON_INSET = 2; + /** Line spacing for the spell name (when on two lines) */ private static final int TEXT_LINE_SPACING = 1; + /** Distance in x from the edge of the screen to the spell name */ private static final int TEXT_INSET_X = 42; + /** Distance in x of the cooldown bar from the screen edge */ private static final int COOLDOWN_BAR_INSET_X = 42; + /** Length of the cooldown bar portion of the HUD texture */ private static final int COOLDOWN_BAR_LENGTH = 79; + /** Height of the cooldown bar portion of the HUD texture */ private static final int COOLDOWN_BAR_HEIGHT = 5; + /** Width and height of the spell icon (very unlikely to change!) */private static final int SPELL_ICON_SIZE = 32; + + public GuiSpellDisplay(Minecraft minecraft){ super(); - this.mc = par1Minecraft; + this.mc = minecraft; } @SubscribeEvent @@ -65,26 +75,8 @@ public class GuiSpellDisplay extends Gui { cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier(); } - // Coordinates of the top left corner of the HUD. - int left = 0; - int top = 0; - boolean mirror = false; - - if(Wizardry.settings.spellHUDPosition == GuiPosition.BOTTOM_LEFT){ - left = 0; - top = height - 36; - }else if(Wizardry.settings.spellHUDPosition == GuiPosition.TOP_LEFT){ - left = 0; - top = 0; - }else if(Wizardry.settings.spellHUDPosition == GuiPosition.TOP_RIGHT){ - left = width - 128; - top = 0; - mirror = true; - }else if(Wizardry.settings.spellHUDPosition == GuiPosition.BOTTOM_RIGHT){ - left = width - 128; - top = height - 36; - mirror = true; - } + boolean flipX = Wizardry.settings.spellHUDPosition.flipX; + boolean flipY = Wizardry.settings.spellHUDPosition.flipY; boolean discovered = true; @@ -100,50 +92,70 @@ public class GuiSpellDisplay extends Gui { String spellName = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.world); FontRenderer font = discovered ? this.mc.fontRenderer : this.mc.standardGalacticFontRenderer; - int maxWidth = 90; + int maxWidth = HUD_WIDTH - TEXT_INSET_X; + int stringWidth = font.getStringWidth(spellName); + int iconMidpoint = (SPELL_ICON_SIZE + 2*SPELL_ICON_INSET)/2; // Should be 18 - if(font.getStringWidth(spellName) <= maxWidth){ + // TODO: Make a 'scrolling' animation when changing spells, using the text alpha channel to fade it in + // and out. + if(stringWidth <= maxWidth){ + //GL11.glPushMatrix(); + //GL11.glEnable(GL11.GL_BLEND); + //OpenGlHelper.glBlendFunc(770, 771, 1, 0); // Taken from GuiInGame. TODO: Replace with OpenGL caps. // Single line is rendered more centrally - font.drawStringWithShadow(colour + spellName, mirror ? left + 5 : left + 41, top + 13, 0xffffffff); - + font.drawStringWithShadow(colour + spellName, flipX ? width - TEXT_INSET_X - stringWidth : TEXT_INSET_X, + // The text is an odd number of pixels high so we need to subtract an extra 1 when at the bottom + flipY ? iconMidpoint - font.FONT_HEIGHT/2 : height - iconMidpoint - font.FONT_HEIGHT/2 - 1, 0xffffffff); + //GL11.glDisable(GL11.GL_BLEND); + //GL11.glPopMatrix(); }else{ int lineNumber = 0; List lines = font.listFormattedStringToWidth(spellName, maxWidth); - for(Object line : lines){ - if(line instanceof String){ - font.drawStringWithShadow(colour + (String)line, mirror ? left + 5 : left + 41, top + 6 + 11 * lineNumber, 0xffffffff); - } + for(String line : lines){ + int lineWidth = font.getStringWidth((String)line); + font.drawStringWithShadow(colour + (String)line, flipX ? width - TEXT_INSET_X - lineWidth : TEXT_INSET_X, + // This time there are two lines so we need to subtract the full line height, and an extra 1 for the spacing + (flipY ? iconMidpoint - font.FONT_HEIGHT - 1 : height - iconMidpoint - font.FONT_HEIGHT - 1) + // Note that there should only ever be two lines maximum + + lineNumber*(font.FONT_HEIGHT + TEXT_LINE_SPACING), 0xffffffff); lineNumber++; } } }else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){ + GlStateManager.pushMatrix(); GlStateManager.enableBlend(); GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); GlStateManager.color(1, 1, 1); - this.mc.renderEngine.bindTexture(hudTexture); - - // Background of spell hud - this.drawTexturedModalRect(left, top, 0, mirror ? 36 : 0, 128, 36); - - // Cooldown bar - if(cooldown > 0){ - this.drawTexturedModalRect(mirror ? left + 5 : left + 41, top + 28, 128, 6, 82, 6); - - int l = (int)(((double)(spell.cooldown * cooldownMultiplier - cooldown) / (double)(spell.cooldown * cooldownMultiplier)) * 82); - - this.drawTexturedModalRect(mirror ? left + 5 : left + 41, top + 28, 128, 0, l, 6); - } - - // Spell illustration + // Spell illustration - this is now done first so it is behind the HUD texture this.mc.renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon()); - WizardryUtilities.drawTexturedRect(mirror ? left + 94 : left + 2, top + 2, 0, 0, 32, 32, 32, 32); + WizardryUtilities.drawTexturedRect(flipX ? width - SPELL_ICON_INSET - SPELL_ICON_SIZE : SPELL_ICON_INSET, + flipY ? SPELL_ICON_INSET : height - SPELL_ICON_INSET - SPELL_ICON_SIZE, 0, 0, 32, 32, 32, 32); + + this.mc.renderEngine.bindTexture(texture); + + // Background of spell hud + WizardryUtilities.drawTexturedFlippedRect(flipX ? width-HUD_WIDTH : 0, flipY ? 0 : height-HUD_HEIGHT, + // The 128 here is a uv value, not a dimension, and hence is left as a hardcoded number. + player.capabilities.isCreativeMode ? 128 : 0, 0, HUD_WIDTH, HUD_HEIGHT, 256, 256, flipX, flipY); + + // Cooldown bar + if(!player.capabilities.isCreativeMode && cooldown > 0){ + + int l = (int)(((double)(spell.cooldown * cooldownMultiplier - cooldown) + / (double)(spell.cooldown * cooldownMultiplier)) * COOLDOWN_BAR_LENGTH); + // Likewise, the 64 here is a uv value and therefore left as a hardcoded number. + WizardryUtilities.drawTexturedFlippedRect(flipX ? width - COOLDOWN_BAR_INSET_X - COOLDOWN_BAR_LENGTH : COOLDOWN_BAR_INSET_X, + flipY ? 1 : height-1-COOLDOWN_BAR_HEIGHT, 0, 64, l, COOLDOWN_BAR_HEIGHT, 256, 256, false, flipY); + } + + GlStateManager.popMatrix(); // Blend needs to be left enabled here because otherwise the hotbar becomes opaque } diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index 6cb52655..d8381f99 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -716,28 +716,48 @@ public final class WizardryUtilities { * @param textureHeight The height of the actual image. */ @SideOnly(Side.CLIENT) - public static void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, - int textureHeight){ + public static void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight){ + drawTexturedFlippedRect(x, y, u, v, width, height, textureWidth, textureHeight, false, false); + } + + /** + * [Client-side only] Draws a textured rectangle, taking the size of the image and the bit needed into + * account, unlike {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int) + * Gui.drawTexturedModalRect(int, int, int, int, int, int)}, which is harcoded for only 256x256 textures. Also handy + * for custom potion icons. This version allows the texture to be flipped in x and/or y. + * + * @param x The x position of the rectangle + * @param y The y position of the rectangle + * @param u The x position of the top left corner of the section of the image wanted + * @param v The y position of the top left corner of the section of the image wanted + * @param width The width of the section + * @param height The height of the section + * @param textureWidth The width of the actual image. + * @param textureHeight The height of the actual image. + * @param flipX Whether to flip the texture in the x direction. + * @param flipY Whether to flip the texture in the y direction. + */ + @SideOnly(Side.CLIENT) + public static void drawTexturedFlippedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, boolean flipX, boolean flipY){ float f = 1F / (float)textureWidth; float f1 = 1F / (float)textureHeight; + + int u1 = flipX ? u + width : u; + int u2 = flipX ? u : u + width; + int v1 = flipY ? v + height : v; + int v2 = flipY ? v : v + height; // Essentially the same as getting the tessellator. For most code, you'll want the tessellator AND the - // vertexbuffer - // stored in local variables. - BufferBuilder buffer = net.minecraft.client.renderer.Tessellator.getInstance() - .getBuffer(); + // vertexbuffer stored in local variables. + BufferBuilder buffer = net.minecraft.client.renderer.Tessellator.getInstance().getBuffer(); // Equivalent of tessellator.startDrawingQuads() - buffer.begin(org.lwjgl.opengl.GL11.GL_QUADS, - net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + buffer.begin(org.lwjgl.opengl.GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); // Equivalent of tessellator.addVertex() - buffer.pos((double)(x), (double)(y + height), 0) - .tex((double)((float)(u) * f), (double)((float)(v + height) * f1)).endVertex(); - buffer.pos((double)(x + width), (double)(y + height), 0) - .tex((double)((float)(u + width) * f), (double)((float)(v + height) * f1)).endVertex(); - buffer.pos((double)(x + width), (double)(y), 0).tex((double)((float)(u + width) * f), (double)((float)(v) * f1)) - .endVertex(); - buffer.pos((double)(x), (double)(y), 0).tex((double)((float)(u) * f), (double)((float)(v) * f1)).endVertex(); + buffer.pos((double)(x), (double)(y + height), 0).tex((double)((float)(u1) * f), (double)((float)(v2) * f1)).endVertex(); + buffer.pos((double)(x + width), (double)(y + height), 0).tex((double)((float)(u2) * f), (double)((float)(v2) * f1)).endVertex(); + buffer.pos((double)(x + width), (double)(y), 0).tex((double)((float)(u2) * f), (double)((float)(v1) * f1)).endVertex(); + buffer.pos((double)(x), (double)(y), 0).tex((double)((float)(u1) * f), (double)((float)(v1) * f1)).endVertex(); // Exactly the same as before. net.minecraft.client.renderer.Tessellator.getInstance().draw(); } diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud.png index 8fb74e4eaabffe5bc5904511202e4d8e7b49c05b..8a6cc2eec401227bd8a4f3950907be01fdae9456 100644 GIT binary patch literal 20225 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 z z))_3$aI!gc4C_P+mS<^Nu2#((

w^PXOMwWc=f-JZICoLBU1`i`wij<%idb6K(C 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 Date: Sun, 24 Jun 2018 19:16:11 +0100 Subject: [PATCH 41/68] Add back face to renderer for force arrow --- .../wizardry/client/renderer/RenderForceArrow.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java b/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java index 5878aeeb..a7632a8d 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java @@ -73,13 +73,23 @@ public class RenderForceArrow extends Render { GlStateManager.scale(scale, scale, scale); GlStateManager.translate(-4.0F, 0.0F, 0.0F); + // Front buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); buffer.pos(-5, 3.5, -3.5).tex((double)u5, (double)v5).endVertex(); buffer.pos(-5, 3.5, 3.5).tex((double)u6, (double)v5).endVertex(); buffer.pos(-5, -3.5, 3.5).tex((double)u6, (double)v6).endVertex(); - buffer.pos(-5, -3.5, -3.5).tex((double)u5, (double)v6); + buffer.pos(-5, -3.5, -3.5).tex((double)u5, (double)v6).endVertex(); + tessellator.draw(); + + // Back + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-5, -3.5, -3.5).tex((double)u5, (double)v6).endVertex(); + buffer.pos(-5, -3.5, 3.5).tex((double)u6, (double)v6).endVertex(); + buffer.pos(-5, 3.5, 3.5).tex((double)u6, (double)v5).endVertex(); + buffer.pos(-5, 3.5, -3.5).tex((double)u5, (double)v5).endVertex(); tessellator.draw(); + // Rings for(int i = 0; i < 5; i++){ GlStateManager.color(1, 1, 1, 1 - i * 0.2f); double j = i + ((double)arrow.ticksExisted % 3) / 3; @@ -102,6 +112,7 @@ public class RenderForceArrow extends Render { GlStateManager.color(1, 1, 1, 1); + // Sides for(int i = 0; i < 4; ++i){ GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F); GL11.glNormal3f(0.0F, 0.0F, scale); From b7cd3db8bcb5ed9f95c74e5b11fbd05aa4aa4377 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Mon, 2 Jul 2018 22:05:19 +0100 Subject: [PATCH 42/68] Rename armour fix model --- .../client/model/{ModelWtfMojang.java => ModelArmourFixer.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/electroblob/wizardry/client/model/{ModelWtfMojang.java => ModelArmourFixer.java} (100%) diff --git a/src/main/java/electroblob/wizardry/client/model/ModelWtfMojang.java b/src/main/java/electroblob/wizardry/client/model/ModelArmourFixer.java similarity index 100% rename from src/main/java/electroblob/wizardry/client/model/ModelWtfMojang.java rename to src/main/java/electroblob/wizardry/client/model/ModelArmourFixer.java From af01beb583fea1d75c8adc9a2b1fc41ef4db024d Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Mon, 2 Jul 2018 22:33:09 +0100 Subject: [PATCH 43/68] Spell HUD rewrite and retexturing: - Replaces the old hardcoded drawing methods with a new json-based system with support for multiple inbuilt and resource pack-defined skins. - Adds a config option for choosing the spell HUD skin, along with a custom config GUI screen allowing the user to select from a list of available skins with a preview of the currently selected skin. - Replaces the HUD texture file with a spell_hud subfolder, containing all the necessary textures and json files for the 12 inbuilt skins. - Adds a subtle sound effect and scroling animation when switching spells - Reorganises the control event code into a single handler class and converts this class and the spell HUD class to static event handlers. - Fixes the HUD position option which got broken in the previous spell HUD commit --- .../electroblob/wizardry/CommonProxy.java | 10 +- .../java/electroblob/wizardry/Settings.java | 12 + .../java/electroblob/wizardry/Wizardry.java | 4 +- .../wizardry/WizardryKeyHandler.java | 68 -- .../wizardry/client/ClientProxy.java | 25 +- .../client/SpellHUDSkinChooserEntry.java | 38 ++ .../client/WizardryClientEventHandler.java | 35 - .../client/WizardryControlHandler.java | 132 ++++ .../wizardry/client/gui/GuiSelectHUDSkin.java | 106 +++ .../wizardry/client/gui/GuiSpellDisplay.java | 617 +++++++++++++++--- .../wizardry/registry/WizardrySounds.java | 2 + .../electroblob/wizardry/util/WandHelper.java | 113 +++- .../assets/ebwizardry/lang/en_gb.lang | 2 + .../assets/ebwizardry/lang/en_us.lang | 2 + .../resources/assets/ebwizardry/sounds.json | 4 +- .../assets/ebwizardry/sounds/select.ogg | Bin 0 -> 9316 bytes .../ebwizardry/textures/gui/spell_hud.png | Bin 20225 -> 0 bytes .../textures/gui/spell_hud/_index.json | 50 ++ .../textures/gui/spell_hud/classic.json | 33 + .../textures/gui/spell_hud/classic.png | Bin 0 -> 22426 bytes .../textures/gui/spell_hud/default.json | 33 + .../textures/gui/spell_hud/default.png | Bin 0 -> 20706 bytes .../textures/gui/spell_hud/jungle.json | 33 + .../textures/gui/spell_hud/jungle.png | Bin 0 -> 25335 bytes .../textures/gui/spell_hud/minimal.json | 33 + .../textures/gui/spell_hud/minimal.png | Bin 0 -> 19824 bytes .../textures/gui/spell_hud/no_icon.json | 33 + .../textures/gui/spell_hud/no_icon.png | Bin 0 -> 20184 bytes .../textures/gui/spell_hud/redwood.json | 33 + .../textures/gui/spell_hud/redwood.png | Bin 0 -> 28010 bytes .../textures/gui/spell_hud/sandstone.json | 33 + .../textures/gui/spell_hud/sandstone.png | Bin 0 -> 24369 bytes .../textures/gui/spell_hud/silverwood.json | 33 + .../textures/gui/spell_hud/silverwood.png | Bin 0 -> 27885 bytes .../textures/gui/spell_hud/skyrim_style.json | 33 + .../textures/gui/spell_hud/skyrim_style.png | Bin 0 -> 20676 bytes .../textures/gui/spell_hud/spell_book.json | 33 + .../textures/gui/spell_hud/spell_book.png | Bin 0 -> 23686 bytes .../textures/gui/spell_hud/stone.json | 33 + .../textures/gui/spell_hud/stone.png | Bin 0 -> 24156 bytes .../textures/gui/spell_hud/vanilla_style.json | 33 + .../textures/gui/spell_hud/vanilla_style.png | Bin 0 -> 33784 bytes 42 files changed, 1393 insertions(+), 223 deletions(-) delete mode 100644 src/main/java/electroblob/wizardry/WizardryKeyHandler.java create mode 100644 src/main/java/electroblob/wizardry/client/SpellHUDSkinChooserEntry.java create mode 100644 src/main/java/electroblob/wizardry/client/WizardryControlHandler.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java create mode 100644 src/main/resources/assets/ebwizardry/sounds/select.ogg delete mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/classic.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/classic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/jungle.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/jungle.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/minimal.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/minimal.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/no_icon.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/no_icon.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/redwood.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/redwood.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/sandstone.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/sandstone.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/silverwood.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/silverwood.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/spell_book.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/spell_book.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/stone.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/stone.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/vanilla_style.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/vanilla_style.png diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index cb2e1441..367352c7 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -46,13 +46,14 @@ public class CommonProxy { public void registerKeyBindings(){ } - public void registerSpellHUD(){} public net.minecraft.client.model.ModelBiped getWizardArmourModel(){ return null; } public void initGuiBits(){} + + public void registerResourceReloadListener(){} // SECTION Particles // =============================================================================================================== @@ -126,6 +127,8 @@ public class CommonProxy { public void setToNumberSliderEntry(Property property){ } + + public void setToHUDChooserEntry(Property property){} // public void setToEntityNameEntry(Property property){} /** @@ -148,4 +151,9 @@ public class CommonProxy { return null; } + /** Returns an unmodifiable set of the string keys for all of the loaded spell HUD skins. */ + public Set getSpellHUDSkins(){ + return null; + } + } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java index f409ecf5..3994f11b 100644 --- a/src/main/java/electroblob/wizardry/Settings.java +++ b/src/main/java/electroblob/wizardry/Settings.java @@ -164,6 +164,10 @@ public final class Settings { public boolean showSummonedCreatureNames = true; /** [Client-only] The position of the spell HUD. */ public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT; + + public static final String DEFAULT_HUD_SKIN_KEY = "default"; // Defined here so it's not in a client-only class. + /** [Client-only] The string identifier of the skin used for the spell HUD. */ + public String spellHUDSkin = DEFAULT_HUD_SKIN_KEY; /** Set of constants for each of the four positions that the spell HUD can be in. */ public enum GuiPosition { @@ -190,6 +194,8 @@ public final class Settings { GuiPosition(String name, boolean flipX, boolean flipY){ this.name = name; + this.flipX = flipX; + this.flipY = flipY; } /** @@ -458,6 +464,12 @@ public final class Settings { property.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_position"); spellHUDPosition = GuiPosition.fromName(property.getString()); propOrder.add(property.getName()); + + property = config.get(CLIENT_CATEGORY, "spellHUDSkin", DEFAULT_HUD_SKIN_KEY, "The skin used for the spell HUD.", Wizardry.proxy.getSpellHUDSkins().toArray(new String[0])); + property.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_skin"); + Wizardry.proxy.setToHUDChooserEntry(property); + spellHUDSkin = property.getString(); + propOrder.add(property.getName()); property = config.get(CLIENT_CATEGORY, "showSummonedCreatureNames", true, "Whether to show summoned creatures' names and owners above their heads."); property.setLanguageKey("config." + Wizardry.MODID + ".show_summoned_creature_names"); diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index 42b156ca..c746803a 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -120,6 +120,8 @@ public class Wizardry { public void preInit(FMLPreInitializationEvent event){ logger = event.getModLog(); + + proxy.registerResourceReloadListener(); settings.initConfig(event); @@ -162,9 +164,7 @@ public class Wizardry { // Event Handlers GameRegistry.registerWorldGenerator(generator, 0); - MinecraftForge.EVENT_BUS.register(new WizardryKeyHandler()); MinecraftForge.EVENT_BUS.register(instance); - proxy.registerSpellHUD(); // This can't easily be converted to use the new @Mod.EventBusSubscriber system NetworkRegistry.INSTANCE.registerGuiHandler(this, new WizardryGuiHandler()); WizardryPacketHandler.initPackets(); diff --git a/src/main/java/electroblob/wizardry/WizardryKeyHandler.java b/src/main/java/electroblob/wizardry/WizardryKeyHandler.java deleted file mode 100644 index 99852c4c..00000000 --- a/src/main/java/electroblob/wizardry/WizardryKeyHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -package electroblob.wizardry; - -import org.lwjgl.input.Keyboard; - -import electroblob.wizardry.client.ClientProxy; -import electroblob.wizardry.packet.PacketControlInput; -import electroblob.wizardry.packet.WizardryPacketHandler; -import net.minecraft.client.Minecraft; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.InputEvent; -import net.minecraftforge.fml.common.network.simpleimpl.IMessage; - -public class WizardryKeyHandler { - - boolean NkeyPressed = false; - boolean BkeyPressed = false; - boolean NkeyAlreadyPressed = false; - boolean BkeyAlreadyPressed = false; - - @SubscribeEvent - public void onKeyInput(InputEvent.KeyInputEvent event){ - - // Key pressed - if(Keyboard.getEventKeyState()){ - - if(Wizardry.proxy instanceof ClientProxy){ - - if(ClientProxy.NEXT_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){ - if(!NkeyPressed){ - NkeyPressed = true; - }else{ - NkeyAlreadyPressed = true; - } - if(!NkeyAlreadyPressed){ - // Packet building - IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY); - WizardryPacketHandler.net.sendToServer(msg); - } - } - - if(ClientProxy.PREVIOUS_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){ - if(!BkeyPressed){ - BkeyPressed = true; - }else{ - BkeyAlreadyPressed = true; - } - if(!BkeyAlreadyPressed){ - // Packet building - IMessage msg = new PacketControlInput.Message( - PacketControlInput.ControlType.PREVIOUS_SPELL_KEY); - WizardryPacketHandler.net.sendToServer(msg); - } - } - } - } - - // Key released - else{ - if(NkeyPressed){ - NkeyPressed = false; - NkeyAlreadyPressed = false; - }else if(BkeyPressed){ - BkeyPressed = false; - BkeyAlreadyPressed = false; - } - } - } -} diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 93deb66d..d688d89f 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -130,6 +130,8 @@ import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.renderer.entity.RenderBlaze; import net.minecraft.client.resources.I18n; +import net.minecraft.client.resources.IReloadableResourceManager; +import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; @@ -185,17 +187,20 @@ public class ClientProxy extends CommonProxy { ClientRegistry.registerKeyBinding(PREVIOUS_SPELL); } - @Override - public void registerSpellHUD(){ - MinecraftForge.EVENT_BUS.register(new GuiSpellDisplay(Minecraft.getMinecraft())); - } - @Override public void initGuiBits(){ mixedFontRenderer = new MixedFontRenderer(Minecraft.getMinecraft().gameSettings, new ResourceLocation("textures/font/ascii.png"), Minecraft.getMinecraft().renderEngine, false); GuiWizardHandbook.initDisplayRecipes(); } + + @Override + public void registerResourceReloadListener(){ + IResourceManager manager = Minecraft.getMinecraft().getResourceManager(); + if(manager instanceof IReloadableResourceManager){ + ((IReloadableResourceManager)manager).registerReloadListener(GuiSpellDisplay::loadSkins); + } + } // SECTION Misc // =============================================================================================================== @@ -204,6 +209,11 @@ public class ClientProxy extends CommonProxy { public void setToNumberSliderEntry(Property property){ property.setConfigEntryClass(NumberSliderEntry.class); } + + @Override + public void setToHUDChooserEntry(Property property){ + property.setConfigEntryClass(SpellHUDSkinChooserEntry.class); + } @Override public World getTheWorld(){ @@ -214,6 +224,11 @@ public class ClientProxy extends CommonProxy { public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){ Minecraft.getMinecraft().getSoundHandler().playSound(new MovingSoundEntity(entity, sound, volume, pitch, repeat)); } + + @Override + public Set getSpellHUDSkins(){ + return GuiSpellDisplay.getSkinKeys(); + } // SECTION Items // =============================================================================================================== diff --git a/src/main/java/electroblob/wizardry/client/SpellHUDSkinChooserEntry.java b/src/main/java/electroblob/wizardry/client/SpellHUDSkinChooserEntry.java new file mode 100644 index 00000000..a6872673 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/SpellHUDSkinChooserEntry.java @@ -0,0 +1,38 @@ +package electroblob.wizardry.client; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import electroblob.wizardry.client.gui.GuiSelectHUDSkin; +import electroblob.wizardry.client.gui.GuiSpellDisplay; +import net.minecraftforge.client.gui.ForgeGuiFactory.ForgeConfigGui.ModIDEntry; +import net.minecraftforge.fml.client.config.GuiConfig; +import net.minecraftforge.fml.client.config.GuiConfigEntries; +import net.minecraftforge.fml.client.config.GuiConfigEntries.SelectValueEntry; +import net.minecraftforge.fml.client.config.IConfigElement; + +/** + * Custom config GUI for spell HUD skin selection; displays a list of all the loaded skins and a preview of the currently + * selected skin. based off of {@link ModIDEntry} from Forge. + */ +public class SpellHUDSkinChooserEntry extends SelectValueEntry { + + public SpellHUDSkinChooserEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop) + { + super(owningScreen, owningEntryList, prop, getSelectableValues()); + if (this.selectableValues.size() == 0) + this.btnValue.enabled = false; + } + + private static Map getSelectableValues(){ + return GuiSpellDisplay.getSkins().entrySet().stream().collect(Collectors.toMap(Entry::getKey, + e -> e.getValue().getName())); + } + + @Override // Copied from superclass to use custom child screen GUI class + public void valueButtonPressed(int slotIndex){ + mc.displayGuiScreen(new GuiSelectHUDSkin(this.owningScreen, configElement, slotIndex, selectableValues, currentValue, enabled())); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java index 39cf3b92..ced104f6 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -7,8 +7,6 @@ import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.item.ItemSpectralBow; import electroblob.wizardry.item.ItemWand; -import electroblob.wizardry.packet.PacketControlInput; -import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.spell.Flight; @@ -38,7 +36,6 @@ import net.minecraft.util.math.RayTraceResult; import net.minecraft.village.MerchantRecipe; import net.minecraftforge.client.event.FOVUpdateEvent; import net.minecraftforge.client.event.GuiContainerEvent; -import net.minecraftforge.client.event.MouseEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderLivingEvent; import net.minecraftforge.client.event.RenderPlayerEvent; @@ -47,7 +44,6 @@ import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -101,37 +97,6 @@ public final class WizardryClientEventHandler { // } } - // Shift-scrolling to change spells - @SubscribeEvent - public static void onMouseEvent(MouseEvent event){ - - EntityPlayer player = Minecraft.getMinecraft().player; - ItemStack wand = player.getHeldItemMainhand(); - - if(!(wand.getItem() instanceof ItemWand)){ - wand = player.getHeldItemOffhand(); - // If the player isn't holding a wand, then nothing else needs to be done. - if(!(wand.getItem() instanceof ItemWand)) return; - } - - if(Minecraft.getMinecraft().inGameHasFocus && !wand.isEmpty() && event.getDwheel() != 0 && player.isSneaking() - && Wizardry.settings.enableShiftScrolling){ - - event.setCanceled(true); - - if(event.getDwheel() > 0){ - // Packet building - IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY); - WizardryPacketHandler.net.sendToServer(msg); - - }else if(event.getDwheel() < 0){ - // Packet building - IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY); - WizardryPacketHandler.net.sendToServer(msg); - } - } - } - @SubscribeEvent public static void onFOVUpdateEvent(FOVUpdateEvent event){ diff --git a/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java b/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java new file mode 100644 index 00000000..8e4fea67 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java @@ -0,0 +1,132 @@ +package electroblob.wizardry.client; + +import org.lwjgl.input.Keyboard; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.gui.GuiSpellDisplay; +import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.packet.PacketControlInput; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.WandHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.client.event.MouseEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.InputEvent; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** Event handler class responsible for handling wizardry's controls. */ +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(Side.CLIENT) +public class WizardryControlHandler { + + static boolean NkeyPressed = false; + static boolean BkeyPressed = false; + static boolean NkeyAlreadyPressed = false; + static boolean BkeyAlreadyPressed = false; + + @SubscribeEvent + public static void onKeyInput(InputEvent.KeyInputEvent event){ + + // Key pressed + if(Keyboard.getEventKeyState()){ + + if(Wizardry.proxy instanceof ClientProxy){ + + EntityPlayer player = Minecraft.getMinecraft().player; + ItemStack wand = player.getHeldItemMainhand(); + + if(!(wand.getItem() instanceof ItemWand)){ + wand = player.getHeldItemOffhand(); + // If the player isn't holding a wand, then nothing else needs to be done. + if(!(wand.getItem() instanceof ItemWand)) return; + } + + if(ClientProxy.NEXT_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){ + if(!NkeyPressed){ + NkeyPressed = true; + }else{ + NkeyAlreadyPressed = true; + } + if(!NkeyAlreadyPressed){ + selectNextSpell(wand); + } + } + + if(ClientProxy.PREVIOUS_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){ + if(!BkeyPressed){ + BkeyPressed = true; + }else{ + BkeyAlreadyPressed = true; + } + if(!BkeyAlreadyPressed){ + selectPreviousSpell(wand); + } + } + } + } + + // Key released + else{ + if(NkeyPressed){ + NkeyPressed = false; + NkeyAlreadyPressed = false; + }else if(BkeyPressed){ + BkeyPressed = false; + BkeyAlreadyPressed = false; + } + } + } + + // Shift-scrolling to change spells + @SubscribeEvent + public static void onMouseEvent(MouseEvent event){ + + EntityPlayer player = Minecraft.getMinecraft().player; + ItemStack wand = player.getHeldItemMainhand(); + + if(!(wand.getItem() instanceof ItemWand)){ + wand = player.getHeldItemOffhand(); + // If the player isn't holding a wand, then nothing else needs to be done. + if(!(wand.getItem() instanceof ItemWand)) return; + } + + if(Minecraft.getMinecraft().inGameHasFocus && !wand.isEmpty() && event.getDwheel() != 0 && player.isSneaking() + && Wizardry.settings.enableShiftScrolling){ + + event.setCanceled(true); + + if(event.getDwheel() > 0){ + selectNextSpell(wand); + }else if(event.getDwheel() < 0){ + selectPreviousSpell(wand); + } + } + } + + private static void selectNextSpell(ItemStack wand){ + // Packet building + IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY); + WizardryPacketHandler.net.sendToServer(msg); + // GUI switch animation + WandHelper.selectNextSpell(wand); // Makes sure the spell is set immediately for the client + GuiSpellDisplay.playSpellSwitchAnimation(true); + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.SELECT_SPELL, 1)); + } + + private static void selectPreviousSpell(ItemStack wand){ + // Packet building + IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY); + WizardryPacketHandler.net.sendToServer(msg); + // GUI switch animation + WandHelper.selectPreviousSpell(wand); // Makes sure the spell is set immediately for the client + GuiSpellDisplay.playSpellSwitchAnimation(false); + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.SELECT_SPELL, 1)); + } +} diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java b/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java new file mode 100644 index 00000000..1da12067 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java @@ -0,0 +1,106 @@ +package electroblob.wizardry.client.gui; + +import java.util.Map; + +import javax.annotation.Nullable; + +import com.google.common.collect.Lists; + +import electroblob.wizardry.client.gui.GuiSpellDisplay.Skin; +import electroblob.wizardry.registry.Spells; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraftforge.fml.client.config.GuiSelectString; +import net.minecraftforge.fml.client.config.IConfigElement; + +public class GuiSelectHUDSkin extends GuiSelectString { + + public GuiSelectHUDSkin(GuiScreen parentScreen, IConfigElement configElement, int slotIndex, Map selectableValues, Object currentValue, boolean enabled){ + super(parentScreen, configElement, slotIndex, selectableValues, currentValue, enabled); + } + + @Override + public void initGui(){ + super.initGui(); + this.entryList.setDimensions(150, height, 43, height-43); + this.entryList.left = 10; + this.entryList.headerPadding = 5; + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks){ + + super.drawScreen(mouseX, mouseY, partialTicks); + + GlStateManager.disableLighting(); + + if(this.currentValue instanceof String){ + + this.drawString(this.fontRenderer, "Preview:", 170, 44, 0xffffff); + + int previewLeft = 170; + int previewRight = width-10; + int previewTop = 60; + int previewBottom = height-43; + + this.drawGradientRect(previewLeft, previewTop, previewRight, previewBottom, 0x88000000, 0x88000000); + + int previewBorder = 10; + + Skin skin = GuiSpellDisplay.getSkin((String)this.currentValue); + + float scale = Math.min((previewRight - previewLeft - 2*previewBorder)/(float)skin.getWidth(), + (previewBottom - previewTop - 2*previewBorder)/(float)skin.getHeight()); + + float x = (previewLeft + previewRight)/2 - (skin.getWidth()*scale)/2; + float y = (previewBottom + previewTop)/2 + (skin.getHeight()*scale)/2; + + GlStateManager.pushMatrix(); + + GlStateManager.scale(scale, scale, scale); + + skin.drawBackground((int)(x/scale), (int)(y/scale), false, false, + Spells.magic_missile.getIcon(), 0.6f, false); + + skin.drawText((int)(x/scale), (int)(y/scale), false, false, + Spells.none.getDisplayNameWithFormatting(), + Spells.magic_missile.getDisplayNameWithFormatting(), + Spells.none.getDisplayNameWithFormatting(), 0); + + GlStateManager.popMatrix(); + + Skin hovered = getHoveredSkin(mouseX, mouseY); + + if(hovered != null){ + this.drawToolTip(Lists.newArrayList("\u00A7a" + hovered.getName(), "\u00A7e" + hovered.getDescription()), + mouseX, mouseY); + } + } + + GlStateManager.enableLighting(); + } + + /** Returns the skin corresponding to the list entry being hovered over, or null if there is none. */ + @Nullable + private Skin getHoveredSkin(int mouseX, int mouseY){ + + int index = this.entryList.getSlotIndexFromScreenCoords(mouseX, mouseY); + + if(index >= 0 && index <= this.entryList.listEntries.size() && mouseY <= this.entryList.bottom){ + + Object object = entryList.getListEntry(index).getValue(); + + if(object instanceof String){ + return GuiSpellDisplay.getSkin((String)object); + } + } + + return null; + } + + @Override // Stops the world being visible behind the GUI when configuring from within a world + public void drawWorldBackground(int tint){ + this.drawBackground(tint); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java index 583d418b..fff4d965 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java @@ -1,10 +1,25 @@ package electroblob.wizardry.client.gui; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import electroblob.wizardry.Settings; import electroblob.wizardry.SpellGlyphData; import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.ClientProxy; +import electroblob.wizardry.client.MixedFontRenderer; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.registry.Spells; @@ -15,42 +30,78 @@ import electroblob.wizardry.util.WandHelper; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.gui.Gui; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager.DestFactor; import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.resources.IResource; +import net.minecraft.client.resources.IResourceManager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.util.JsonUtils; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; -public class GuiSpellDisplay extends Gui { +@Mod.EventBusSubscriber(Side.CLIENT) +public class GuiSpellDisplay { - private Minecraft mc; - - private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud.png"); - - // Measurements - /** Width of the used portion of the HUD texture */ private static final int HUD_WIDTH = 128; - /** Height of the used portion of the HUD texture */ private static final int HUD_HEIGHT = 64; - /** Distance (in x and y) of the spell icon from the screen edge */ private static final int SPELL_ICON_INSET = 2; - /** Line spacing for the spell name (when on two lines) */ private static final int TEXT_LINE_SPACING = 1; - /** Distance in x from the edge of the screen to the spell name */ private static final int TEXT_INSET_X = 42; - /** Distance in x of the cooldown bar from the screen edge */ private static final int COOLDOWN_BAR_INSET_X = 42; - /** Length of the cooldown bar portion of the HUD texture */ private static final int COOLDOWN_BAR_LENGTH = 79; - /** Height of the cooldown bar portion of the HUD texture */ private static final int COOLDOWN_BAR_HEIGHT = 5; - /** Width and height of the spell icon (very unlikely to change!) */private static final int SPELL_ICON_SIZE = 32; + private static final ResourceLocation INDEX = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud/_index.json"); - public GuiSpellDisplay(Minecraft minecraft){ - super(); - this.mc = minecraft; + /** A map which stores all loaded HUD skin objects. This gets wiped on resource pack reload and repopulated with + * mappings as specified by {@code _index.json} (these stack between resource packs). The keys in the map correspond + * to the keys in {@code _index.json}, and are sorted in that order, with skins belonging to resource packs sorted + * from lowest to highest priority. The skins in the base mod will therefore always be first. */ + private static final Map skins = new LinkedHashMap<>(12); // 12 is the number of skins packaged with the mod + + private static final Gson gson = new Gson(); + + /** Width and height of the spell icon (very unlikely to change!) */ + private static final int SPELL_ICON_SIZE = 32; + /** Number of ticks the spell switching animation plays for. */ + private static final int SPELL_SWITCH_TIME = 4; + /** Scale of the next/previous spell names. */ + private static final float SPELL_NAME_SCALE = 0.5f; + /** Opacity of the next/previous spell names, as a fraction. */ + private static final float SPELL_NAME_OPACITY = 0.3f; + + /** Controls the spell switching animation. Positive when switching to the next spell, negative when switching to + * the previous spell. Decremented in magnitude by 1 each tick until it reaches 0 again. */ + private static int switchTimer = 0; + + /** + * Starts the spell switching animation. + * @param next True to switch to the next spell, false for the previous spell. + */ + public static void playSpellSwitchAnimation(boolean next){ + switchTimer = next ? SPELL_SWITCH_TIME : -SPELL_SWITCH_TIME; } - + + /** Returns an unmodifiable set of the string keys for all of the loaded spell HUD skins. */ + public static Set getSkinKeys(){ + return Collections.unmodifiableSet(skins.keySet()); + } + + /** Returns an unmodifiable view of the loaded spell HUD skins map. */ + public static Map getSkins(){ + return Collections.unmodifiableMap(skins); + } + + /** Returns the skin that corresponds to the given key. */ + public static Skin getSkin(String key){ + return skins.get(key); + } + + // Normally when extending Gui, you'd have to have an instance to access its methods. However, we're not actually + // using any of them, so this class may as well not bother and just be a static event handler. Neat! @SubscribeEvent - public void draw(RenderGameOverlayEvent event){ + public static void draw(RenderGameOverlayEvent event){ + + Minecraft mc = Minecraft.getMinecraft(); - EntityPlayer player = this.mc.player; + EntityPlayer player = mc.player; // If the player has a wand in each hand, only displays for the one in the main hand. @@ -65,100 +116,502 @@ public class GuiSpellDisplay extends Gui { int width = event.getResolution().getScaledWidth(); int height = event.getResolution().getScaledHeight(); + boolean flipX = Wizardry.settings.spellHUDPosition.flipX; + boolean flipY = Wizardry.settings.spellHUDPosition.flipY; + + Skin skin = skins.get(Wizardry.settings.spellHUDSkin); + + if(skin == null){ + + Wizardry.logger.info("The spell HUD skin '" + Wizardry.settings.spellHUDSkin + "' specified in the config" + + " did not match any of the loaded skins; using the default skin as a fallback."); + + skin = skins.get(Settings.DEFAULT_HUD_SKIN_KEY); + + if(skin == null){ + Wizardry.logger.warn("The default spell HUD skin is missing! A resource pack must have overridden it" + + " with an invalid JSON file (default.json), please try again without any resource packs."); + return; + } + } + + // 'Origin' of the spell hud (bottom left corner of the actual texture, always in the corner of the screen) + int x = flipX ? width : 0; + int y = flipY ? 0: height; + Spell spell = WandHelper.getCurrentSpell(wand); int cooldown = WandHelper.getCurrentCooldown(wand); - float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(wand, WizardryItems.cooldown_upgrade) * Constants.COOLDOWN_REDUCTION_PER_LEVEL; + if(event.getType() == RenderGameOverlayEvent.ElementType.TEXT){ + + float animationProgress = Math.signum(switchTimer) * ((SPELL_SWITCH_TIME - Math.abs(switchTimer) + + event.getPartialTicks()) / SPELL_SWITCH_TIME); + + String prevSpellName = getFormattedSpellName(WandHelper.getPreviousSpell(wand), player, WandHelper.getPreviousCooldown(wand)); + String spellName = getFormattedSpellName(spell, player, cooldown); + String nextSpellName = getFormattedSpellName(WandHelper.getNextSpell(wand), player, WandHelper.getNextCooldown(wand)); - if(player.isPotionActive(WizardryPotions.font_of_mana)){ - // Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously - cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier(); + skin.drawText(x, y, flipX, flipY, prevSpellName, spellName, nextSpellName, animationProgress); + + }else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){ + + float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(wand, WizardryItems.cooldown_upgrade) * Constants.COOLDOWN_REDUCTION_PER_LEVEL; + + if(player.isPotionActive(WizardryPotions.font_of_mana)){ + // Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously + cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier(); + } + + boolean discovered = true; + + if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){ + discovered = WizardData.get(player).hasSpellBeenDiscovered(spell); + } + + ResourceLocation icon = discovered ? spell.getIcon() : Spells.none.getIcon(); + + float progress = 1; + // Doesn't really matter what progress is when in creative, but we might as well avoid the calculation. + if(!player.capabilities.isCreativeMode && !spell.isContinuous){ + // Subtracted partial tick time to make it smoother + progress = (spell.cooldown * cooldownMultiplier - (float)cooldown + event.getPartialTicks()) + /(spell.cooldown * cooldownMultiplier); + } + + skin.drawBackground(x, y, flipX, flipY, icon, progress, player.capabilities.isCreativeMode); + } - - boolean flipX = Wizardry.settings.spellHUDPosition.flipX; - boolean flipY = Wizardry.settings.spellHUDPosition.flipY; - + } + + /** + * Makes the given opaque colour translucent with the given opacity. + * @param colour An integer colour code, should be a 6-digit hexadecimal (i.e. opaque). + * @param opacity The opacity to apply to the given colour, as a fraction between 0 and 1. + * @return The resulting integer colour code, which will be an 8-digit hexadecimal. + */ + private static int makeTranslucent(int colour, float opacity){ + return colour + ((int)(0xff * opacity * 0x01000000)); + } + + /** Gets the name of the given spell, with formatted added according to its cooldown and whether the given player + * has discovered it. + * @param spell The spell to get the name of. + * @param The player to test for having discovered the given spell. + * @param cooldown The spell's current cooldown. + * @return The spell name, with relevant formatting added, for use with the {@link MixedFontRenderer}. + */ + private static String getFormattedSpellName(Spell spell, EntityPlayer player, int cooldown){ + boolean discovered = true; if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){ discovered = WizardData.get(player).hasSpellBeenDiscovered(spell); } + + // Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect + String format = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.element.getFormattingCode(); + if(!discovered) format = "\u00A79"; + + String name = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.world); + name = format + name; + if(!discovered) name = "#" + name + "#"; + + return name; + } + + /** + * Draws the given string at the given position, scaling it if it does not fit within the given width. + * @param font A {@code FontRenderer} object. + * @param text The text to display. + * @param x The x position of the top-left corner of the text. + * @param y The y position of the top-left corner of the text. + * @param scale The scale that the text should be if it does not exceed the maximum width. + * @param colour The colour to render the text in, supports translucency. + * @param width The maximum width of the text. This is not scaled; you should pass in the width of the actual + * area of the screen in which the text needs to fit. + * @param centre Whether to adjust the y position such that the centre of the text lines up with where its centre + * would be if it was not scaled (automatically or manually). + * @param alignR True to right-align the text, false for normal left alignment. + */ + private static void drawScaledStringToWidth(FontRenderer font, String text, float x, float y, float scale, int colour, float width, boolean centre, boolean alignR){ + + float textWidth = font.getStringWidth(text) * scale; + float textHeight = font.FONT_HEIGHT * scale; + + if(textWidth > width){ + scale *= width/textWidth; + }else if(alignR){ // Alignment makes no difference if the string fills the entire width + x += width - textWidth; + } + + if(centre) y += (font.FONT_HEIGHT - textHeight)/2; + + drawScaledTranslucentString(font, text, x, y, scale, colour); + } + + /** Draws the given string at the given position, scaling the text by the specified factor. Also enables blending to + * render text in semitransparent colours (e.g. 0x88ffffff). */ + private static void drawScaledTranslucentString(FontRenderer font, String text, float x, float y, float scale, int colour){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.scale(scale, scale, scale); + // Because we scaled it, the coordinates have to be scaled inversely + x /= scale; + y /= scale; + font.drawStringWithShadow(text, x, y, colour); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + } + + @SubscribeEvent + public static void onLivingUpdateEvent(LivingUpdateEvent event){ + if(event.getEntity() == Minecraft.getMinecraft().player){ // Makes sure this only gets called once each tick. + if(switchTimer > 0) switchTimer--; + else if(switchTimer < 0) switchTimer++; + } + } + + /** Called from preInit in the main mod class (via the proxies) to initialise the HUD skins, and again on each + * resource reload. */ + public static void loadSkins(IResourceManager manager){ + + try { - if(event.getType() == RenderGameOverlayEvent.ElementType.TEXT){ - - // Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect - String colour = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.element.getFormattingCode(); - if(!discovered) colour = "\u00A79"; - String spellName = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.world); - FontRenderer font = discovered ? this.mc.fontRenderer : this.mc.standardGalacticFontRenderer; - - int maxWidth = HUD_WIDTH - TEXT_INSET_X; - int stringWidth = font.getStringWidth(spellName); - int iconMidpoint = (SPELL_ICON_SIZE + 2*SPELL_ICON_INSET)/2; // Should be 18 - - // TODO: Make a 'scrolling' animation when changing spells, using the text alpha channel to fade it in - // and out. - if(stringWidth <= maxWidth){ - //GL11.glPushMatrix(); - //GL11.glEnable(GL11.GL_BLEND); - //OpenGlHelper.glBlendFunc(770, 771, 1, 0); // Taken from GuiInGame. TODO: Replace with OpenGL caps. - // Single line is rendered more centrally - font.drawStringWithShadow(colour + spellName, flipX ? width - TEXT_INSET_X - stringWidth : TEXT_INSET_X, - // The text is an odd number of pixels high so we need to subtract an extra 1 when at the bottom - flipY ? iconMidpoint - font.FONT_HEIGHT/2 : height - iconMidpoint - font.FONT_HEIGHT/2 - 1, 0xffffffff); - //GL11.glDisable(GL11.GL_BLEND); - //GL11.glPopMatrix(); - }else{ - - int lineNumber = 0; - - List lines = font.listFormattedStringToWidth(spellName, maxWidth); - - for(String line : lines){ - int lineWidth = font.getStringWidth((String)line); - font.drawStringWithShadow(colour + (String)line, flipX ? width - TEXT_INSET_X - lineWidth : TEXT_INSET_X, - // This time there are two lines so we need to subtract the full line height, and an extra 1 for the spacing - (flipY ? iconMidpoint - font.FONT_HEIGHT - 1 : height - iconMidpoint - font.FONT_HEIGHT - 1) - // Note that there should only ever be two lines maximum - + lineNumber*(font.FONT_HEIGHT + TEXT_LINE_SPACING), 0xffffffff); - lineNumber++; + List indexFiles = manager.getAllResources(INDEX); + + skins.clear(); // Wipes the skins map before repopulating it + + for(IResource indexFile : indexFiles){ + + BufferedReader reader = new BufferedReader(new InputStreamReader(indexFile.getInputStream())); + + JsonElement je = gson.fromJson(reader, JsonElement.class); + JsonObject json = je.getAsJsonObject(); + + // Need to iterate over these since we don't know what they're called or how many there are + for(Entry entry : json.entrySet()){ + + String key = entry.getKey(); // Find out what each element is called, this will be the skins map key + + // It's a good idea to use JsonUtils because it produces more helpful error messages (that pack + // makers should understand). + + JsonObject skinData = JsonUtils.getJsonObject(json, key); + + String[] splitName = ResourceLocation.splitObjectName(JsonUtils.getString(skinData, "texture")); + ResourceLocation texture = new ResourceLocation(splitName[0], "textures/" + splitName[1] + ".png"); + + splitName = ResourceLocation.splitObjectName(JsonUtils.getString(skinData, "metadata")); + ResourceLocation metadata = new ResourceLocation(splitName[0], "textures/" + splitName[1] + ".json"); + + // The nice thing about this is it overwrites the existing mapping, and since the index files are in + // ascending order of resource pack priority, this means resource packs can override existing skins + // by specifying one with the same key. + skins.put(key, new Skin(texture, metadata)); } } - }else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){ + } catch (IOException e){ + // If an exception is thrown, chances are the resource pack did not have a spell_hud folder, so nothing + // else needs to be done. + Wizardry.logger.error("Error reading spell HUD skin index file: ", e); + } + } + + /** Instances of this class represent individual HUD skins, complete with texture and all necessary metadata. This + * class serves to separate the logic behind the spell HUD from its actual rendering. + * All information and processing done within this class relates only to the actual drawing; spells and such like + * must be queried outside of this class and fed into the methods as appropriate. */ + public static class Skin { + + /** The texture file for this skin. */ + private final ResourceLocation texture; + /** The display name of the skin in the config menu. */ + private String name; + /** The description of the skin shown when its button is hovered over in the config menu. */ + private String description; + + /** Width of the entire spell HUD. */ + private int width; + /** Height of the entire spell HUD. */ + private int height; + + /** Whether the entire HUD is flipped when on the right-hand side of the screen. If this is false, the HUD will + * still appear on the right-hand side of the screen, but in the same orientation as on the left-hand side. */ + private boolean mirrorX; + /** Whether the entire HUD is flipped when at the top of the screen. If this is false, the HUD will + * still appear at the top of the screen, but in the same orientation as at the bottom. */ + private boolean mirrorY; + + /** Distance of the spell icon from the left edge of the screen (or right edge when flipped). */ + private int spellIconInsetX; + /** Distance of the spell icon from the bottom edge of the screen (or top edge when flipped). */ + private int spellIconInsetY; + + /** Distance of the spell name from the left edge of the screen (or right edge when flipped). */ + private int textInsetX; + /** Distance of the spell name from the bottom edge of the screen (or the top edge when flipped). */ + private int textInsetY; + + /** Horizontal distance between the start of adjacent spell names. */ + private int cascadeOffsetX; + /** Vertical distance between the start of adjacent spell names. */ + private int cascadeOffsetY; + + /** Distance of the cooldown bar from the left edge of the screen (or right edge when flipped). */ + private int cooldownBarX; + /** Distance of the cooldown bar from the bottom edge of the screen (or top edge when flipped). */ + private int cooldownBarY; + /** Length of the cooldown bar. */ + private int cooldownBarLength; + /** Height of the cooldown bar. */ + private int cooldownBarHeight; + + /** Whether the cooldown bar is flipped horizontally when the HUD is on the right-hand side of the screen. */ + private boolean cooldownBarMirrorX; + /** Whether the cooldown bar is flipped vertically when the HUD is at the top of the screen. */ + private boolean cooldownBarMirrorY; + + /** Whether the cooldown bar progress overlay is shown when the cooldown bar is full (i.e. when progress = 1). */ + private boolean showCooldownWhenFull; + + private final Minecraft mc; + + /** Creates a new skin with the given texture and reads its values from the given metadata json file. */ + public Skin(ResourceLocation texture, ResourceLocation metadata){ + + mc = Minecraft.getMinecraft(); + + this.texture = texture; + + try { + // This time we only want the highest priority file + IResource metadataFile = Minecraft.getMinecraft().getResourceManager().getResource(metadata); + BufferedReader reader = new BufferedReader(new InputStreamReader(metadataFile.getInputStream())); + + JsonElement je = gson.fromJson(reader, JsonElement.class); + + parseJson(je.getAsJsonObject()); + + } catch (IOException e){ + // If an exception is thrown, chances are the resource pack did not have a spell_hud folder, so nothing + // else needs to be done. + Wizardry.logger.error("Error reading spell HUD skin metadata file: ", e); + } + } + + /** Returns the display name of this HUD skin, which is shown in the config GUI. */ + public String getName(){ + return name; + } + + /** Returns the description of this HUD skin, which is shown in its tooltip in the config GUI. */ + public String getDescription(){ + return description; + } + + /** Returns the overall width of this spell HUD skin. */ + public int getWidth(){ + return width; + } + + /** Returns the overall height of this spell HUD skin. */ + public int getHeight(){ + return height; + } + + /** Actually reads the metadata values for this skin from the json file. */ + private void parseJson(JsonObject json){ + + // For now, all the keys must be present for the metadata file to work (the only ones that could reasonably + // have a default anyway are the mirror values). + + name = JsonUtils.getString(json, "name"); + description = JsonUtils.getString(json, "description"); + + width = JsonUtils.getInt(json, "width"); + if(width > 128) Wizardry.logger.warn("The width of the spell HUD skin " + name + " exceeds 128, this may cause it to render strangely."); + height = JsonUtils.getInt(json, "height"); + + JsonObject mirror = JsonUtils.getJsonObject(json, "mirror"); + mirrorX = JsonUtils.getBoolean(mirror, "x"); + mirrorY = JsonUtils.getBoolean(mirror, "y"); + + JsonObject spellIconInset = JsonUtils.getJsonObject(json, "spell_icon_inset"); + spellIconInsetX = JsonUtils.getInt(spellIconInset, "x"); + spellIconInsetY = JsonUtils.getInt(spellIconInset, "y"); + + JsonObject textInset = JsonUtils.getJsonObject(json, "text_inset"); + textInsetX = JsonUtils.getInt(textInset, "x"); + textInsetY = JsonUtils.getInt(textInset, "y"); + + JsonObject cascadeOffset = JsonUtils.getJsonObject(json, "spell_cascade_offset"); + cascadeOffsetX = JsonUtils.getInt(cascadeOffset, "x"); + cascadeOffsetY = JsonUtils.getInt(cascadeOffset, "y"); + + JsonObject cooldownBar = JsonUtils.getJsonObject(json, "cooldown_bar"); + cooldownBarX = JsonUtils.getInt(cooldownBar, "x"); + cooldownBarY = JsonUtils.getInt(cooldownBar, "y"); + cooldownBarLength = JsonUtils.getInt(cooldownBar, "length"); + cooldownBarHeight = JsonUtils.getInt(cooldownBar, "height"); + + JsonObject cooldownBarMirror = JsonUtils.getJsonObject(cooldownBar, "mirror"); + cooldownBarMirrorX = JsonUtils.getBoolean(cooldownBarMirror, "x"); + cooldownBarMirrorY = JsonUtils.getBoolean(cooldownBarMirror, "y"); + + showCooldownWhenFull = JsonUtils.getBoolean(cooldownBar, "show_when_full"); + + } + + // The idea of these methods is that everything in here relates only to the actual drawing of the HUD. In other + // words, all processing of which spells to draw and so on is done outside of here. This means that the config + // GUI can easily display its preview without having a player or wand stack object to query. + + /** + * Draws the background layer of this HUD skin at the given position with the given orientations, with the given + * spell icon and cooldown bar progress. + * + * @param x The x-coordinate of the corner of the spell HUD. The bottom left corner of the actual texture + * will always be at this position unless mirrorX/Y is false, so for example if flipX is false and flipY is true, + * this will be the corner of the HUD that is closest to the top left corner of the screen. + * @param y The y-coordinate of the corner of the spell HUD; see above. + * @param flipX Whether to flip the HUD horizontally. + * @param flipY Whether to flip the HUD vertically. + * @param icon A {@code ResourceLocation} corresponding to the icon of the selected spell. + * @param cooldownBarProgress The fraction of the cooldown bar to draw; must be between 0 and 1 (inclusive). + * @param creativeMode True to draw the creative mode HUD, false for the survival mode version. + */ + public void drawBackground(int x, int y, boolean flipX, boolean flipY, ResourceLocation icon, float cooldownBarProgress, boolean creativeMode){ + + // Moves the origin if the HUD does not mirror; neatens the rest of the code. + if(flipX && !mirrorX) x -= width; + if(flipY && !mirrorY) y += height; + GlStateManager.pushMatrix(); GlStateManager.enableBlend(); GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); GlStateManager.color(1, 1, 1); // Spell illustration - this is now done first so it is behind the HUD texture - this.mc.renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon()); + mc.renderEngine.bindTexture(icon); - WizardryUtilities.drawTexturedRect(flipX ? width - SPELL_ICON_INSET - SPELL_ICON_SIZE : SPELL_ICON_INSET, - flipY ? SPELL_ICON_INSET : height - SPELL_ICON_INSET - SPELL_ICON_SIZE, 0, 0, 32, 32, 32, 32); + int x1 = flipX && mirrorX ? x - spellIconInsetX - SPELL_ICON_SIZE : x + spellIconInsetX; + // y is upside-down so this is the other way round + int y1 = flipY && mirrorY ? y + spellIconInsetY : y - spellIconInsetY - SPELL_ICON_SIZE; - this.mc.renderEngine.bindTexture(texture); + WizardryUtilities.drawTexturedRect(x1, y1, 0, 0, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE); // Background of spell hud - WizardryUtilities.drawTexturedFlippedRect(flipX ? width-HUD_WIDTH : 0, flipY ? 0 : height-HUD_HEIGHT, - // The 128 here is a uv value, not a dimension, and hence is left as a hardcoded number. - player.capabilities.isCreativeMode ? 128 : 0, 0, HUD_WIDTH, HUD_HEIGHT, 256, 256, flipX, flipY); + mc.renderEngine.bindTexture(texture); + + x1 = flipX && mirrorX ? x - width : x; + y1 = flipY && mirrorY ? y : y - height; + // The 128 here is a uv value, not a dimension, and hence is left as a hardcoded number. + // TODO: Since the HUD is wider than it is tall, perhaps the creative mode texture should be in the bottom half instead of the right half? + WizardryUtilities.drawTexturedFlippedRect(x1, y1, creativeMode ? 128 : 0, 0, width, height, 256, 256, flipX && mirrorX, flipY && mirrorY); // Cooldown bar - if(!player.capabilities.isCreativeMode && cooldown > 0){ + if(!creativeMode && cooldownBarProgress > 0 && (showCooldownWhenFull || cooldownBarProgress < 1)){ - int l = (int)(((double)(spell.cooldown * cooldownMultiplier - cooldown) - / (double)(spell.cooldown * cooldownMultiplier)) * COOLDOWN_BAR_LENGTH); - // Likewise, the 64 here is a uv value and therefore left as a hardcoded number. - WizardryUtilities.drawTexturedFlippedRect(flipX ? width - COOLDOWN_BAR_INSET_X - COOLDOWN_BAR_LENGTH : COOLDOWN_BAR_INSET_X, - flipY ? 1 : height-1-COOLDOWN_BAR_HEIGHT, 0, 64, l, COOLDOWN_BAR_HEIGHT, 256, 256, false, flipY); + int l = (int)(cooldownBarProgress * cooldownBarLength); + + x1 = flipX && mirrorX ? x - cooldownBarX - (cooldownBarMirrorX ? l : cooldownBarLength) : x + cooldownBarX; + y1 = flipY && mirrorY ? y + cooldownBarY : y - cooldownBarY - cooldownBarHeight; + + int u = cooldownBarX; // This doesn't change, even when cooldownBarMirrorX is true, because it should + int v = height; // always start with the left-hand in the actual texture file + + WizardryUtilities.drawTexturedFlippedRect(x1, y1, u, v, l, cooldownBarHeight, 256, 256, flipX && cooldownBarMirrorX, flipY && cooldownBarMirrorY); } GlStateManager.popMatrix(); // Blend needs to be left enabled here because otherwise the hotbar becomes opaque } + + /** + * Draws the text layer of this HUD skin at the given position with the given orientations, with the given + * spell name strings. + * + * @param x The x-coordinate of the corner of the spell HUD. The bottom left corner of the actual texture + * will always be at this position, so for example if flipX is false and flipY is true, this will be the corner + * of the HUD that is closest to the top left corner of the screen. + * @param y The y-coordinate of the corner of the spell HUD; see above. + * @param flipX Whether to flip the HUD horizontally. + * @param flipY Whether to flip the HUD vertically. + * @param prevSpellName The name of the previous spell. This string will be drawn directly using the + * {@link MixedFontRenderer}; as such it should be supplied with formatting codes and # characters already + * appended. + * @param spellName The name of the currently selected spell; see above. + * @param nextSpellName The name of the next spell; see above. + * @param animationProgress The progress of the spell switching animation, as a fraction between 0 and 1 + * (inclusive). Positive values indicate switching forwards, negative values indicate switching backwards, and + * a value of zero indicates that the spell is not currently being switched. + */ + public void drawText(int x, int y, boolean flipX, boolean flipY, String prevSpellName, String spellName, String nextSpellName, float animationProgress){ + + // Moves the origin if the HUD does not mirror; neatens the rest of the code. + if(flipX && !mirrorX) x -= width; + if(flipY && !mirrorY) y += height; + + FontRenderer font = ClientProxy.mixedFontRenderer; // On this occasion we're client-side so this is OK + + // Position of the selected spell name in normal display, also used for interpolation when animating + int x1 = flipX && mirrorX ? x - width : x + textInsetX; + // The text is an odd number of pixels high so we need to subtract an extra 1 when not flipped + int y1 = flipY && mirrorY ? y + textInsetY - font.FONT_HEIGHT/2 + 2 : y - textInsetY - font.FONT_HEIGHT/2 - 1; + + int maxWidth = width - textInsetX; // Maximum width of the text + + if(animationProgress == 0){ // Normal display + + float xPrev = flipX && mirrorX ? x - width : x + textInsetX - (flipY ? -1 : 1) * cascadeOffsetX; + float xNext = flipX && mirrorX ? x - width : x + textInsetX + (flipY ? -1 : 1) * cascadeOffsetX; + // Don't ask me why adding 1 to this makes it look more even, it just does! + float yPrev = y1 - (cascadeOffsetY + 1); // No need to account for flipY because previous is always above. + float yNext = y1 + cascadeOffsetY; // No need to account for flipY because next is always below. + float maxWidthPrev = maxWidth + (flipY ? -1 : 1) * cascadeOffsetX; + float maxWidthNext = maxWidth - (flipY ? -1 : 1) * cascadeOffsetX; + int nextPrevClr = makeTranslucent(0xffffff, SPELL_NAME_OPACITY); + + drawScaledStringToWidth(font, prevSpellName, xPrev, yPrev, SPELL_NAME_SCALE, nextPrevClr, maxWidthPrev, true, flipX && mirrorX); + drawScaledStringToWidth(font, spellName, x1, y1, 1, 0xffffffff, maxWidth, true, flipX && mirrorX); + drawScaledStringToWidth(font, nextSpellName, xNext, yNext, SPELL_NAME_SCALE, nextPrevClr, maxWidthNext, true, flipX && mirrorX); + + }else{ // Switching spells + + boolean reverse = animationProgress < 0; + if(reverse) animationProgress = 1 - Math.abs(animationProgress); // Simplest way of reversing the animation + + float xPrev = flipX && mirrorX ? x - width : x + textInsetX - (flipY ? -1 : 1) * cascadeOffsetX * animationProgress; + float xNext = flipX && mirrorX ? x - width : x + textInsetX + (flipY ? -1 : 1) * cascadeOffsetX * (1 - animationProgress); + float yPrev = y1 - (cascadeOffsetY + 1) * animationProgress; // No need to account for flipY because previous is always above. + float yNext = y1 + cascadeOffsetY * (1 - animationProgress); // No need to account for flipY because next is always below. + float maxWidthPrev = maxWidth + (flipY ? -1 : 1) * cascadeOffsetX * animationProgress; + float maxWidthNext = maxWidth - (flipY ? -1 : 1) * cascadeOffsetX * (1 - animationProgress); + float scalePrev = SPELL_NAME_SCALE + (1 - SPELL_NAME_SCALE) * (1 - animationProgress); + float scaleNext = SPELL_NAME_SCALE + (1 - SPELL_NAME_SCALE) * (animationProgress); + int clrPrev = makeTranslucent(0xffffff, SPELL_NAME_OPACITY + (1 - SPELL_NAME_OPACITY) * (1 - animationProgress)); + int clrNext = makeTranslucent(0xffffff, SPELL_NAME_OPACITY + (1 - SPELL_NAME_OPACITY) * animationProgress); + + if(reverse){ // Switching to previous spell + + // Only renders the next spell and the current one + drawScaledStringToWidth(font, spellName, xPrev, yPrev, scalePrev, clrPrev, maxWidthPrev, true, flipX && mirrorX); + drawScaledStringToWidth(font, nextSpellName, xNext, yNext, scaleNext, clrNext, maxWidthNext, true, flipX && mirrorX); + + }else{ // Switching to next spell + + // Only renders the previous spell and the current one + drawScaledStringToWidth(font, prevSpellName, xPrev, yPrev, scalePrev, clrPrev, maxWidthPrev, true, flipX && mirrorX); + drawScaledStringToWidth(font, spellName, xNext, yNext, scaleNext, clrNext, maxWidthNext, true, flipX && mirrorX); + + } + } + } + } } diff --git a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java index f9a2b90f..5b50eb61 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java +++ b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java @@ -37,6 +37,7 @@ public final class WizardrySounds { public static final SoundEvent SPELL_LOOP_WIND = createSound("wind"); public static final SoundEvent SPELL_EARTHQUAKE = createSound("rumble"); public static final SoundEvent SPELL_FORCE = createSound("force"); + public static final SoundEvent SELECT_SPELL = createSound("select"); /** Trick borrowed from the Twilight Forest, makes things neater. */ public static SoundEvent createSound(String name){ @@ -65,5 +66,6 @@ public final class WizardrySounds { event.getRegistry().register(SPELL_LOOP_WIND); event.getRegistry().register(SPELL_EARTHQUAKE); event.getRegistry().register(SPELL_FORCE); + event.getRegistry().register(SELECT_SPELL); } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/util/WandHelper.java b/src/main/java/electroblob/wizardry/util/WandHelper.java index a98788fb..f4a01a04 100644 --- a/src/main/java/electroblob/wizardry/util/WandHelper.java +++ b/src/main/java/electroblob/wizardry/util/WandHelper.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Set; +import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.spell.Spell; @@ -116,50 +117,82 @@ public final class WandHelper { return Spells.none; } + + /** Returns the spell after the currently selected spell for the given wand, or the 'none' spell if the wand has no + * spell data. */ + public static Spell getNextSpell(ItemStack wand){ + + Spell[] spells = getSpells(wand); + + if(wand.getTagCompound() != null){ + return spells[getNextSpellIndex(wand)]; + } + + return Spells.none; + } + + /** Returns the spell before the currently selected spell for the given wand, or the 'none' spell if the wand has no + * spell data. */ + public static Spell getPreviousSpell(ItemStack wand){ + + Spell[] spells = getSpells(wand); + + if(wand.getTagCompound() != null){ + return spells[getPreviousSpellIndex(wand)]; + } + + return Spells.none; + } /** Selects the next spell in this wand's list of spells. */ public static void selectNextSpell(ItemStack wand){ // 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades - if(getSpells(wand).length < 0) setSpells(wand, new Spell[5]); + if(getSpells(wand).length < 0) setSpells(wand, new Spell[ItemWand.BASE_SPELL_SLOTS]); if(wand.getTagCompound() != null){ - - int numberOfSpells = getSpells(wand).length; - int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY); - - // Greater than or equal to so that if attunement upgrades are somehow removed by NBT modification it just - // resets. - if(selectedSpell >= numberOfSpells - 1){ - selectedSpell = 0; - }else{ - selectedSpell++; - } - - wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, selectedSpell); - + wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, getNextSpellIndex(wand)); } } /** Selects the previous spell in this wand's list of spells. */ public static void selectPreviousSpell(ItemStack wand){ - // 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades - if(getSpells(wand).length < 0) setSpells(wand, new Spell[5]); - // This cannot possibly be null here, and yet I am getting an NPE... + if(getSpells(wand).length < 0) setSpells(wand, new Spell[ItemWand.BASE_SPELL_SLOTS]); + if(wand.getTagCompound() != null){ - - int numberOfSpells = getSpells(wand).length; - int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY); - - if(selectedSpell <= 0){ - selectedSpell = numberOfSpells - 1; - }else{ - selectedSpell--; - } - - wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, selectedSpell); + wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, getPreviousSpellIndex(wand)); } } + + private static int getNextSpellIndex(ItemStack wand){ + + int numberOfSpells = getSpells(wand).length; + int spellIndex = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY); + + // Greater than or equal to so that if attunement upgrades are somehow removed by NBT modification it just + // resets. + if(spellIndex >= numberOfSpells - 1){ + spellIndex = 0; + }else{ + spellIndex++; + } + + return spellIndex; + } + + private static int getPreviousSpellIndex(ItemStack wand){ + + int numberOfSpells = getSpells(wand).length; + int spellIndex = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY); + + if(spellIndex <= 0){ + spellIndex = numberOfSpells - 1; + }else{ + spellIndex--; + } + + return spellIndex; + } /** * Returns an array of the cooldowns for each spell bound to the given wand. As of Wizardry 1.1, this array is not @@ -210,6 +243,28 @@ public final class WandHelper { // Don't need to check if the tag compound is null since the above check is equivalent. return cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)]; } + + /** Returns the given wand's cooldown for the spell after the currently selected spell, or 0 if the wand has no + * cooldown data. */ + public static int getNextCooldown(ItemStack wand){ + + int[] cooldowns = getCooldowns(wand); + + if(cooldowns.length == 0) return 0; + // Don't need to check if the tag compound is null since the above check is equivalent. + return cooldowns[getNextSpellIndex(wand)]; + } + + /** Returns the given wand's cooldown for the spell before the currently selected spell, or 0 if the wand has no + * cooldown data. */ + public static int getPreviousCooldown(ItemStack wand){ + + int[] cooldowns = getCooldowns(wand); + + if(cooldowns.length == 0) return 0; + // Don't need to check if the tag compound is null since the above check is equivalent. + return cooldowns[getPreviousSpellIndex(wand)]; + } /** Sets the given wand's cooldown for the currently selected spell. */ public static void setCurrentCooldown(ItemStack wand, int cooldown){ diff --git a/src/main/resources/assets/ebwizardry/lang/en_gb.lang b/src/main/resources/assets/ebwizardry/lang/en_gb.lang index 17165266..79eb401e 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_gb.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_gb.lang @@ -710,6 +710,7 @@ config.ebwizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit config.ebwizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist config.ebwizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist config.ebwizardry.spell_hud_position=Spell HUD Position +config.ebwizardry.spell_hud_skin=Spell HUD Skin config.ebwizardry.cast_command_name=Cast Spell Command Name config.ebwizardry.discoverspell_command_name=Discover Spell Command Name config.ebwizardry.ally_command_name=Set Ally Command Name @@ -746,6 +747,7 @@ config.ebwizardry.cast_command_multiplier_limit.tooltip=Upper limit for the mult config.ebwizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). config.ebwizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). config.ebwizardry.spell_hud_position.tooltip=The position of the spell HUD. +config.ebwizardry.spell_hud_skin.tooltip=Change the look of the spell HUD... config.ebwizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. config.ebwizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. config.ebwizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang index fe97b0ae..449313b5 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_us.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang @@ -710,6 +710,7 @@ config.ebwizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit config.ebwizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist config.ebwizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist config.ebwizardry.spell_hud_position=Spell HUD Position +config.ebwizardry.spell_hud_skin=Spell HUD Skin config.ebwizardry.cast_command_name=Cast Spell Command Name config.ebwizardry.discoverspell_command_name=Discover Spell Command Name config.ebwizardry.ally_command_name=Set Ally Command Name @@ -746,6 +747,7 @@ config.ebwizardry.cast_command_multiplier_limit.tooltip=Upper limit for the mult config.ebwizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). config.ebwizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). config.ebwizardry.spell_hud_position.tooltip=The position of the spell HUD. +config.ebwizardry.spell_hud_skin.tooltip=Change the look of the spell HUD... config.ebwizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. config.ebwizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. config.ebwizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. diff --git a/src/main/resources/assets/ebwizardry/sounds.json b/src/main/resources/assets/ebwizardry/sounds.json index 649770ba..42258e4b 100644 --- a/src/main/resources/assets/ebwizardry/sounds.json +++ b/src/main/resources/assets/ebwizardry/sounds.json @@ -35,5 +35,7 @@ "sparkle": {"category": "player","sounds": [{"name": "ebwizardry:sparkle","stream": false}]}, "wind": {"category": "player","sounds": [{"name": "ebwizardry:wind","stream": false}]}, - "rumble": {"category": "player","sounds": [{"name": "ebwizardry:rumble","stream": false}]} + "rumble": {"category": "player","sounds": [{"name": "ebwizardry:rumble","stream": false}]}, + + "select": {"category": "player","sounds": [{"name": "ebwizardry:select","stream": false}]} } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/sounds/select.ogg b/src/main/resources/assets/ebwizardry/sounds/select.ogg new file mode 100644 index 0000000000000000000000000000000000000000..cf9450ce8a1f85215e1564c1cae2e920968f192d GIT binary patch literal 9316 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

AAR*B9qwt{};Vu%D*0zSZ4d+_wy{~qQ|_| zjaL@1?7Y=*r{;5x-j`YiJ1*Auo2%O`%j1?TQQhWM`+wt||8~dpRKDcDj`jLceQ+w< zKeL$RISjLIKT=)I^Lp`@jF;E;i5gt1Ww`gjOW$phfLoC=m;B#?-}l2Al7*i+2;0~x zoVg@^N>+aHLahn?fes9R#T-8JN^+fbnJ-Z`N3)@MhyRb{i|he84kA`t4fOpgB9nZaowC3C>et&{b_9kK5`9PKRU=8AvJIrVU@f%OEIS+{>J z=Wm_0BqH`#(y|raO#8&7Duq6TGas{H+>tp=_wGHf-5(v79^QM~v~u+yxl0j_&bF1_ z2erT4i+T5O%bx?)za=;;%9%cOmh%WTMC<)pe7UiG{h{a|KNqeK|6>(CH|V+b60axB zGh%eR{9e~MNiee*%<{31=bk!^<4@=ULl1^LtAds0EFTT6IBvwVN;TUxOuWT?@A$W5 zP7%NJd;IPtT|4;9qN=vXiAloubKd+8umAtNw{ksMY$6f*^1!=g{rmJ2o;=`X)%Q73 z6yA2n?qlAmmv`p~|9Z?Bqx9jJctv<)+bZh^-^)977|KNxwq(ptQe9Y+Q@y#~WDV0# z6@yP7E;k;xXuEam_Hl`g3~td19rD};n>51O4<46LYPcxG@u+R_ug~@K3u=257;@)rn^-~}dQ^9h^r93Q!UX$EwjU*g<#MC$RUrGpB%Dj7j`>yu>Tz96WZTIgl zKENcw`|`lMzxL;f7T6bTyAvg)yHi2;?ydNLx~hyl%Ss+BWP4gLzcwlI|7MxZPZgty;Z$qTkG3B&$}lc54d&i__M=XdG@^Dzcl*!{o0kR7w+?4`p)=c zVuNZ!wCt~KM^8?&Z=db@;`{#-j(y8=7v7a%sgKN0x&JdGf>T1v_r`HEHHP(^@m@O& zIsR?Baw5q@li~jLU?!%5?&dx=-zUj$4srhZw7g!~k74mqmM>cy@>zdKRL*FP`w_(F zbe}U~*2?MqhVPgqd_T0-KUp5P_#l%^mOq#L?Hf!IzWk4uGxyuLb+f(**VLQHY7n)p z<M8pnc6z=-@@<4L+tB^Gco&ACe4HpmX;QbnCFZ)Ay%l%6w4=yG# zioJ7wn4F?;r%9&H>ch9Yb>5d7-GenYtmgRh^S^{j!})iza#J*(EN9ODU6SyNu)f;^X5`~Sty`ffLC-f@0^IY;hFhcVJgP~ewL4n=Zs;F;iKDgRm&#g=}{PNK^nIwF(*F{TlJQ8lr*Zq0pTrESKcfyLP z4EC}Wua`6bmbfipderf5j)A>wMat#I+8-okZ@Ln*Tm`f4;u+(IRQa zA1Bv7SLT&oa;pBk_qjd74btyyWfkW(-I8(nm%M_O;9DGr(@G1hcE8|vxMg$Ks&(=5HSfed zoHrJ@CjZ;4{${JlL}8Uo4Y``93V!o`*Yw%U`S#teHe}yl$>X{X5?1x=t^a>xJ!kp# z-kc5APCs|s&zYJ3e{KGsvW9?r6_>aFJokOwdD-H3A2-jBo0k9o{`Efsns5Jnj;s9m zHKy{itL4Gcb;UQ$^UiMne=|1y>Fp$qebuk--uZGsljHESU+eA9scx^o`m-*eY-W9+lFlpU83HNhCm5uTDQw>)hJM)|Q&I*_J|KA;8ongN`?S%fO z?uzq*GR`0C()=09)>o{JpZ)yY-kZ-de*cx8Hzj1+DcD+ok`oRZaX$;}7~0SLbHArm z!20KAxIg=Y6VC6QyxgVrtG>lNuk8EF8x+-Nc0N*p|L@(4-_++;`TpDY{r}7340Fof z@&D3oxbyXY#cAKZ*20gKmWwXl`FHs~^M|k6`=3PUUviU@Qp~L@J^7cR=JzvUgCduY z-Jj)UKkfa|^gcO)sh~W$wDsQA9p!r_sAX`eba9p@E@{|T(bk|iAxPLnmC-ptg2|aH z>safHSEm#N&fLn?dU&EDY<*s0>}fWg=*0plI==q?bJp-4H{k+xj9nP+z0se}Q1|!o z?TWYm&pqigZCn(eWRWDH{XuA{xV}j(o1*+j_g(#u{0=0Yb}rvDK{12NXQkniCEL}H zu9<0?GFkG}p{50zoUAHAlYZ;2Sl_*1vstLeYBp(!&S zYrTBY^U-B;+V`sB3nd56a(@4%^6l@V$ODmwYkJoi-k<24SrPxEmdBgn!hW6SN(l}J zL|AwmCn`7c>e`;UnXV)~%RDeTwl9;*hjW?YiL^^sdbO4B&Q3b@#7ZjNH#PL~X$dPw z*O{Kzf>?~2O2iz5xj42I{QGA0N9xsL=0o-7*At)4-fmZuqsS>!;#2+io0E#-u9*!1jleE%d}Z-U%ch}!^gtE z8UB4Kn&xpqu&Pr@Mr2Am@2SI0uTB+xyHTulckS8`SLYd*j)`z7Cf>^1ePP?KR{c4Z zQVVZM$^E>%Sm)<;=`U&`GuNn147=jDYJvK+)UU7Xtad$4(K)+CtGeOq!*#*@s()IY zKE?!V)t~uYZun5*-R9fXzx#i!;g@&iTu>nTV4t~86I)0)yF|FG!o|sIQWHa_d8+mF z3r(5T%y)NwPPp|})2Ah6IZjfUY9?>o3}&aT|G$f6miXuG_O?e}ZOuJ0$!u?}nen$f zGrzvBu2{cv^1YTttF`@%R?nQJ+;HgWekY+DF}#*yx(xT7K5RV7@}QSFV@3a`2eZu> znVlFlxV@jfF=m{*)wAU248yHmvsNi6W^TOyuiaqhwI%Dzg{7@;bzCzw%6(;#VbgoX zyL{t=iRv%BHLHZodfDF|e#{-WP=9Hss;F(P+1$H@L6K*V7-{e43fS@I`T4iCKW=QB z&^(7JC_#!T*y|AE$+oL=S$GdBelAmAV7e@I<7L0com=<1@0_@_?*82wJA-*cMW-5+ z+HBB&IJ5LhDC-IxV~bZyey)k!HfPtYqEm+$PdQE6G~vhuCe0%X>I?Yg?c6SKMpP&S z$t5P$>TV59ZAoF%zUsScegC{|r9Ss_tx}h@-KaYD_EN)&`Mh6)Ioq{3Psb|OFnus8 z*%lNnn($3fUFiOmBaFY_AH03~y0G__$$r)wnH_^Cocgw&NhJE;=ZA-no2fM%S|Y2- z(k9T-tTtKgib3wFIG?#8zNL~JcY7ykE)uPt82Q^KtXy1;-TCXp13T`B^1Sga{AN|7 z7b1Bj{Qarh>(@F&X8NoY2omP=U|Oc~VxfG##-{v#zdsl{u>`Cr+&t4{t@O3YJu_KK zY=d8|Ua^A5sPuUjQ}DN@E=>p153wFL>{_fvbDndtC!Eot*I6~nCj zE{L%BHutPF;8K(Scjtb4zmR}KqRN76J3q**&CJbCKRJoduHt&iH@(s`_EmaM+5MQC z9Au}|CU%@wYnZxWU-P*iYR7zUPW@$jT=>2Bg?%f#*UhsKHqTkK)b?20_gR1AK0I7J z#f~9gWkIGF(=ua!b6@o{<{2Kltg9;?T~wd(=~a^26_(5!-wiTsim8NaEc|mUZ>hp^Z&HwcKLtqrshei5g>Jh@OUd)XS9F3Ql z)-oyvcrBiK$gJ$}i9L)5Go538WiYwdv@!QZ9A@kkuXw#Nz2e!;?Se{vMib9ON;4I) zJWyk@?6m!7a-h9mP_f}qK!U2m#p~{&l~a{JLF z;;+_m^auzrl{IhDd}CQ{pQZlh;HhVPah1uI`Fr+GdgpRn!M-70@x%s+99%Ee!EBX8e2c3-}x>v?>|)Y7%GOLUn}w?!Oh(>h$ovVdP+Rk5M-s+!~G z`3%#x-#T$8&wg2n+3y(^E4%J~n{}`&_5J33m8`n2%`V)$<`(MPvFT;}`OJUnH$Gg6 z*Vr!Hac%oTFCm@TM`!=9YFzh@MfbJ!jGfncf+D*^SDSClJM0!^wk0?%BBYJA+V5-Y z{r3Ke#}))6EM5r|?%qZ4)eJyW^^|Zv7ueD#i@!IfO?(3Dlev9bVpC2ABF0pHH zWLa=9Oo7L9h0THL)7G7CJX%VV*2QsaFTVNv$l{9UTeq)Ru~Ol48vns#EGNI;PmQf+ zTl%2Y_5T8$sKc+ON@u>U>7V)g-Qnc_HGL76)CBlGJ-j86b|K-;4}~Ltd`#u-ywVt- zI5%z;o<4u8W2U3l(ib-~6((`VML|M9^vNX(&5RKcBL9czMR^vlVc4tQj<%z9~jd~@Diw_U$Q4xTEidc?+g zI^`#O?waWRjS=g6Q?sM2!h|Zex9;-%s#E!kgIy~79Zn{Z3i})c5az`ykE2O>(#VV$ER-o^3`hHPW6z`SX!eh22Z3D-LXScO8@?I{n zUe}>2`fF)KJ5pizT)xsQBN$<&Q7+5Rk4E55j$}MglN4q_jpXXbDbISS&Z^CTF zE~Q=EmB}Duy_qxfhTqd9XT{dDP20b*K3KvWcP>0)-+$NTLZ4U8uRFD}=1o|Z8KSGT ze96wl;@^9hGk(~re}Ag}L%pK;zrVge$NXSX{{1QIH`E-~pW}6Add#=U|5lxD3ugVb ze0nVNfv5KSE$ZiL>+KS3n183r?oxr4?e6=ZCmFwIdC*qvFCXwI_Q@)*`q#z$j2~{h z&Of=oe|_Dn%&x1~SlrfL`!00goiOuXmItCG-?>Gnaeohcrz?^c{vp;#V%3`O0iikN zTb|nMGfv5hddl@b;P0!q`!)AU7d<_b+mg81%3^Np7j}i*d3kdWT?`KU&b?$|#EwOV z|8EL^i+VLB>OAM$=Jhg1P8QEUKe7GtzkAF3Pi?n;8E@uI~OZ zMnlHMu^;x{s`m`eQDBt06k+IadUumez28{|#_#8DwhI-lcc?yGef*Tw{_T%~ytk*- zPXE03ZqW<LG7DYB;N2?sx!mZ~i1skL-sP(Wy?@7EnsR%WG_?p=JU z63potUfy%;jzr1(;!g)nnb&MQRQHwd%EP9pGQszjP01Sf&cES2@J@97*X+-CcADRo z$=zRncru?P$5CzhbLAq3-qb%?%M^ZKe(l#1hCZ7wdP_>Sd|Z@%zVz6ojr$$FPG5Xx z$^B&Ee(PKRmISXqdH?%A`@a$mm(Trm+|N2;_dogkohLUM=-KJJo6Ndh|Ero|U)|H` zGOt~4c{nRCIlEqOr+h>H{Te2>K8?D>O;`0bl#AW=_vywRhu-(~It`YF!$ zooGS)345t~v%2*dWh`tDED~jGS{7Vh=oBlVxj=uOVgkpKD=faA2MWHWm@HY47SpkA z9S_sNHFuW@_4TBGeI<5nYtDg9rd*E4E`9lO%VvJaWZgiV!W##9kJlB;EQ#MzGd+**sWXl6d(39RqGC8;hdH5%xm5EZ%byFZf?sl za*m7;Fi~CD;Nn%ZpY?00V9B**s}@aS{+_?!HOWpS`)}pm=fT{okvCU$F^hcz^#U%@DHUFS|fP_O@oLO#wD&MsLg9qzWv{OFXE zr6%WQom#bQx?xFEm(k=kOF2?lUg|Wci3nsE-VhJCu|C;#L%YzYLofXoPTT)#$}Yy- zJD;s@)lF?T3H##CBzEp)?ZW?04!u8Wyt;{nmqQ{!>Rg`p#0d%_0tu-%i_gz}`Syic zf|E*yfQe#)%S@|Gna;krW&SG@W0tg?v<|&|NoUTAGd+$6u5?UM5-{61we#K9if7J0 ziuRVXDu5Q*Cr6#ws~vc+?C3Jjv$-Gth@A6YU>(G=V7Hg~0)rEOEKTd2&V@NGT&dft zkid1wG5w!BAJ?hFY)=y#=WbiMdacR?-vCkGL@()Jjh2?etAT0nVh(ev%lfU@)^^Lh zDa75kN|-A+Ye~Qxo3*p%MNHc_!}n0n;)~7m76+_;>!DV?@#n7Xz7JPToj&L8_uv&z zV;_|)_jCUG`diYk>b1Wd?HJate3krqfx!_g5s?{eQ`~)zg|d5mS)$49t#wLe>s7V6 zudf$gSonML+pOi=md!cW=j);D>zg{|*UifuXXmh=?e;u+Yh~xG8EwA#^Uu!v?VtSj zm)y0SSEb(yMJC7|65psi;eh+mN7bxVE0SB2?^^q6=LGxcd2L+t+w=L~R+pD`{Kf7k zv!rr0c#f8uMYQ@{S`@DR4A$9Ov6d?!SaeD8TkAL5|10{eGky8Gcf-cTy&0iXGJ~ZX z1Xg~1y)ihpXSIPL&p}7`x91^UJx*2?$6#R&jyFnm9kRK6(Wh>3ZLfDO4 zcKgdIGo_MVOK$gOUQ}mx#a~rsm5NSz>j%yQr!U;}$_;I}=|0D!CRmvL&3^WL{dj+! zi+)ybkMObhI%=(EFZp*o_TTM!1rNS3l<)7_ymW3*-vjMdMh+RJg6;dJ?Yyq!vQA}g zScc*SFU6%UujhPs(bUpjWV26)k7-{~MM}fbjk@=rKI8s*Kw*!Q?)zV#x&A7*hAnuR z{Xe(aiC3}pfIw5hg_KJzQpV9CmA3Qc&+n+x46mxTX}b z#A>Gaec*M_=$$yZ-1D5wg?Hyf`<`8A+Oo;fcXH)2M zdFR|Z>p2su!;SX5ZHqd2qc$m_K{O&q_3)e+-I|B@k9~G+$Wils-S$-_S&cFF{FGl> zT3XFMcX!S@FlFz8B(4D78gZfXjb4p1&vzbTlqk+;z1MUkc+0+jeA!{O9aH;+O;{Z- zDjcjv#~v~*&_QQvQkhhjX~ZfB_;&RNmFsm6J_{>Es@)`<;P+r5RN zF5kL#Zj!2O&4+a--^9L}QU4|86#pDHmPRX$--iUkeHpY9YuV?1^zE6wN&9PcpZdM& z3u=SKV{Hr7@@}|zSMz-7yS}_to8kLDHGx}(zh#5tlQmi!)fhs;T@1G#x*(+}Bc#zk zjalIJ>%-S>C9*D@XmPorp<%&=8MoZLPo^*@9oVbCWXF%s7x#Rq7drbswoTfvvge3b z8z{!v-+x+_X|-EZvh9G$T!Z@y6koo3^RUx>e!{8M-7^D(mn7alyx?O^LexagFYIlrr`|4}1zTSLanwO?bs zGG`vUobciivRGVa(y?FoRyOj_7L^!5=U;SjS@=p1;8UGeE2+V5O#F^nL z!NI|iF(F8y<=7Oqiwqu|i3>Yt&3b?J)}M8U6PDlkH_dp-BF{{ny>D5z7pOkocl4@< zlS{{Jo-?$s+Cnp8y9v3!Uow4nnx<|(nqXw3{TbRW%Cxrxdo0(iPo4NV>FUIeh zF(*HiKe^L(>pnN(v4bmw#ts%R?p8j+uw&=#~-9`5zw;4}ja6ca%TB3Sby+N>u$;ytwQ|DUyLSC&?+MZu-ZrQHB;Sihgx0$X_ zHW(Lfn^48Ig7w?U+Fi^Q;yuisHlJmqlG*l3Hcy+XJ;NYXY;xM0Cdnx-rxu-=vs3%x ztGEsKZm)XwDq|}{%-eh}_aDts!FmgvoK%~*6gyKkyYM=;Dso5)n3*1IP>^Y`%~rg? zTQq0cR?%f_4;QXE*dDdX%`=I^sLRnaESh_Ame0Gmm`-0I58(p}&Azkd$(-~&#Qbl%z3Kn-ME&uwo~Qx=1iZ&;tL<$gNzHA_I&rZiZTn>`THizsW9iOBJCVj zdF{7^8^bkk|Gpntef{f-PjgqywCcY4`gX;G`R6xpH10Dx-5GKv`DW39;+}7z4NlEb zH9SlcEFbb`_zL*$6bX@><)P-dmGLXv71sqpS*w@@3{4(3B&=^Zdul^U7K01Jp~M*$ z+;Z`%7W+>Yx{_0&mS84U}(HoAW;zVhyWa)Rs!6X|I-UVrs6mu%%+ zW@3>2?s?^>h1CjIoNq6asFuHS;?vW!dv@k9?|r??Bh`ern(fnEn^~>@wH{=xpEhn%gRv^d@hQ$TTjCgZOU!C$=~>AcdidUDkrIb| zdGKbO9h_bA>&-e9Ju)1R#qQIrSfJa3PIccN3M(JPMGqlb2-WGaoFki*3L&P&{rjKRm zlDVebS{Gdo2X1LATBK4kDavwUlx63%H(FLNRC*g7dGBT^2lvE!3aMvDvFLd6xSEzO z@m#b-SVQ$i`H$TyDzz776q!zh#)`G6gvdSE`*g0!`re7>GImwz-ZEP@!|J)hy~tg2 zT<)_O_wir?|h0BWTC1#V@%{{|8)`=eyVIvs8d%&f3d93+_zl z;XmLRI&1RsjA#B$mZr11<|^1Y9_C5lzfj7g=n!IgePyqc6`!tVg{|g|DWzNX&s|;g z)Qzv2wIX{hONNPUjaf!oh6XdEKU(sH`mHsbIP=-QmeLl_BDSqpF1uQr z&AOK(o*nF)kr=RAovBG+tHcyRm7YstT&)ik8NOTpVA;?ckfD^8o6a@COVi3M)g#Sh zQ2cy@fR!UZhUjvu8?QTzB7$qsQjiT}tb?sylZ} zp3mnS_Tt9X_uVFCp8a)=WoFN^l$~bf0*?=E%ph zJKsN*zr0ba)xqoG55^)#8$ss{n^$rkYt*?hf2xFdvxQR6uV;2IRtis;U*2-PO8(5p z2`3IL3Uka3x-?PnNUqHB`QApZ5t-gijd6btBt5*ej&Z(ehd`oI(2OaZo~%s^3}%Yn zn*Qw;ZY*2PaF6kI6hqiM^;ActwVq2%zFPOE-`&+)@?EoO>eDYrc!j2&{KS8& z;`?9ToL5^j-*2mU{B^2M)Q%aOKAM`Wf2}YrWY5+d-pkVJlTKy)nq;=oj{Ee#lv^)9 z<^G8KBDQVkpMAZ|tKKnu`S#7qDMex@i+rOQtN(1ZT3(@Z%*)QZy!{#Z#r(hQt6PbM z>T3$$2~H5mXfwa=SS@6A`NDFROxAPSB1eiA9(Kx^o!TJqb;csDg`2Oisujk(oo;A& zGhw~T;-D?5*95m$-I#Fiz^yM_K1y%oELv_J+n+dbQQO=V%cjk^d%XSb`$Y*x>e4h{i^jlW%1a39=dVZ&+C z@K0Su7p6`L86f%H%r&Q>~8y7 z(Y4pIlEU<*BfTdW@SaKAb+6kf)^q#T&ZpmYyR1+%rOH-5X%&xp;hott;b7Y}9x=vy zHPx(Vb?25G7u~o-Xd(jz|$O0EA_Rf<}lpW)y?-;iPU+|Hz6WH z$w)deS7_Sy1<|(z*GJuu)ZlMCbD&LROS+0|q(_!#7`G0u)^_uTvXdvBna<{Z)a_dT zLF`FEU?RsUCdO~P^5^OvDhC`|)b4jHL(yf1*D=G!m1~|dhka0!{W4+8rkq8sez$&@ z#HVN(|D0gDBy`e@SBgsxdoXDPrEC=7$U0KN)WYT)%p32somce13lRneaemOb0Ed##E(y(^&)Ed~;2G-zR2l4eg=a%`JX`Tm zwU^%A(=#4>43;sn7-=OSddF9aniTa=Ww z%-hGKdv{g@SJ;-wXq7+fLdCot*Ay#pctq8Hxp_AwWRl)pzXk=#O)fJJR4g-Uu6?O` z&@1et6}RW)Ge>zmW@V(Mt1(}YxYNG%8+*y6&Q2xoE~&`lju(F(d81c0ckjG;`*@}% zI;KYa2yV!I$^0RycKXqizga6De2rVBb!bYf^Pc^SCcj$cmEL}T$s+T43)h8Rymaf} zE7RPP(o)5uD32#Lm!twNDc!tux~22!nn>B>VG}l*)JkujQ=3r`aC7}z*`wRumDR8^ z6-ie{L``I|+O$EBbK*ArJ%^S{}GRtH5kUuHW`jSbtM%o8$;%C0J5&v2Zcr9OA|@%IN~cC|WXoUC56WR6r- zB;S`0|8HAwSFl|7sqg>3%f_3HcW*Y&Tsk$SQZ+J6L^}FN;ff=EIb2Q2K8&IUB8sj; z3QD3(`HEBb+<1E9{T@|O4I!sb69Oz83N+3f6-W_hiSO8XWLt{z$xSWgTW{UIlfLVB zP34PsH|O1(d-dq0Q&Ds4uU>msHh=EiSu@|)@B4iBUt)~r4;lX=?(YE!6SiGX3$B}# zc3i#P=zxLms-EX+mT~os+pbk_V$fqN;M}-L$Y595`}NNoC*Ltl%2p@Pendsfb#q~V)oNjZTMfR#3B4Dx+G~D%OY%RHsJw5UXY%DwjMo~p zw7fDF@`kK6x*O=jD`&@L?R9AH&k4tuvFg0}I#oF|@tU|8bK*&^s};}ll}ZGx4%94_ zl4W#RWY^Fw!V)7m+3;fYosYGzb{%2b%wy=*Xy|8fzJqULbY4=>`ls17)7Cif>wMT> z(`;U3?wr`S{B^(KaZRrtqvM{(QjDv)_8&U^ue&5;eMhPV(+(GpaHcq8wL9DPmopqW zc(UY-wdQ3RpMO%@I09^{_tb>jb(MYPw98XbiF3Hl+|g@ncx9U#v#pPW@5c|$GqN?0 zKVnk|tT@JX)?r2TifHH9g}n=4I7^GpC!^H1oB4T56WTYP ze(R&hy+Q88HO8DL%jSHw3R)|XJ@w6nRV_?zHdd=lSWLG3;PMXB;1pzB5NH+F+Q+qz zE4Q<}HaSE2%=K3#DyLX(9QoUSCF*)jy}rn*fXu5OHeQKbaz;bWxo5WKvAu>SJQ9~Z z*-9Iq{}O0el#^=AEyG&FBdd1ftY1Dq_s&Q^)4qjCoLASKNU>mwXt!|KmZhV8e4gCh zxl@Jx@2&W9XM4^xMeVEej=9ZXoRG`xC(p>T;aZa58kc<`x1$aSL@Zqx*x!(Ta7hu5 zVp~9qLkq(}_ZjQ2eN2ALAAD@SEmO>yg$sDaD);?0zEz?TkkpjRb3!2aUg?&zI-$`^ z6WV`R-cOh`_l(QKyH}KXHuu`fJomI=nJ+c_#+jCx36t+0+_I;IVWAe|rX=SgmJNLA z*S9q4vA@XDF58}x7k%r*<%8?DrtCG}b?^S)_*qXM%w2k~)1i>T!0?iTDcAHPkM}We zWpTKzXU^*?x3{FZI;#S#|&Qbnk4~*>P8-)O{r!D=0spj0v5HoqcS2U^~wUbFX``q; zo0Nan0`L|lV|q4bF+4A z%hvoJ*Xy+}^KrcQRkj5|D~*hdWH_r-6t7n7+wVTb@?%55G}d62g+Xh}4zItPQGZH1 zV4~c?32Q#auP~o+E`=ko%-!&bVT8>pog~TUE&E&=8{Ya9&AR;NS-9o7{~v?pmY-3v zJN4M+*t$Pk-z4f^`#$4?+RCR|B72miH0n0{I={M-c~Q+}#cqWMPkZ8)vs(Q!eKE)T z@j17`m*=l%Y-0I!y0xMIUgV?se4)D^A7qh`mhJ3gQ@R^;z13^!@;9N67dx1D3rzn% zsqptviGROjoo%;@u2)?!`&`P8pma5hMn?^X(i%36#U&MoAI#1yTV^S`ujgR$X1`BN z_KVI+y4`4DQ02KkyH@9gO=C$$VDbf?g0{(5Zh8MG`EWJJJ=55|?||R|kh?y zWI4IxZ)EfS3tlu$l9{UJA2wr+p z`>pbss?Af*GK8*7V#+9w+LC#3fiw4fsr5!K6BXSWjPE`Vma{m2DZ731{NT-kuUDS@ z)Wu)_>Gwa+haY_2w`cx;@+o@Lt-ZaQ?EYG%oK%w4Is0zUOXUMq;nvGSOS5w;{(RWU z-Mq$(_r;Y(MQ>VXuP8aNsl~rnDzt3#d^YBuj^ldy_Qh3P2QP3%|CysMktoPsdbm9P!d1I1C%3L~OzBPA z`g`@=-IuPHLw;O~qR>CMS2uH1h->THfo<_u=H^-|SQ)r~PgUho_vCDBXQz!nBnek0=}t znelk%hjgA!_nXqsXC2&|la=>$itVW__8wDR8ER&Q%vkEs=wuUE(UHiuN2v1ClcK%7 z`_~D5P;y_t+45m?VZtk~@Ta!sqPJIzuAb~1miszqX3zG!Ke^>>x3p)ySm@B`$im<4 zKhdmIY@^xnjSnij;wDbJzbJKfPHI_Nui^ zhd%epPZs7EJ)L&9ZPA>EDs6>2il#iiw@OMT%;EfTV(;;=BP%Z*=ND(*;j-ho!^f^k zPyLu?b)KI6uVB5{+VYt_y%SFsuoQF_d^jgG-}=g)B%c3Ae0rb9ecjzQ|7=u@he`d~ zYQ4#YKW(o>Nk92kYpKp(*U9tx>%QOWjAucrcJDhKw&uLyhp&@Po^b8i|G?vc(&JLy z<5N$i=$JOId#FCMw|iwxwdrD;4P{po!tC^JCr_x8zZO+)mmR)mJNtW`uf1QaEG%+z zDkd+syjOHtBX|E{?a$ZtD)I4!3p2i%eP-dp^J}kL3l$XXxRtQ(NzB&f=EJTQOd-)0 z`Ueg^%=*Hhx9r@^=H|nqZVUy5NBLxBWY#TEK5&mSb>+RptW9@xnfI1$et7HbF1mq%cO#W8xAZCC9K+$GR-_+ zKgtUB-E_}!mV%6>g+)vw%Y<(%mm+dkc|MX|a^0e+pkPN6=Yu0Yx>E%^JRTf-`%}(x z^%3iadovtoDV%fTTYXTlx%qIaO2d-c4dv5f-+yRYQ$C@j-*JkU&$GGzKNM^|{^IiI z&(~%xdgO87U}CM}cNvYc-p@r!p3YW61qBiA{0g@x*DPG6zMgfR{K10{jRYNT{aCJc z+NM;;YVmuCen0m1IF_wqA%dX+Z?iTq#vVL+V_}3?kPoN!DwpfpQ?=xKRp-_36!`K- zo}In@v;)JO>>g+(y-(Y0U?S4FE$jNSlHZr z_}8K8)6#7_%90wEMzvr3#4z9XiSozF_>hkQdu}jmFwAZ{eRr;X`_cv@8-oJ@3mbmf zS++JcHgUK%P7*xjCLt=}swq8#r}h+^oV}pYR@37iff1|9@7OT0w}1V{uqkd&B~ z3!X6eE2JlWE|B!swcIMg;J>&!iMfZv`Ki#?Dq)@qH_a-ii!LsPnjfysdD`){qAX)V ze3*1#j-s3WRS|afc5e@cyPxh|w9uHagYD#Wt;z)o1`U(8D^_k5Y24!wcTmF7<)mbP zkz7yXB8{hWKCL{fIDh8n8){8V*CkIUu4Xy+xx8S7ZWVUeCUilf zdAXQy6xTchl|y3uW&8);3B8dCu~JQJ*NV1H+^}+kIu{#L1oPX>6;l+hH~z14jmY6z z&YY;(;+OM#+KwuNW2VWMrn9K1HU2i*U0>vT?Ss&!*S{+TtLD9yl`&&sT+&{{AR*|& zdY;2_isE^LiTsu4R}|e1OWh+e(>sDeu(yddpJA@x8Oc_Q*&BB9td*LRb@1V`f@A$< z{{;?ai4^-tU%rxJdAV!Pr4Mp%id9ZjG4UTg@*$whq-5&v)v@o(pHyg+-ksQR*zF)! zEQ4~Bq0mvr9!33tPc7NSUJKcN2;58l@Q>@sS=Tq}_d4F)>Z;67F*+!C!q;Ij^Zl7( z%VxLj>Wp_giB zwlB3qxk87}f1x|+_Uk_i7W9cy_^!4J;GBF@-FMTDy=#;-Hjs z#|1+LRR#W{$7MH+7`RO=tbEN8nl1sf{}rJw)bhbTSrrCHCrCKzK%ShQgMf zh0PlR)(Ug5G)!IbG9tW!!Ss8dg~b|m#uV>H&$5hACq`vC*-$Aasi>M(RqZJ)9Si|$ zoK`rwv&Oe>JFc_U8x%Kq zIWLxDJm2Jb^=PYvlOU5I6N`M}zNq8Sa;Obsrq>7ZkG3^D%k(XzmkB zn_oF5(`;6|y?OAUfYYYoUBCs2`k&u~=Ko96=3-eTBqaXm$kE@5fjtM>-vtEdUt_vp zaVmc0HIB~nzwf@N&-tSi`?&t|zNhMwSQx9B8_o$A6zo{SGGWgC%dC!5y{1l__|W4* z^NI}hp69=-T`t$#Du}$~YUXfS8r6GklZ=bcxj$zAY;`3j&EuTH!WbT`U?sjVMXd0DupdifhSdOguB+00S+Q(tm> ze9yz??OOh_+*Ml`H*p=gS(0Gy{9fOp%Jkq$J?j_-#+2KQmsJ=(Z0C1(*$}YO<@4Xp zCkHNFN;vInd-|wtC;J3}rX$Dxx94}&bk$WctX|42d^rB}h3}`hC6Wct7cD6kW-#Zo zZ=NCWG3Wa||Fk;xhUn#T&U*v|PY1i-=R1&V{wICQHEu!S+W-G9%d9LdeVQM3f_Nm?{<4Z>HIDKy6^wK`|cP2-p7JRF2DQ# z>$(2^e*3=%#1|j$<9uZN|C9RNuk-(Wu6H={=_I=y-vMw(P51djfVpH(`)u6-&?f#t-nT$h$?Nq%Ue)FpA6f7V6z-+dpA@7}e#*?6?2 z=J}I6hIjk^864v_Jl2$MDD>&X`8>u4w);OWewX+E1HaPx2h90D^HSb)UVjkz@9XRL zEDsL9|JmOWv1da4pGWcxAJXgpwCc_D_)}j0eP;i9gKI}RHnZJ%fA8ly`{~EMJ-%E_ z7vE7>z3=yKWhQrqlj4 zR&1TFzvQICY^9iN*@AP~n_r(|Ub9m0M*j9<3wxLK#apv~^xN$|u=1!D`+FTrr5#=$ a|A)nu{QkR8Ih%ojfx*+&&t;ucLK6T8vBRAJ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.json new file mode 100644 index 00000000..b4173a15 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.json @@ -0,0 +1,33 @@ +{ + "name": "Default", + "description": "The default, oak wood look of the spell HUD.", + "width": 128, + "height": 50, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 42, + "y": 18 + }, + "spell_cascade_offset": { + "x": 2, + "y": 8 + }, + "cooldown_bar": { + "x": 42, + "y": 2, + "length": 79, + "height": 3, + "mirror": { + "x": false, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.png new file mode 100644 index 0000000000000000000000000000000000000000..ce3109410f1a205414b597644fe21cacaccad794 GIT binary patch literal 20706 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 SDkla81_n=8KbLh*2~7YP%|)94 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/jungle.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/jungle.json new file mode 100644 index 00000000..e5273e4b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/jungle.json @@ -0,0 +1,33 @@ +{ + "name": "Jungle", + "description": "For the most intrepid explorers!", + "width": 128, + "height": 37, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 42, + "y": 18 + }, + "spell_cascade_offset": { + "x": 0, + "y": 8 + }, + "cooldown_bar": { + "x": 41, + "y": 2, + "length": 82, + "height": 3, + "mirror": { + "x": false, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/jungle.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/jungle.png new file mode 100644 index 0000000000000000000000000000000000000000..0015cb10545aae4f4dcb22d55e7fc18ec35f068e GIT binary patch literal 25335 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/minimal.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/minimal.json new file mode 100644 index 00000000..f63b60f3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/minimal.json @@ -0,0 +1,33 @@ +{ + "name": "Minimal", + "description": "A modern, sleek, minimalist look.", + "width": 128, + "height": 36, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 39, + "y": 16 + }, + "spell_cascade_offset": { + "x": 0, + "y": 8 + }, + "cooldown_bar": { + "x": 36, + "y": 1, + "length": 86, + "height": 2, + "mirror": { + "x": true, + "y": true + }, + "show_when_full": false + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/minimal.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/minimal.png new file mode 100644 index 0000000000000000000000000000000000000000..ba38076d05baa09bad612455b52b8e5be29f8dfe GIT binary patch literal 19824 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 D?6s(o literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/no_icon.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/no_icon.json new file mode 100644 index 00000000..cbee2a6f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/no_icon.json @@ -0,0 +1,33 @@ +{ + "name": "No Icon", + "description": "A variation on the default skin that doesn't show the spell icon.", + "width": 96, + "height": 37, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": -999, + "y": -999 + }, + "text_inset": { + "x": 10, + "y": 18 + }, + "spell_cascade_offset": { + "x": 2, + "y": 8 + }, + "cooldown_bar": { + "x": 10, + "y": 2, + "length": 79, + "height": 3, + "mirror": { + "x": false, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/no_icon.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/no_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e8e8615b5457301c578d853a674d108cc7c6995d GIT binary patch literal 20184 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/redwood.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/redwood.json new file mode 100644 index 00000000..634b5f72 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/redwood.json @@ -0,0 +1,33 @@ +{ + "name": "Redwood", + "description": "A variation on the default skin with red-coloured wood and a purple-pink cooldown bar.", + "width": 128, + "height": 50, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 42, + "y": 18 + }, + "spell_cascade_offset": { + "x": 2, + "y": 8 + }, + "cooldown_bar": { + "x": 42, + "y": 2, + "length": 79, + "height": 3, + "mirror": { + "x": false, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/redwood.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/redwood.png new file mode 100644 index 0000000000000000000000000000000000000000..ae9316245bc36d829df8892d6e690824a7a01b75 GIT binary patch literal 28010 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 F2>?gH#T5Vm literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/sandstone.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/sandstone.json new file mode 100644 index 00000000..513d7068 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/sandstone.json @@ -0,0 +1,33 @@ +{ + "name": "Sandstone", + "description": "Explore ancient ruins with this desert-themed skin!", + "width": 128, + "height": 37, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 42, + "y": 18 + }, + "spell_cascade_offset": { + "x": 0, + "y": 8 + }, + "cooldown_bar": { + "x": 41, + "y": 2, + "length": 82, + "height": 3, + "mirror": { + "x": false, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/sandstone.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/sandstone.png new file mode 100644 index 0000000000000000000000000000000000000000..e4b23c4175087d0452e2e9fa01124ac0b3c38d6d GIT binary patch literal 24369 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/silverwood.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/silverwood.json new file mode 100644 index 00000000..83c64dbf --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/silverwood.json @@ -0,0 +1,33 @@ +{ + "name": "Silverwood", + "description": "A variation on the default skin with silver-coloured wood and a blue cooldown bar.", + "width": 128, + "height": 50, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 42, + "y": 18 + }, + "spell_cascade_offset": { + "x": 2, + "y": 8 + }, + "cooldown_bar": { + "x": 42, + "y": 2, + "length": 79, + "height": 3, + "mirror": { + "x": false, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/silverwood.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/silverwood.png new file mode 100644 index 0000000000000000000000000000000000000000..e097a57e3f4fe4838c8569591c8cb1d4e3f591b5 GIT binary patch literal 27885 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 KT-G@yGywqQi!A{F literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.json new file mode 100644 index 00000000..2ffc29c6 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.json @@ -0,0 +1,33 @@ +{ + "name": "Skyrim-style", + "description": "A HUD skin in the styling of The Elder Scrolls V, for that Skyrim feel!", + "width": 128, + "height": 38, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 3, + "y": 3 + }, + "text_inset": { + "x": 42, + "y": 19 + }, + "spell_cascade_offset": { + "x": 0, + "y": 8 + }, + "cooldown_bar": { + "x": 44, + "y": 2, + "length": 79, + "height": 3, + "mirror": { + "x": true, + "y": false + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png new file mode 100644 index 0000000000000000000000000000000000000000..846f69cf746729dca1c307d18ce87a7f0218eafc GIT binary patch literal 20676 zcmeAS@N?(olHy`uVBq!ia0y~yU}OMc4mJh`hM1xiX$%YuY)RhkE)4%caKYZ?lNlHo zI14-?iy0XB4uUY_j)~cC85kJYOFVsD*&nep@fq^kG6!vEU{GN2ba4!+xbPR8mZM-rU> z+-OWWq#}7Jzu^ccX9W)<&p|fnoIRTNa&Jz%yDew!+Iv@S-<`gyxUT-n+S{f1_w#c1 zde-hcUtD@MbosRC<@etIp7(vv^V-(O7UsshUP~`MpW&?YWUIgVp0(<3N?hOHoSJV` zoA9gtVIuRLs@H4HufDsnG5NUe=R#)g%G~DG_sp07cQ-I($yZ&_G&cN_v*_Md-e=;= z{!h1Hykhs~=bMfPQEfl{WjbHH$x6Qb-+KZBL*AZ`Zh5=knt^DBB~yxv5|@fNJdN6Z zw`}&y-pL1Eg&Ar;H~hPQi-OGYoj)^j>JRgpFPJiGs=1HX%KZI*zb&5Ca*VU2X2-K8 ziGn0Qhs*!HCHfxUk*V4DWvPDV=}jd+qP#d)@8a?Ps+E{5;Dn4QB9d{=8;(t??d~Vykm8UMt=npM2rmvj5YC7{Bzs-j%%X{QmvUXTBai ztlxO>};2(=1$fR z`6{63BhV%zRwp6Q$HSwuYw=d&h$a?;iN%q3Uxnn(sfnyv$hYWB4Ws|{%;)=4?#9{) zzIo#t%2^x1eD$+-%|rIb%hdgZ_`my^|D8Vj9H+tnv)uG6z#$=AR0=|X4egf<55)~dhx8(KIP%oE#@(|maQe5NgI zOKT2>b8!p&a1me;V43*HiDSO#7ANk;FfL8isBDvlAQN-dA2-*TaQs-G-+g}d(!_){ z49zPieD(S8-bPpJkUrx|5i_ZkqT8Zfqa>5hT`9BAQx6F#Om)lZW!++GuK3}k3@Gm$=q4 zDjuAaArkc4nUTBq+5;|)S?T*T+8EfpZ!q1sb=f3!u}1&*)@u>;+~g{tZsY% znMXLW1iV+B5OD3A6ng=S%avPfAtYgJ7>X1Zy=M!@?2+jBoLyU16c zZDH5vly_LGe1e~^v08F*{(gl;rh&Y?8A(Eqq?Eh_*^`8FyagsQxmVrL4crpGz|kot z>sahT%f4r^6@RX5_Q-OaFEoWAb>9C)9~gbE|2IhUcu=C=P$gadZCS)!tsDE6_Et+K zC#_%hlV>)QE7t**56>9;TU0YPu>^7_ZBu*1k;Iqtjv-wpWp`Qv!!_3j?c=fy+Y#wEslhahbD>*zvI6x%i-Df_vZTF_1kkcI7b~kzW03Z$K#sQ z!`L59d$zeR^yc?q_7>)i5^L_T*x%OvQPF+;J%2=x!U@GcGZ}8r+{CBQ;i*5>Ygzd- z#^aa%-!}7o`#Q8=tM)a$ENOR$j3Lj)KFy<{76qwXC0e)Fg4yzkLi>b6HLoJUCjFUj91v z^p_(_hjPBuN9=AFm%5r&d-;F&1cto*f6GoqMjwsYpRxUZowaq@8w1;o9SOhcIfWep zHmX)|>YSc6dHR9Rd%U7vJebAC&42m7cRxeky5k4T?^Pr}Rb@DmGc$AEbH*39^Y`z~ z^IRcoUB>eB}vuJuQUbk@1II~UEf@((ol8i>e9XEO}#ug zeB0MXinj9dZqU-J*uVJaQdNh8GgZ$fYaT4{G2a8?t>FU+9nD7 zV|R=@F?;#$ZHkRQKQf-V^1s-YkN?E+FE0-{o_P`*ulIA#V$nhqPR?AjlBf$0Glaxk zmN;Z+Xr9>F)YH^6DaAx&LWA}lQi^QgES)jn;%5rqmhyG>8A`Ie<+AQ-XWM~FD1$+s)x>Y~=z52>I>l#knwp(SI zapBbe1&sEYniUI7rRsNITeV03Pw#)-Kl`_aO-*jOma*q#Sw+kGrCZ%X)-Ap8w4Y;L z=*~X2w~Y*I{}%sv{{4Jlrnpu3kN;LbVjos7uF3f^Z-&kMc}04mSNTlN|NC@)dBvyo zI~9)k&pR*J>7rF@Fu(9e)azB*@!R5Nx4M0{WLXg&66DbtbgKSs%l}iNQ6=4CNvnxktKpW|)mcm*jAvcTU4HoaN+qROu^O#I%eSr*`>`s&=Fo~i zD-1q19Q*uv?IYoCzIUAtCrW?D9b)q5^~{?0_vw}Ama|=5)0y3Vh+p80NK7@h<7|CclO)t^Id7Ynel7)PMDx^fIE_9-ujK&v#Nt8hsy@W^3z9A?&g!f7Zm+hyLIk?1Sf-Lt>T4$+A2)B zv0`bgQx;4TxuP|>S&WI_W7(yOAE)cIS_C-iXU3QmJYH|=8_8F*#j5EsKlfzU1gqj- z7TcvIPE;LLoP2W1{M+$f8+5j$KJ@I=R++a!gUi#?qwCV5jL0V~3i>LCSDGlVG^t#m zaq66%=EoM7))spWi6H*(cIIJ`MN#Yf794z&v{96O?e>%#34FQ@Rh19zt19Q@+f8wr zV!DSRDtcD!=b#R+zzG{ugd$B#KIpQBZe!aL@0L<@CjQzVC$GGU^5nZUC6l*u@ zw)?j(hp66pxM1Rj?-mBi{abT)+`V{gDWhad|7+>%UwW5oEeXnBlM^ssAZz~Piyl`V zn5Z{YMg4fq|Fq$b;XI{snd!4{Z8P&sG2jl!WqX$P@|U+b|MzS4Vb@~>qC>uCrZGMf zFWT7J)E4X~ea6=3zkVT8M2>mNvZd3^z#IbugBk8j5jhJNbn6+|7QS$`|J8<%XiJU0xlG!&bXsj)aQA6%5+bgyLNhl)#m+TPjwE29+Ll)tJ5Ux z{$L4rx= z*gt+Tt=#*U!nXEUDl{i-JMiE~r-BdD!&462tETpS+ax74Blh9<&+pIQVLzHw==WYd zsLbx#?y>|%pY1)C1p-puAoV%C9W$T(`v2y7^v#>ISFO3bKK7Bc&T-y?HM!;AmT4XJ zSax{o^9c9cSF97P$ zoVzFT{mm);7iaGj<*J+CHH|r!ZEvgh-_~Giqu&mr36-yTSJg7Od;kBczu&TH3Rj}0 z-5343S@+)8ePM8_;_wdrw)cB}HN%hZ{%@TkBEWm|16re6S`)Hp8ZJI%Vp%{gx+ zPsx>24$1e8^7lBJGS>X{>J^Yu6qWzG^1aNC$9rdXZTr@GL;Mf_-_`kycfMX^_BieA z#X8N2tN;7IyEpf-eo)`7b*t`oZYuYKV(Z#O{xxjgg-3bcf6;CD|5bQ?giin3`X|v0 z{xyI9hn{em(qH{cew{PN+2x-O2{b4&G~Yb*b^7t0|33X_O7Ap1YRkj(O#YJphLygW zdd$sBJs7%|8nh@XBv(r6Ffbl?w1O|W=%B95M=6~|CJTcZ>s+GeW;A*>2aDG}z7@gf zEddI@sT)q;(lY$)$>FFl;ou*o7xjx7rm4Nj61IsIP0MWg^rhYNP$tKMrUm!nHvCw$ zdv%nv{*=-LgYC`?@|n&*yf3l`yl-7m%ELM}wfx(%8#iaKdcAS~(_80GJ$Ko#**x{w zB5sCYxjPXIqB0Ub?QtCQS=Q~hi7OOpTifiA+|tjx#dEFN%JAv?=4nbzXt?O~*`F!R zETL1_VZ)hC`8F|`*Tr8Y%!!EhHH&##p6xGuH#S74b;E^r@22xho~~Y>Yaq|Ta^He+ zx&|Z5(?$LJWGbF%?b&+Vzkc7Z=R2R?@_RfXNtFXZGh;)ubPJshSMt^(6q9T+G zHamDvVEA>+G`f10n2ln`!AA-S#@t(2Y8e`TrdwTIaP7P>NBxbH(dVr!#N5{(R8na; zYVyv^Wy^>2^$XJ)dBoU2;U*duf5Nb0!t4tzOV8;aTKHfq_ok+q3m5nw^0YjB(lXI# zo`OPCL5*XD*b1{dcLWYIMKc`KIgoVGZfmlC^H0Oy;)iu6C^r6VkL25PM9}Yk?gkd! zhNEH}NlA>)#5-41vU$&95c5{>5a`P~_P?!w_t`{-RlXlu`B@AP<+sJLaXT;^G)Pcn zcHFgF=uT1Yp$P|Vk~Ug2@`|x_XIU0}u)S-_^Q@0WOlsMF@kZ7S64RL3uiMXi>G1i{ zoE=-YL|kk7(wlAkclQLA4Kt=O`+pBQSMsKIx7z!stGH(^%bA^d|K)|cUFpRpNd|Te zOMAUk9we>cv&qc#xz@^`zgk@+JoZA!&1;ucU&yYhTUfnIZSS40-{$JQJ$!!QG#w_T z73rOOK_gA47OmvVH8{_*VMbg-)M}+UYc2j1u{#B73mo6H|K7gfy?-~((O0<4z_{|> zcI{M-0}%|t#~)8lu3dJd*8lpuid*MIyyLPL&D#0ursLbs{2hk`4hVf?Y>8)C(Z{oT zt`b*!@3n2Kuii7>x;9t*UVOjJvdd*`$NLT#aoGRgR~TFQja#=tO@7Ho#u*+5SPy)i zew^{gFXx@C`}-3_7ry-evpL2mbD{6lN3E65x)aqBcBLL-EB0YX6s}VgJfbiobLG#Y zNkI(9u5V^w5fEXI<(YLN;pHLzKSqc5SE@H0O=6PLO<2Rw{Ifmwb!+^I=@%>*#nWD- zZa7lQ(9P-g<9Ypytr9v1UKRyOoY}~_VMg9D9rk(kI%3=xLNwzPxDz%mX)!w8INdC4 zJC`x{76GvXNrk&+K0V-F{UT(&Lgzsnfdfg2ciydQiR7yhdh1_e`5|c|L-ywYi8K5z z0TT}Eu-k3DJ^w|~gQFr`G8#A%x%k9f>Jzj49CbHBjRhCkGuw&ja=A43!Szk>X=Y!+d`Zz_DY-RY51h!9Azs{Qt{Aph@k`3R=& zgJ0%p>h3*w$3bt}tpZ1vSu_8~&v?FX#=GM!>gN};ZivWJd82G_#=bs6XJSKuy{@fH zbW~+?@Eisog%g*Km1Mqbe)%xU$iT(Gn|ktw$vzfKi(?{XNAs*%?|JoqCs@;z>qi^fI>0a^oiuJnu zn9ZBbkA9tgym$YL6y1iSj~KX~{qFs6UVquSe=IZZM=lVyKgYs1SA&9t3eueT5H-u*7sU6T^pZE9a z0XA>x?qwDk8>G(Yu+O{y^Z;8MgBU9#%hH913{E$ums=J%teJdR*O{e_p=#A?X7xoO znUCh~UFmhf?Jd{-0)p;d#k&%g>?@2-Ws{yG!*uZeU3)k0JL_1k%wSlfYR3}6bFsmgmocoDSFy#-<7l#F zea`P~+mt;{JA1TF;L;Rzs=8C3VapJn|Hd^+E=X&GNKnO}7p>h475A6+E9-=BW0-v1|{`+zLJ>CQN@Bd$S>hq7k@s$gbYVZEOBhkP2 z*(~$>3+x!rlux~u;3MV2BzKl`huY2e+{?cROgp~s1lzeQ>l?pRBqZ>Lue)ikIbqtP zd$zVylkXS*EAH5&;OYJGuloHXzqi{4sqydsJC}dY=1c#|@BLM7S*m^g*YWz_4Ew(y zv_5_49rx4g|6cC$`fdO3@c#8er}qClrT$~G{okU>+4a5qcYNJE^_%s+ANCV3t-kaA z?EHU5=Jih}ryl%z{_{=yKUquv#^3ok(JNZ#=yJOsx%)ot%@&+?eERQ+b zXS)AiF^2aQr)51}W&Dc7-yCU9vAXh*?B|gxKPBj z1CyGzebY!zc4cYuO<%7p7JqDCZLQ3!*T=t_a5-MQ>f^ISv$7zx|G~+nZzyc2Bihnw)Z<=#zjcDWVg4@1TJ?mzFBj(9MX4ll=d9eg zM8$Gq`sHJ0UOSa|4IPh6bCKZJs`n>e&a6=W!)7eR;Ny3i zwLqsJ$MJ|zM5@q>_p=jDw`#w%FKFqz=9Uwk;JrcDab?7U&3hZ2jLy%xI`>OX)bV@w zj&CfPwv27|q}2soO-`H+!lf)xKmPMu|Jk)$DD>g}afQMwjsowTdwZrmIbqSq`?16I2-|V54SAu~Hz%q{U)yp~EHt}W&U z7Mbz~w#(@Y_Wy9w4?LpObZmxevd@KEcTQB!zHVq|;NY#)rE8nBP(bL~{93i<-@kqw zD3w>bb@7=0zEXbc`4!Vr!UA$!3th~QvT_hEQw(eQ2^%l-O$ zhc_y`a&Y$9^z_iv7n9t}bdE~Cj>^dH6qu?f9=~boRavu{PXycC**r_WZK#X2{!-KN zr~b~t{<g+lGqGDE!=jKfZ*Pdaz;`e{%#=VUP z?>PAta(Oi7a^`4uT2A^`yVynN;I-4|k6x6zT^hMDNpj`E@Qf{9C9x%D(&1Y!Ub@2b zdK#m+;O!fp>D|u7%}1^8Z=d^jciH8e*F2ohEL7CW?C{djoZ#eB$Rs5pab~gbhBD_p zhUZSLNus8S2xE=?eLKYie_{6HnK%KzcP56UZ%Y3T;saZBa6-+c@im5&Huro zhwsA0M+N6Z->cRxneMG`*)Lu$uQpY7QNV{}cBO3!@w4Wzt}y?bo{(U0oF!m)hC5fI zD$B->v#Xxwu8A+UdmXm*(k%w3{>3TtTrU3<;kRqDwre{(d*N4Ehw7g^V)rJRJl~%y zy(OY#>%61g{_h=kvgWK52of$<>C^3Od7&=Tm2;+^xw%rQA*wf8OHAU0y^mh%;}?3@ zO156OB9nOcR@fZV=gya<7Kr{3Ns(up%6?PM>hRKt+xxioFx-qc_;AMi&HdkOd5XSA z#9VT^7p>ip#U`KjCO=^V151E3=ZaEG8~1EBw)Pu4i(9V8ZL@rS#&28v&fa6EuQ3ZQ z5SFqtIGefo!0UpFmWy8mZ(X0`di`1I6646Wz8*ufiD{|-1%I^#ec4}h;7e2EL8o5~ zhbA^`(=E)YpObgHZbtr*Nj?331@~>gZ+y10J>s6&!rzOwJDoq?__fsUHlK^;*S(Hq zDNP5JoqJSb-GaLg7ETX2x42&8Y{appCwYGI@`z1iICNskC6`-59+`>)9Et%^3rrPQ zyfU{0Rb0CnaWq|VQ{AlK_|D>^yLWu)`WrK=c8Yl2F9rU8pIlo!CZB$G>RMZa5hDwC zL=+1AUeNX|6RaDaMjfQqeVy*PC3jdqQ8|_HdDviQcfMS~RR&Q0e{Z`mpzT z8x}c;SV&7<+wgNv_sfVnx%KiA4^O6-e}2=w-gutu%t!17QyY1Co=s%Pn%l6C-(iwh z>V_?@!O6xqdyZcS5Hn9JJk~n9WB*sHKa+g+GgvinpLXwO&~Gl4yvhE*rE!Yuri_c< zf5}Z-fAh#H<8w#)JRb3Kn&sJayJS!Lt8W|mv>7y5WFHZ$YqrwHk;I=p`edFta zyH8>~7iH_Rv$Op?_`Uw1a=+ctg^hw->sntsW-XcjY(^)8i9v(_Q^d_I;f?B?3Evyq zb<%%tTsr?v^3zpf=j{ITe0x(h^)UOl3*{^3Up(j-b!(AH&X49z&-VBKi~pnD8z*M? zL1~MJ67TGaf1U1<(&sOgSG4p#pYOQu$)@uAf_z{3FJHHJX?}W1MmQ%fz2*Lagnfpp zA`zO6*Zv(3-B1*(-MZ*_^Y`~j2_-!XH=4Asy?GS27Qo#t$YkBl33F~U+~JgAoFrp4 z<%#{f{nEGe6FY1&qGwIt_f4KYudZ>~Hnpzv{sJ#gPOAQz%Ev1j z$R)S;f4hmwtsCEe889zizv1H|?w>FF<<+KsE=Ur*XEEbYU&I#uZiiEALW~U}47e8v zajp5gzkIr+71NnD0J^SD=Eh*60Ffb`$LB!69bN6a) z%g;={t#FaiQef+Q|HNwx{qGlduIi3mzsFKr}Q zm#GPL>=n;vR>r7)uyH(ixk7J;*X7zY<9@qa?rQ5dE)x68>>498ufC9<{g<1hzjlzN ztJQJ|8PCth_9@P*sL{_pA92p*m~#9T8Jig@Gj%rPxH7ATf7VX-;bT0b<vy;#7J9T1WqRn;X z*=HYBN%S3F$wG63W zdb97Fta16IyD2vr9@#J99L$u`q?k z1+G})y-xq+r>VVf?oU4!98h99^Py09p3bKyar=!XG#*^3@@IMQl~uALPk1^We3)_i zp<%^mNwWu^E(vmnJMXiI^LwJ`v2@ZCF4a$Y^Dd@Lo5a1KR@+e>r#ku+7~XhOLp+hdaZW_j^xZF^!$E z@9xJfYje$GJHIhx8Z*rnZSlUtp8EDsz5caLuWy^(3=VFR%>VOdzr@xRvi5S>yM-;E zm;AkHzV78qqgvbO86tm5dLKL&Tl*pZ{-tNvS!ekDZogd0Zok2-wY*`it?z-9+WimS ze>iO!{OtbaT($+*Hbr?{d42uC(pXco7SNDi|IhbZUk8(^Z%1|Ew-&{_y?#{?(ss z>i&nzEr`qYO}Lo#*MM=(?n^UO8a6Cow_mX>rea4?{#pa}Ciw{mOH%hPU!7FF%lCgP zXTrj^(8dq`*VjM%7d`on{&eH-ggRk$E5B~KQ1}0&`Nw~`{ZmdJ&aZ#Y{C>@r|8vX# zb0oezwe{b}`*sK3*M2y+YSYX3-^*WXz5V}#|NlNOjsL&2=RffO_vQ4{+<&J39$h;h zcI*9*NB>>C))(zJum5%W&Y!9N(^#+DpHKh)VfEB+^@YdXwQ@I#%>VUZ`_EI~*SSW> z#s6!b|8Zvi9$Oc;uIT#b8&7QnjYx|MZ@9r~zvgfGw`Hq16SDn-r%vN%sr)@{n-(K~ z|IOvXpEfwOAFiH$%BFtDqoDgco_(0{e|K}yi+8qrAwz?`^M+i*JEU2^h|%5(4>tYMQopz8|*mu`~ID<)ZVM#vVXYF)m-t^ z=VO0G-%V}|u=#ncEM9TW=fhp00vtc|=l{}W zxc70I^@K~;kA46Dsp^01u3!HZmcGvZyot5wJAX~?|9$**8;kC~uY3KOq2|S}|Av{2 zQ_lZCU;kP3{-GaVj-PT_{PWn_|KbhyJARhezILth@K#=O{C?fD-3&F4>i4s+_7SQ7 z`LTLgt)6vt@SV-CuS6dg;;8?S=cCxLVH$t-rwt9#iuP8AOvRa*Kr3(lR?8@Di!U#% zOy|*5n5_3Gf=SaT(j@*I|Vi#)SDjT@Au^9mW{nZ>pYx&1U9M$x+|$Z&36n>mx=w9k(u>ullQKd zwUtZ@i;gHYP14qwBJ#20NM3$gipkO1y|Y$Vu^hj&-u>{(gmdTEvO4vC+}$2?+p^W+ z_c8yw3=5*(#=9~!M#`T%DSqvf+kt-hhdHNLN3&KRJFt;e&^uwO=YswDO}gUimi#{; zXcZ;BF}G3o;5L?}NsZ^ev2mTW$qp;Ov^i6@x?2ADrN~)QIbQ1yX>xI?GWcE*%rLwv z9&mfTx9f)G!k=zE^j|v-G#I|h?BKu4y75o1&0BWTQscprR1R^q3zs#S z3}!4{t;Msc)_Zp31Y_?NrdyW^SZq@e`*{5S#*PJsX%{7gD_Hx_^`*@Tnl{ZvB)aN` zlcLI&?P@o6Z0r5L=Y6h=^{p2bW=`3M)Mkd>2vTlMdiyI(ElAZ!vwzK8x5dlvxUUVf zp6m0i>haft*|#EB8(6ZRUmkXv{fH#b+-0w?2Os^yAN@7Bh9NQdYC>6nbdqc@M-I1? zuor+`MG*)wC}k6z_eR=B?4od-3A66E98(E(u+**3$91e|Gws=N}$&ev|k7RVl+dW!Xp9IeaPwTO$5!aPZ&0_FF7J|K+UPS0;D2 z&bVfKv#?$_kZu2AyVx*OU9&4~kA886Eu2y8nRRp;_w>cyayK`M$m;Ut>I%B??>lmI zdQNI-yRVvLdPT|v7w@L8uXi3s0j;-zyVca(W+g z?6IorxSY$gd%{Lh$Nzd^y7D~tUt9h?WGs0gM83iB|8ur&B2zckpPBgOz4X%EyQgyN z+fTn(+rA-oy6D~09=!XU9)FS(5})gPy4$sg_w0r|$pXQRz4i+?A3ZopZ+cvMtLAZYwCFrP zGF8ZaiPNIi{kAiG3QH}gDepLUZJy`lpBb-po<*I=Uj86^YfZ(qyk#?atk1Bq6}ML; z&zTx4Te8JOV5;k#KNhV%ZJh_5b1bTvdAGG)NxXIbja$iF=GfOAuCqH&ZdUjv_n=Th zcERGK59es#^ZwqkCwH|!UxCsTyh-uEm>{#zhe1+Kh>CR2Or+{f4F>0 z@G0?{r5hL;{aGAeWk=TOI8E`sl-VlAv{od@Yl~jB|CB{LH4mOITk3eAzBYQ#sYf$T zr&qplij!>#U;UK1K5lLOl51RBdcVz=zLLeE$udpgh?3drY1=o}o&C8c`l?qpGly;8 zq)H**=fO5VINtq`Fw1YdR{lUdigm+>z9p9bb8jy=x@h%Row%AR{!_XM-mMdM?TLvN z+PHky+V0BGTb)Uvv(J{#6I&pv@sxX4(1}eCq8kFFR_nZ3NHmuW`lVqbYh__@r>#Iemvn z_U-USafRR9Z1XBR|5o2Wpu42=MpH*_;FiCu{I(`PP44|;tvbK(#+h&~?}iYmNVSG- z&(v7{{a2mf`I~9M1&y_*ViaI&5?9Z;d`L8aCqBe~UAg5&j|0Eds<#?kpL8(hY|4$h zv7BY!`z1T)re1MldQ~({WlLH@LC0Kc_lmcvvy0EYN%=kXcE+9@TLDI^g%6o8&oSlR z!`JRE;VZwe_H1NHZk(IdDTapdd^Tjyc&i=b^<@$|N z4mmw$SnJD~vv$K4H;(x%Qo_9qON=CK*4BmzNOjut6tK9o9J?kL;LDzlA2rlGDGYyZfC^ zm--gj`5;)VPI?2&4KAx$LJ?7k*{&=bw(R%U5Z7es?X;Nb!>1AvB)pl$aOK9p63&YD zwH2X}HrH<)co=f+yKc*tFFAjwwQljb%(|iX!+CzAl_nFnu>?hNuq=wHx@+#p>h)7D z=e(8l>K{5T*Zhl@X&0`m5T72malZHF{!fSe<)0jk-`63KS#&ez=B*iTo+QLnSg|sN z{?QVB@9}eS?OAz20oTVG{O;OG4ax^DDlB#2=+)H~;`87%TUF`^lM{`K&Mo}L@6353&1j3swjWIESv#*utiHB=VuzK* zwuH*>T5H}Zx!eo?zvSNC1lLB50yC2}iJvXSFK_%~6K8L5X!7}Y&u)sxr`uQ?J#Dp> zO=4);`u!lcjKwz{#%*lwTuM>GS1&ZEsVS~gTqIJc5Ehp#NMK25gO{YYB7^PfLWb$N z1wYO?uZ?giIJrpUK@fwDh}iiL+#-TPTQ03)IlXqPjLzGIktG7cU4gop3VmrEHkNLZ zDzA=qcDlvg+A7w0cXX;))n*N8bR_?!EXyWS;R ziq*t3!|j5K%EzEi;?}5kX?Cwk<6eC$XW!odV>!zO4b85C{Y=8ClO`YO5LR#VZVSJ0 z_TL=_Ll)mMYiZ%xl_hWFHaRrvNp((2vzI#YQbbU4;Sv%1$`?8JYJX}6*D|<;JkMJb z<;(K#%cRu@E;sp@9e)_a7+taF<@I}xw@*F&aH?PO#f0~Ne+ag@U)ICbvp8nCX=ZFR`Is~h@5;b#dp#j@BhEVy*7%t2Gv$RC=lZ z_W6kldF?e@c~&1jvbBAYD0lAyhgpIxAD(;2EW7sb_N~h)90}_{gI*uI*G;qWUAW@J zGZF2uEgSyb;eGSxsqmglI+0%S!2}WE#yDWGA z!SnC`@wuo=*i3rVWd3zS^>@a3_pkbYx*+j$(X#5z!7ra2)%mlXA)aIQ&!_33{VYwP zwTvr&J=?Dl%^)zjDUETi*_slQY^8!wWfKn%E{n^TEQGqYsomldUlVS?bdo26vqSvh z-P5A;@25|8nsBu#$)Gm4*jZhOGa{eu!EJum%w?T*d>0&)SKsJpbxBg3pt8tUV{Jjf zj1O*}t5qUxyOzw=5nH>fGi^6>YtkMQkI7mS6&Cw%9xNyF$!?CG6wwv2a&OKf8dDo5I`E#1vH>t1fb?sGnm1(kt zZ|l-!duKeX@hSdiZ|(MweL_%DX6qLbLGKG1EOW)y^dI_Vu_p6^$m6EasLgkTOrDtJ ze3;wF;N_IaFsX1u_lF0L2P^yxo^YwzXt1&7&G5MxmS0h>bS*J;qD0`QCod9AdrN{o zJlDx^o7|y#K}yPV!c|MFCtg-hw0?P2OD0ZX5);eqS)F(-B7LH=@5!>l7*8%&?YSZ+ z7A}$3P@PfogIz_XH{+Zz*97eVhLukT@CAI6Y2k zSwzql{q8v%KGZLCD>!^R`+IBaAMVQ&4v9O>+86fOzx>}!0lyTjR)+`6{Wdqcd2c$? z_nFHRpewmdj-()z!9i>9tt zD6-Hwu-R02!NnaSnQ5$If+}L1CcGxeiJRBH4Br@{EPKt%?3TFT<-)Léh8@7G8 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≻w`&n?IKJ5Nq_uMF^%KFlZy~ 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/spell_book.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/spell_book.json new file mode 100644 index 00000000..eef32610 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/spell_book.json @@ -0,0 +1,33 @@ +{ + "name": "Spell book", + "description": "Knowledge is power, or so they say.", + "width": 128, + "height": 38, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 41, + "y": 20 + }, + "spell_cascade_offset": { + "x": 0, + "y": 8 + }, + "cooldown_bar": { + "x": 41, + "y": 3, + "length": 79, + "height": 3, + "mirror": { + "x": true, + "y": true + }, + "show_when_full": false + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/spell_book.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/spell_book.png new file mode 100644 index 0000000000000000000000000000000000000000..50feb347ba243ec080f99e5158826e1de4171a31 GIT binary patch literal 23686 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 z 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 WJzX_haV`S`1B0ilpUXO@geCwyrPvw( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/vanilla_style.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/vanilla_style.json new file mode 100644 index 00000000..6c541a38 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/vanilla_style.json @@ -0,0 +1,33 @@ +{ + "name": "Vanilla-style", + "description": "A vanilla Minecraft-styled skin, for the purists out there.", + "width": 128, + "height": 36, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 40, + "y": 18 + }, + "spell_cascade_offset": { + "x": 0, + "y": 8 + }, + "cooldown_bar": { + "x": 40, + "y": 0, + "length": 81, + "height": 5, + "mirror": { + "x": false, + "y": false + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/vanilla_style.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/vanilla_style.png new file mode 100644 index 0000000000000000000000000000000000000000..3e6e037bbef7537ec8abf3b7458e55ebf250ad07 GIT binary patch literal 33784 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 z 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 Date: Mon, 2 Jul 2018 22:56:04 +0100 Subject: [PATCH 44/68] Add config option to reverse the spell switching scroll direction --- src/main/java/electroblob/wizardry/Settings.java | 8 ++++++++ .../wizardry/client/WizardryControlHandler.java | 6 ++++-- src/main/resources/assets/ebwizardry/lang/en_gb.lang | 2 ++ src/main/resources/assets/ebwizardry/lang/en_us.lang | 3 ++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java index 3994f11b..f6c9bb54 100644 --- a/src/main/java/electroblob/wizardry/Settings.java +++ b/src/main/java/electroblob/wizardry/Settings.java @@ -158,6 +158,8 @@ public final class Settings { * while sneaking. */ public boolean enableShiftScrolling = true; + /** [Client-only] Whether to reverse the spell switching scroll direction.*/ + public boolean reverseScrollDirection = false; // Display /** [Client-only] Whether to show summoned creatures' names and owners above their heads. */ @@ -459,6 +461,12 @@ public final class Settings { property.setRequiresWorldRestart(false); enableShiftScrolling = property.getBoolean(); propOrder.add(property.getName()); + + property = config.get(CLIENT_CATEGORY, "reverseScrollDirection", true, "Whether to reverse the scroll direction used to switch between spells on a wand while sneaking."); + property.setLanguageKey("config." + Wizardry.MODID + ".reverse_scroll_direction"); + property.setRequiresWorldRestart(false); + reverseScrollDirection = property.getBoolean(); + propOrder.add(property.getName()); property = config.get(CLIENT_CATEGORY, "spellHUDPosition", GuiPosition.BOTTOM_LEFT.name, "The position of the spell HUD.", GuiPosition.names); property.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_position"); diff --git a/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java b/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java index 8e4fea67..ce212de8 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java @@ -101,10 +101,12 @@ public class WizardryControlHandler { && Wizardry.settings.enableShiftScrolling){ event.setCanceled(true); + + int d = Wizardry.settings.reverseScrollDirection ? -event.getDwheel() : event.getDwheel(); - if(event.getDwheel() > 0){ + if(d > 0){ selectNextSpell(wand); - }else if(event.getDwheel() < 0){ + }else if(d < 0){ selectPreviousSpell(wand); } } diff --git a/src/main/resources/assets/ebwizardry/lang/en_gb.lang b/src/main/resources/assets/ebwizardry/lang/en_gb.lang index 79eb401e..79604949 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_gb.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_gb.lang @@ -703,6 +703,7 @@ config.ebwizardry.friendly_fire=Friendly Fire config.ebwizardry.telekinetic_disarmament=Telekinetic Disarmament config.ebwizardry.discovery_mode=Discovery Mode config.ebwizardry.enable_shift_scrolling=Enable Shift-scrolling +config.ebwizardry.reverse_scroll_direction=Reverse Scroll Direction config.ebwizardry.minion_revenge_targeting=Minion Revenge Targeting config.ebwizardry.player_damage_scaling=Player Damage Scaling Factor config.ebwizardry.npc_damage_scaling=NPC Damage Scaling Factor @@ -740,6 +741,7 @@ config.ebwizardry.friendly_fire.tooltip=Whether to allow players to damage their config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items. config.ebwizardry.discovery_mode.tooltip=For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false. config.ebwizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. +config.ebwizardry.reverse_scroll_direction.tooltip=Whether to reverse the scroll direction used to switch between spells on a wand while sneaking. config.ebwizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge attack their owner if their owner attacks them. config.ebwizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. config.ebwizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang index 449313b5..f8d7de57 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_us.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang @@ -703,6 +703,7 @@ config.ebwizardry.friendly_fire=Friendly Fire config.ebwizardry.telekinetic_disarmament=Telekinetic Disarmament config.ebwizardry.discovery_mode=Discovery Mode config.ebwizardry.enable_shift_scrolling=Enable Shift-scrolling +config.ebwizardry.reverse_scroll_direction=Reverse Scroll Direction config.ebwizardry.minion_revenge_targeting=Minion Revenge Targeting config.ebwizardry.player_damage_scaling=Player Damage Scaling Factor config.ebwizardry.npc_damage_scaling=NPC Damage Scaling Factor @@ -739,7 +740,7 @@ config.ebwizardry.show_summoned_creature_names.tooltip=Whether to show summoned config.ebwizardry.friendly_fire.tooltip=Whether to allow players to damage their designated allies using magic. config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items. config.ebwizardry.discovery_mode.tooltip=For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false. -config.ebwizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. +config.ebwizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings.config.ebwizardry.reverse_scroll_direction.tooltip=Whether to reverse the scroll direction used to switch between spells on a wand while sneaking. config.ebwizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge attack their owner if their owner attacks them. config.ebwizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. config.ebwizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. From 82eed83dccb455b23a9b6eabb7706aee9ae4ce16 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 3 Jul 2018 00:24:16 +0100 Subject: [PATCH 45/68] Correct default scroll direction --- src/main/java/electroblob/wizardry/Settings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java index f6c9bb54..0917ece2 100644 --- a/src/main/java/electroblob/wizardry/Settings.java +++ b/src/main/java/electroblob/wizardry/Settings.java @@ -462,7 +462,7 @@ public final class Settings { enableShiftScrolling = property.getBoolean(); propOrder.add(property.getName()); - property = config.get(CLIENT_CATEGORY, "reverseScrollDirection", true, "Whether to reverse the scroll direction used to switch between spells on a wand while sneaking."); + property = config.get(CLIENT_CATEGORY, "reverseScrollDirection", false, "Whether to reverse the scroll direction used to switch between spells on a wand while sneaking."); property.setLanguageKey("config." + Wizardry.MODID + ".reverse_scroll_direction"); property.setRequiresWorldRestart(false); reverseScrollDirection = property.getBoolean(); From ad363c64af469b65c594eb0cbe28b2ca6ccc0061 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Tue, 3 Jul 2018 00:26:44 +0100 Subject: [PATCH 46/68] Correct missing return in lang file --- src/main/resources/assets/ebwizardry/lang/en_us.lang | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang index f8d7de57..a7acb7fb 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_us.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang @@ -740,7 +740,8 @@ config.ebwizardry.show_summoned_creature_names.tooltip=Whether to show summoned config.ebwizardry.friendly_fire.tooltip=Whether to allow players to damage their designated allies using magic. config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items. config.ebwizardry.discovery_mode.tooltip=For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false. -config.ebwizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings.config.ebwizardry.reverse_scroll_direction.tooltip=Whether to reverse the scroll direction used to switch between spells on a wand while sneaking. +config.ebwizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. +config.ebwizardry.reverse_scroll_direction.tooltip=Whether to reverse the scroll direction used to switch between spells on a wand while sneaking. config.ebwizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge attack their owner if their owner attacks them. config.ebwizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. config.ebwizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. From b374f71533d077a576327ce17d6f98708b41a8fc Mon Sep 17 00:00:00 2001 From: Electroblob77 <> Date: Tue, 1 Jan 2019 21:40:04 +0000 Subject: [PATCH 47/68] 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 --- .../electroblob/wizardry/CommonProxy.java | 2 - .../wizardry/WizardryEventHandler.java | 23 +- .../wizardry/block/BlockCrystalFlower.java | 2 +- .../wizardry/block/BlockSpectral.java | 6 +- .../wizardry/client/ClientProxy.java | 60 +- .../client/particle/ParticleBeam.java | 95 +++ .../client/particle/ParticleBlizzard.java | 67 -- .../client/particle/ParticleBuff.java | 41 +- .../particle/ParticleCustomTexture.java | 130 ---- .../client/particle/ParticleEntityLinked.java | 61 -- .../client/particle/ParticleFlash.java | 6 +- .../wizardry/client/particle/ParticleIce.java | 34 +- .../client/particle/ParticleLeaf.java | 44 +- .../client/particle/ParticleLightning.java | 167 ++++ .../particle/ParticleLightningPulse.java | 38 + .../client/particle/ParticleMagicBubble.java | 4 +- .../client/particle/ParticleMagicFlame.java | 7 +- .../client/particle/ParticlePath.java | 53 +- .../particle/ParticleRotatingSparkle.java | 60 -- .../client/particle/ParticleScorch.java | 70 ++ .../client/particle/ParticleSnow.java | 37 +- .../client/particle/ParticleSpark.java | 83 +- .../client/particle/ParticleSparkle.java | 69 +- .../client/particle/ParticleTargeted.java | 105 +++ .../client/particle/ParticleWizardry.java | 334 +++++++- .../wizardry/client/renderer/RenderArc.java | 187 ----- .../client/renderer/RenderLightningPulse.java | 72 -- .../wizardry/entity/EntityArc.java | 78 -- .../entity/construct/EntityBlizzard.java | 23 +- .../entity/construct/EntityDecay.java | 2 +- .../entity/construct/EntityForcefield.java | 4 +- .../entity/construct/EntityHammer.java | 25 +- .../entity/construct/EntityHealAura.java | 4 +- .../construct/EntityLightningPulse.java | 18 - .../construct/EntityLightningSigil.java | 27 +- .../entity/construct/EntityTornado.java | 14 +- .../wizardry/entity/living/EntityDecoy.java | 19 +- .../entity/living/EntityEvilWizard.java | 2 +- .../entity/living/EntityIceGiant.java | 4 +- .../entity/living/EntityIceWraith.java | 4 +- .../entity/living/EntityLightningWraith.java | 4 +- .../entity/living/EntityShadowWraith.java | 10 +- .../entity/living/EntitySilverfishMinion.java | 2 +- .../entity/living/EntitySpiderMinion.java | 2 +- .../entity/living/EntitySpiritHorse.java | 4 +- .../entity/living/EntitySpiritWolf.java | 4 +- .../entity/living/EntityStormElemental.java | 5 +- .../wizardry/entity/living/EntityWizard.java | 2 +- .../entity/living/ISummonedCreature.java | 2 +- .../entity/projectile/EntityDarknessOrb.java | 6 +- .../entity/projectile/EntityDart.java | 2 +- .../entity/projectile/EntityFirebomb.java | 11 +- .../entity/projectile/EntityForceArrow.java | 11 + .../entity/projectile/EntityForceOrb.java | 4 +- .../entity/projectile/EntityIceCharge.java | 4 +- .../entity/projectile/EntityIceLance.java | 2 +- .../entity/projectile/EntityIceShard.java | 6 +- .../projectile/EntityLightningArrow.java | 6 + .../entity/projectile/EntityMagicArrow.java | 8 +- .../entity/projectile/EntityMagicMissile.java | 32 +- .../entity/projectile/EntityPoisonBomb.java | 10 +- .../entity/projectile/EntitySmokeBomb.java | 6 +- .../entity/projectile/EntitySparkBomb.java | 11 +- .../wizardry/potion/PotionFrost.java | 2 +- .../java/electroblob/wizardry/spell/Arc.java | 9 +- .../wizardry/spell/ArcaneJammer.java | 2 +- .../electroblob/wizardry/spell/Banish.java | 2 +- .../wizardry/spell/ChainLightning.java | 11 +- .../wizardry/spell/Clairvoyance.java | 4 +- .../wizardry/spell/CurseOfSoulbinding.java | 6 +- .../wizardry/spell/Entrapment.java | 2 +- .../wizardry/spell/FlamingWeapon.java | 2 +- .../electroblob/wizardry/spell/Flight.java | 4 +- .../wizardry/spell/FontOfMana.java | 4 +- .../wizardry/spell/ForestsCurse.java | 8 +- .../electroblob/wizardry/spell/Freeze.java | 4 +- .../wizardry/spell/FreezingWeapon.java | 2 +- .../electroblob/wizardry/spell/FrostRay.java | 6 +- .../electroblob/wizardry/spell/Glide.java | 4 +- .../electroblob/wizardry/spell/GroupHeal.java | 14 +- .../electroblob/wizardry/spell/HealAlly.java | 6 +- .../electroblob/wizardry/spell/IceStatue.java | 6 +- .../wizardry/spell/ImbueWeapon.java | 2 +- .../wizardry/spell/Intimidate.java | 2 +- .../wizardry/spell/InvigoratingPresence.java | 2 +- .../wizardry/spell/InvokeWeather.java | 2 +- .../wizardry/spell/Levitation.java | 2 +- .../electroblob/wizardry/spell/LifeDrain.java | 6 +- .../wizardry/spell/LightningPulse.java | 15 +- .../wizardry/spell/LightningRay.java | 41 +- .../wizardry/spell/LightningWeb.java | 42 +- .../wizardry/spell/Metamorphosis.java | 3 +- .../wizardry/spell/MindControl.java | 4 +- .../electroblob/wizardry/spell/MindTrick.java | 2 +- .../electroblob/wizardry/spell/Petrify.java | 4 +- .../wizardry/spell/PlagueOfDarkness.java | 4 +- .../electroblob/wizardry/spell/Poison.java | 4 +- .../electroblob/wizardry/spell/Shockwave.java | 4 +- .../electroblob/wizardry/spell/Slime.java | 2 +- .../electroblob/wizardry/spell/Snare.java | 6 +- .../electroblob/wizardry/spell/SpellBuff.java | 4 +- .../wizardry/spell/SpellConjuration.java | 2 +- .../wizardry/spell/SummonIronGolem.java | 2 +- .../wizardry/spell/SummonSnowGolem.java | 2 +- .../wizardry/spell/Thunderstorm.java | 23 +- .../wizardry/spell/WallOfFrost.java | 6 +- .../electroblob/wizardry/spell/Wither.java | 4 +- .../wizardry/util/ParticleBuilder.java | 710 +++++++++++------- .../ebwizardry/textures/particle/ice_0.png | Bin 0 -> 307 bytes .../ebwizardry/textures/particle/ice_1.png | Bin 0 -> 238 bytes .../ebwizardry/textures/particle/ice_2.png | Bin 0 -> 217 bytes .../ebwizardry/textures/particle/ice_3.png | Bin 0 -> 191 bytes .../ebwizardry/textures/particle/ice_4.png | Bin 0 -> 289 bytes .../ebwizardry/textures/particle/ice_5.png | Bin 0 -> 259 bytes .../ebwizardry/textures/particle/ice_6.png | Bin 0 -> 187 bytes .../ebwizardry/textures/particle/ice_7.png | Bin 0 -> 183 bytes .../textures/particle/ice_particles.png | Bin 957 -> 0 bytes .../ebwizardry/textures/particle/leaf_0.png | Bin 0 -> 196 bytes .../ebwizardry/textures/particle/leaf_1.png | Bin 0 -> 187 bytes .../ebwizardry/textures/particle/leaf_10.png | Bin 0 -> 184 bytes .../ebwizardry/textures/particle/leaf_11.png | Bin 0 -> 184 bytes .../ebwizardry/textures/particle/leaf_12.png | Bin 0 -> 191 bytes .../ebwizardry/textures/particle/leaf_13.png | Bin 0 -> 180 bytes .../ebwizardry/textures/particle/leaf_14.png | Bin 0 -> 181 bytes .../ebwizardry/textures/particle/leaf_15.png | Bin 0 -> 243 bytes .../ebwizardry/textures/particle/leaf_2.png | Bin 0 -> 194 bytes .../ebwizardry/textures/particle/leaf_3.png | Bin 0 -> 167 bytes .../ebwizardry/textures/particle/leaf_4.png | Bin 0 -> 197 bytes .../ebwizardry/textures/particle/leaf_5.png | Bin 0 -> 229 bytes .../ebwizardry/textures/particle/leaf_6.png | Bin 0 -> 223 bytes .../ebwizardry/textures/particle/leaf_7.png | Bin 0 -> 232 bytes .../ebwizardry/textures/particle/leaf_8.png | Bin 0 -> 251 bytes .../ebwizardry/textures/particle/leaf_9.png | Bin 0 -> 243 bytes .../textures/particle/leaf_particles.png | Bin 803 -> 0 bytes .../textures/particle/lightning_0_0.png | Bin 0 -> 299 bytes .../textures/particle/lightning_0_1.png | Bin 0 -> 353 bytes .../textures/particle/lightning_0_2.png | Bin 0 -> 340 bytes .../textures/particle/lightning_0_3.png | Bin 0 -> 337 bytes .../textures/particle/lightning_1_0.png | Bin 0 -> 315 bytes .../textures/particle/lightning_1_1.png | Bin 0 -> 355 bytes .../textures/particle/lightning_1_2.png | Bin 0 -> 352 bytes .../textures/particle/lightning_1_3.png | Bin 0 -> 346 bytes .../textures/particle/lightning_2_0.png | Bin 0 -> 301 bytes .../textures/particle/lightning_2_1.png | Bin 0 -> 317 bytes .../textures/particle/lightning_2_2.png | Bin 0 -> 300 bytes .../textures/particle/lightning_2_3.png | Bin 0 -> 318 bytes .../textures/particle/lightning_3_0.png | Bin 0 -> 291 bytes .../textures/particle/lightning_3_1.png | Bin 0 -> 328 bytes .../textures/particle/lightning_3_2.png | Bin 0 -> 319 bytes .../textures/particle/lightning_3_3.png | Bin 0 -> 302 bytes .../textures/particle/lightning_4_0.png | Bin 0 -> 283 bytes .../textures/particle/lightning_4_1.png | Bin 0 -> 285 bytes .../textures/particle/lightning_4_2.png | Bin 0 -> 298 bytes .../textures/particle/lightning_4_3.png | Bin 0 -> 295 bytes .../textures/particle/lightning_5_0.png | Bin 0 -> 300 bytes .../textures/particle/lightning_5_1.png | Bin 0 -> 314 bytes .../textures/particle/lightning_5_2.png | Bin 0 -> 298 bytes .../textures/particle/lightning_5_3.png | Bin 0 -> 298 bytes .../textures/particle/lightning_6_0.png | Bin 0 -> 291 bytes .../textures/particle/lightning_6_1.png | Bin 0 -> 313 bytes .../textures/particle/lightning_6_2.png | Bin 0 -> 312 bytes .../textures/particle/lightning_6_3.png | Bin 0 -> 304 bytes .../textures/particle/lightning_7_0.png | Bin 0 -> 313 bytes .../textures/particle/lightning_7_1.png | Bin 0 -> 323 bytes .../textures/particle/lightning_7_2.png | Bin 0 -> 328 bytes .../textures/particle/lightning_7_3.png | Bin 0 -> 326 bytes .../textures/particle/lightning_particles.png | Bin 2602 -> 0 bytes .../lightning_pulse_0.png | Bin .../lightning_pulse_1.png | Bin .../lightning_pulse_2.png | Bin .../lightning_pulse_3.png | Bin .../lightning_pulse_4.png | Bin .../lightning_pulse_5.png | Bin .../lightning_pulse_6.png | Bin .../lightning_pulse_7.png | Bin .../particle/{path_particles.png => path.png} | Bin .../ebwizardry/textures/particle/scorch_0.png | Bin 0 -> 840 bytes .../ebwizardry/textures/particle/scorch_1.png | Bin 0 -> 867 bytes .../ebwizardry/textures/particle/scorch_2.png | Bin 0 -> 874 bytes .../ebwizardry/textures/particle/scorch_3.png | Bin 0 -> 820 bytes .../ebwizardry/textures/particle/scorch_4.png | Bin 0 -> 848 bytes .../ebwizardry/textures/particle/scorch_5.png | Bin 0 -> 862 bytes .../ebwizardry/textures/particle/scorch_6.png | Bin 0 -> 865 bytes .../ebwizardry/textures/particle/scorch_7.png | Bin 0 -> 885 bytes .../ebwizardry/textures/particle/snow_0.png | Bin 0 -> 140 bytes .../ebwizardry/textures/particle/snow_1.png | Bin 0 -> 140 bytes .../ebwizardry/textures/particle/snow_2.png | Bin 0 -> 145 bytes .../ebwizardry/textures/particle/snow_3.png | Bin 0 -> 137 bytes .../textures/particle/snow_particles.png | Bin 179 -> 0 bytes .../textures/particle/sparkle_0.png | Bin 0 -> 307 bytes .../textures/particle/sparkle_1.png | Bin 0 -> 239 bytes .../textures/particle/sparkle_10.png | Bin 0 -> 134 bytes .../textures/particle/sparkle_2.png | Bin 0 -> 240 bytes .../textures/particle/sparkle_3.png | Bin 0 -> 215 bytes .../textures/particle/sparkle_4.png | Bin 0 -> 298 bytes .../textures/particle/sparkle_5.png | Bin 0 -> 243 bytes .../textures/particle/sparkle_6.png | Bin 0 -> 182 bytes .../textures/particle/sparkle_7.png | Bin 0 -> 191 bytes .../textures/particle/sparkle_8.png | Bin 0 -> 257 bytes .../textures/particle/sparkle_9.png | Bin 0 -> 181 bytes .../textures/particle/sparkle_particles.png | Bin 917 -> 0 bytes 201 files changed, 1682 insertions(+), 1551 deletions(-) create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java delete mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java delete mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java delete mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleLightningPulse.java delete mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleRotatingSparkle.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleScorch.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java delete mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderArc.java delete mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderLightningPulse.java delete mode 100644 src/main/java/electroblob/wizardry/entity/EntityArc.java delete mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_7.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/particle/ice_particles.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_10.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_11.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_12.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_13.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_14.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_15.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_8.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_9.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/particle/leaf_particles.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_0_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_0_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_0_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_0_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_1_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_1_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_1_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_1_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_2_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_2_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_2_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_2_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_3_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_3_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_3_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_3_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_4_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_4_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_4_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_4_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_5_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_5_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_5_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_5_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_6_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_6_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_6_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_6_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_7_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_7_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_7_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_7_3.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/particle/lightning_particles.png rename src/main/resources/assets/ebwizardry/textures/{entity => particle}/lightning_pulse_0.png (100%) rename src/main/resources/assets/ebwizardry/textures/{entity => particle}/lightning_pulse_1.png (100%) rename src/main/resources/assets/ebwizardry/textures/{entity => particle}/lightning_pulse_2.png (100%) rename src/main/resources/assets/ebwizardry/textures/{entity => particle}/lightning_pulse_3.png (100%) rename src/main/resources/assets/ebwizardry/textures/{entity => particle}/lightning_pulse_4.png (100%) rename src/main/resources/assets/ebwizardry/textures/{entity => particle}/lightning_pulse_5.png (100%) rename src/main/resources/assets/ebwizardry/textures/{entity => particle}/lightning_pulse_6.png (100%) rename src/main/resources/assets/ebwizardry/textures/{entity => particle}/lightning_pulse_7.png (100%) rename src/main/resources/assets/ebwizardry/textures/particle/{path_particles.png => path.png} (100%) create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/scorch_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/scorch_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/scorch_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/scorch_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/scorch_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/scorch_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/scorch_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/scorch_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/snow_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/snow_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/snow_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/snow_3.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/particle/snow_particles.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_10.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_8.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_9.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/particle/sparkle_particles.png diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index 367352c7..846d65ab 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -70,8 +70,6 @@ public class CommonProxy { public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){ } - - public void spawnEntityParticle(World world, Entity entity, int maxAge, float r, float g, float b){} // SECTION Items // =============================================================================================================== diff --git a/src/main/java/electroblob/wizardry/WizardryEventHandler.java b/src/main/java/electroblob/wizardry/WizardryEventHandler.java index a46d2730..f5ea91ac 100644 --- a/src/main/java/electroblob/wizardry/WizardryEventHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryEventHandler.java @@ -206,22 +206,13 @@ public final class WizardryEventHandler { // Static Aura if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura)){ - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(event.getEntityLiving().posX, event.getEntityLiving().posY + 1, - event.getEntityLiving().posZ, attacker.posX, attacker.posY + attacker.height / 2, - attacker.posZ); - world.spawnEntity(arc); - }else{ - for(int i = 0; i < 8; i++){ - ParticleBuilder.create(Type.SPARK).pos(attacker.posX + world.rand.nextFloat() - 0.5, - attacker.getEntityBoundingBox().minY + attacker.height / 2 + world.rand.nextFloat() * 2 - 1, - attacker.posZ + world.rand.nextFloat() - 0.5).spawn(world); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, attacker.posX + world.rand.nextFloat() - 0.5, - attacker.getEntityBoundingBox().minY + attacker.height / 2 + world.rand.nextFloat() * 2 - - 1, - attacker.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); - } + if(world.isRemote){ + + ParticleBuilder.create(Type.LIGHTNING).entity(event.getEntity()).pos(0, event.getEntity().height/2, 0) + .target(attacker).spawn(world); + + ParticleBuilder.spawnShockParticles(world, attacker.posX, + attacker.getEntityBoundingBox().minY + attacker.height, attacker.posZ); } attacker.attackEntityFrom( diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java index 27bc7046..a10aa77e 100644 --- a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java +++ b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java @@ -43,7 +43,7 @@ public class BlockCrystalFlower extends BlockBush { if(world.isRemote && random.nextBoolean()){ ParticleBuilder.create(Type.SPARKLE) .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble() / 2 + 0.5, pos.getZ() + random.nextDouble()).vel(0, 0.01, 0) - .lifetime(20 + random.nextInt(10)).colour(0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2), + .time(20 + random.nextInt(10)).clr(0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/block/BlockSpectral.java b/src/main/java/electroblob/wizardry/block/BlockSpectral.java index 708f3fe6..07023985 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSpectral.java +++ b/src/main/java/electroblob/wizardry/block/BlockSpectral.java @@ -70,9 +70,9 @@ public class BlockSpectral extends BlockContainer { // Top surface for(int i=0; i<2; i++){ ParticleBuilder.create(Type.DUST) - .pos(pos.getX() + random.nextDouble(), pos.getY() + 1, pos.getZ() + random.nextDouble()) - .lifetime((int)(16.0D / (Math.random() * 0.8D + 0.2D))) - .colour(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f) + .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble(), pos.getZ() + random.nextDouble()) + .time((int)(16.0D / (Math.random() * 0.8D + 0.2D))) + .clr(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f) .shaded(true).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index d688d89f..82630f2d 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -13,25 +13,9 @@ import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.gui.GuiSpellDisplay; import electroblob.wizardry.client.gui.GuiWizardHandbook; import electroblob.wizardry.client.model.ModelWizardArmour; -import electroblob.wizardry.client.particle.ParticleBlizzard; -import electroblob.wizardry.client.particle.ParticleBuff; -import electroblob.wizardry.client.particle.ParticleDarkMagic; -import electroblob.wizardry.client.particle.ParticleDust; -import electroblob.wizardry.client.particle.ParticleFlash; -import electroblob.wizardry.client.particle.ParticleIce; -import electroblob.wizardry.client.particle.ParticleLeaf; -import electroblob.wizardry.client.particle.ParticleMagicBubble; -import electroblob.wizardry.client.particle.ParticleMagicFlame; -import electroblob.wizardry.client.particle.ParticlePath; -import electroblob.wizardry.client.particle.ParticleRotatingSparkle; -import electroblob.wizardry.client.particle.ParticleSnow; -import electroblob.wizardry.client.particle.ParticleSpark; -import electroblob.wizardry.client.particle.ParticleSparkle; -import electroblob.wizardry.client.particle.ParticleTornado; -import electroblob.wizardry.client.particle.ParticleWizardry; +import electroblob.wizardry.client.particle.*; import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory; import electroblob.wizardry.client.renderer.LayerStone; -import electroblob.wizardry.client.renderer.RenderArc; import electroblob.wizardry.client.renderer.RenderArcaneWorkbench; import electroblob.wizardry.client.renderer.RenderBlackHole; import electroblob.wizardry.client.renderer.RenderBlank; @@ -45,7 +29,6 @@ import electroblob.wizardry.client.renderer.RenderHammer; import electroblob.wizardry.client.renderer.RenderIceGiant; import electroblob.wizardry.client.renderer.RenderIceSpike; import electroblob.wizardry.client.renderer.RenderLightningDisc; -import electroblob.wizardry.client.renderer.RenderLightningPulse; import electroblob.wizardry.client.renderer.RenderMagicArrow; import electroblob.wizardry.client.renderer.RenderMagicLight; import electroblob.wizardry.client.renderer.RenderPhoenix; @@ -55,7 +38,6 @@ import electroblob.wizardry.client.renderer.RenderSpiritHorse; import electroblob.wizardry.client.renderer.RenderSpiritWolf; import electroblob.wizardry.client.renderer.RenderStatue; import electroblob.wizardry.client.renderer.RenderWizard; -import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.entity.EntityShield; import electroblob.wizardry.entity.construct.EntityArrowRain; import electroblob.wizardry.entity.construct.EntityBlackHole; @@ -71,7 +53,6 @@ import electroblob.wizardry.entity.construct.EntityHailstorm; import electroblob.wizardry.entity.construct.EntityHammer; import electroblob.wizardry.entity.construct.EntityHealAura; import electroblob.wizardry.entity.construct.EntityIceSpike; -import electroblob.wizardry.entity.construct.EntityLightningPulse; import electroblob.wizardry.entity.construct.EntityLightningSigil; import electroblob.wizardry.entity.construct.EntityTornado; import electroblob.wizardry.entity.living.EntityDecoy; @@ -291,27 +272,30 @@ public class ClientProxy extends CommonProxy { public void initParticleFactories(){ factories = new HashMap<>(); - - factories.put(Type.BLIZZARD, (world, x, y, z) -> new ParticleBlizzard(world, x, y, z)); - factories.put(Type.DARK_MAGIC, (world, x, y, z) -> new ParticleDarkMagic(world, x, y, z)); - factories.put(Type.DUST, (world, x, y, z) -> new ParticleDust(world, x, y, z)); - factories.put(Type.FLASH, (world, x, y, z) -> new ParticleFlash(world, x, y, z)); - factories.put(Type.ICE, (world, x, y, z) -> new ParticleIce(world, x, y, z)); - factories.put(Type.LEAF, (world, x, y, z) -> new ParticleLeaf(world, x, y, z)); - factories.put(Type.MAGIC_BUBBLE, (world, x, y, z) -> new ParticleMagicBubble(world, x, y, z)); - factories.put(Type.MAGIC_FIRE, (world, x, y, z) -> new ParticleMagicFlame(world, x, y, z)); - factories.put(Type.PATH, (world, x, y, z) -> new ParticlePath(world, x, y, z)); - factories.put(Type.SNOW, (world, x, y, z) -> new ParticleSnow(world, x, y, z)); - factories.put(Type.SPARK, (world, x, y, z) -> new ParticleSpark(world, x, y, z)); - factories.put(Type.SPARKLE, (world, x, y, z) -> new ParticleSparkle(world, x, y, z)); - factories.put(Type.SPARKLE_ROTATING, (world, x, y, z) -> new ParticleRotatingSparkle(world, x, y, z)); + + factories.put(Type.BEAM, ParticleBeam::new); + factories.put(Type.BUFF, ParticleBuff::new); + factories.put(Type.DARK_MAGIC, ParticleDarkMagic::new); + factories.put(Type.DUST, ParticleDust::new); + factories.put(Type.FLASH, ParticleFlash::new); + factories.put(Type.ICE, ParticleIce::new); + factories.put(Type.LEAF, ParticleLeaf::new); + factories.put(Type.LIGHTNING, ParticleLightning::new); + factories.put(Type.LIGHTNING_PULSE, ParticleLightningPulse::new); + factories.put(Type.MAGIC_BUBBLE, ParticleMagicBubble::new); + factories.put(Type.MAGIC_FIRE, ParticleMagicFlame::new); + factories.put(Type.PATH, ParticlePath::new); + factories.put(Type.SCORCH, ParticleScorch::new); + factories.put(Type.SNOW, ParticleSnow::new); + factories.put(Type.SPARK, ParticleSpark::new); + factories.put(Type.SPARKLE, ParticleSparkle::new); } @Override public ParticleWizardry createParticle(Type type, World world, double x, double y, double z){ IWizardryParticleFactory factory = factories.get(type); if(factory == null){ - Wizardry.logger.warn("Unrecognised particle type %s! Ensure the particle is properly registered.", type); + Wizardry.logger.warn("Unrecognised particle type %s ! Ensure the particle is properly registered.", type); return null; } return factory.createParticle(world, x, y, z); @@ -431,8 +415,8 @@ public class ClientProxy extends CommonProxy { double x = caster.posX + radius * Math.cos(angle); double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2; double z = caster.posZ + radius * Math.sin(angle); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.02, 0).colour(0.6f, 1, 0.6f) - .lifetime(80 + world.rand.nextInt(10)).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.02, 0).clr(0.6f, 1, 0.6f) + .time(80 + world.rand.nextInt(10)).spawn(world); } for(int i = 0; i < 20; i++){ double radius = 1; @@ -578,7 +562,6 @@ public class ClientProxy extends CommonProxy { manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/smoke_bomb.png"), false)); // Effects and constructs - RenderingRegistry.registerEntityRenderingHandler(EntityArc.class, RenderArc::new); RenderingRegistry.registerEntityRenderingHandler(EntityBlackHole.class, RenderBlackHole::new); RenderingRegistry.registerEntityRenderingHandler(EntityShield.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityBubble.class, RenderBubble::new); @@ -608,7 +591,6 @@ public class ClientProxy extends CommonProxy { RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class, manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f)); RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new); - RenderingRegistry.registerEntityRenderingHandler(EntityLightningPulse.class, manager -> new RenderLightningPulse(manager, 8.0f)); // TESRs ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench()); diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java new file mode 100644 index 00000000..63548e0b --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java @@ -0,0 +1,95 @@ +package electroblob.wizardry.client.particle; + +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.world.World; + +public class ParticleBeam extends ParticleTargeted { + + /** Half the width of the outermost layer. */ + private static final float THICKNESS = 0.1f; + + public ParticleBeam(World world, double x, double y, double z){ + super(world, x, y, z); // Does not have a texture! + this.setRBGColorF(1, 1, 1); + this.setMaxAge(1); + this.particleScale = 1; + } + + @Override + public int getFXLayer(){ + return 3; + } + + @Override + protected void draw(Tessellator tessellator, double length, float partialTicks){ + + float scale = this.particleScale; + + if(this.particleMaxAge > 1){ + float ageFraction = (particleAge + partialTicks - 1)/particleMaxAge; + // Squaring this makes it look smoother than a linear shrinking effect + scale = this.particleScale * (1 - ageFraction*ageFraction); + } + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + for(int layer=0; layer<3; layer++){ + drawSegment(tessellator, layer, 0, 0, 0, 0, 0, length, THICKNESS * scale); + } + + GlStateManager.enableTexture2D(); + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + } + + /** Draws the given layer of a segment of the arc, from the point (x1, y1, z1) to the point (x2, y2, z2), with the given thickness. */ + private void drawSegment(Tessellator tessellator, int layer, double x1, double y1, double z1, double x2, double y2, double z2, float thickness){ + + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); + + switch(layer){ + + case 0: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, 0.25f*thickness, 1, 1, 1, 1); + break; + + case 1: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, 0.6f*thickness, (particleRed + 1)/2, (particleGreen + 1)/2, + (particleBlue + 1)/2, 0.65f); + break; + + case 2: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, thickness, particleRed, particleGreen, particleBlue, 0.3f); + break; + } + + tessellator.draw(); + } + + /** Draws a single box for one segment of the arc, from the point (x1, y1, z1) to the point (x2, y2, z2), with given width and colour. */ + private void drawShearedBox(BufferBuilder buffer, double x1, double y1, double z1, double x2, double y2, double z2, float width, float r, float g, float b, float a){ + + buffer.pos(x1-width, y1-width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2-width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1-width, y1+width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2+width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1+width, y1+width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2+width, y2+width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1+width, y1-width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2+width, y2-width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1-width, y1-width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2-width, z2).color(r, g, b, a).endVertex(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java deleted file mode 100644 index 9f7c2828..00000000 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java +++ /dev/null @@ -1,67 +0,0 @@ -package electroblob.wizardry.client.particle; - -import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -@SideOnly(Side.CLIENT) -public class ParticleBlizzard extends ParticleSnow { - - private double angle; - private double radius; - private double speed; - - public ParticleBlizzard(World world, double ox, double y, double oz){ - super(world, ox, y, oz); - this.angle = this.rand.nextDouble() * Math.PI * 2; - double x = ox - Math.cos(angle) * radius; - double z = oz + radius * Math.sin(angle); - this.setPosition(x, y, z); - this.prevPosX = x; - this.prevPosY = y; - this.prevPosZ = z; - if(rand.nextBoolean()){ - speed = rand.nextDouble() * 2 + 1; - }else{ - speed = rand.nextDouble() * -2 - 1; - } - this.multipleParticleScaleBy(1.5f); - } - - // @Override - // public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float - // rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ - // if(this.particleAge < this.particleMaxAge / 3 || (this.particleAge + this.particleMaxAge) / 3 % 2 == 0){ - // super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); - // } - // } - - @Override - public void onUpdate(){ - - this.prevPosX = this.posX; - this.prevPosY = this.posY; - this.prevPosZ = this.posZ; - - if(this.particleAge++ >= this.particleMaxAge){ - this.setExpired(); - } - - // This is in radians per tick... - double omega = Math.signum(speed) * ((Math.PI * 2) / 20 - speed / (20 * radius)); - - // v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi. - this.angle += omega; - - this.motionY -= 0.04D * (double)this.particleGravity; - this.motionZ = radius * omega * Math.cos(angle); - this.motionX = radius * omega * Math.sin(angle); - this.move(motionX, motionY, motionZ); - - if(this.particleAge > this.particleMaxAge / 2){ - this.setAlphaF( - 1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); - } - - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java index b7ea5432..9e9a46d0 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java @@ -21,36 +21,41 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleBuff extends ParticleEntityLinked { +public class ParticleBuff extends ParticleWizardry { private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/buff.png"); private final boolean mirror; - public ParticleBuff(World world, Entity entity, float r, float g, float b, boolean mirror){ - super(world, entity); - this.setRBGColorF(r, g, b); - this.mirror = mirror; - } - - public ParticleBuff(World world, Entity entity, int maxAge, float r, float g, float b, boolean mirror){ - super(world, entity, maxAge); - this.setRBGColorF(r, g, b); - this.mirror = mirror; - } - - @Override - public void init(){ - this.particleGravity = 0; - this.posY += 1; + public ParticleBuff(World world, double x, double y, double z){ + super(world, x, y, z); + this.setVelocity(0, 0.27, 0); // Approximately what it was before + this.mirror = world.rand.nextBoolean(); + this.setMaxAge(15); + this.setGravity(false); + this.canCollide = false; } @Override public void onUpdate(){ super.onUpdate(); - this.setPosition(this.entity.posX, this.entity.posY + 1 + 4f * this.particleAge/this.particleMaxAge, this.entity.posZ); if(this.particleAge > this.particleMaxAge/2) this.particleAlpha = 2f - 2f*(float)this.particleAge/(float)this.particleMaxAge; } + /* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png + * to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the + * render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine + * for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was + * presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning + * you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten + * anyway since they bind their own textures. It is of course important to bind the texture every time you render a + * custom particle, but I don't see how you could do it any other way, since you don't have access to + * EffectRenderer. */ + @Override + public int getFXLayer(){ + // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. + return 3; + } + @Override public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java b/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java deleted file mode 100644 index fadf37d9..00000000 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java +++ /dev/null @@ -1,130 +0,0 @@ -package electroblob.wizardry.client.particle; - -import org.lwjgl.opengl.GL11; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.entity.Entity; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.World; - -@Deprecated -public abstract class ParticleCustomTexture extends ParticleWizardry { - - public ParticleCustomTexture(World world, double x, double y, double z){ - super(world, x, y, z); - } - - /** - * Returns a ResourceLocation for the particle's texture sheet. Do not create a new ResourceLocation in this method, - * only return a constant. - */ - public abstract ResourceLocation getTexture(); - - /** Returns how many 'frames' there are in the x direction on the texture. */ - protected abstract int getXFrames(); - - /** Returns how many 'frames' there are in the y direction on the texture. */ - protected abstract int getYFrames(); - - /* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png - * to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the - * render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine - * for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was - * presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning - * you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten - * anyway since they bind their own textures. It is of course important to bind the texture every time you render a - * custom particle, but I don't see how you could do it any other way, since you don't have access to - * EffectRenderer. */ - @Override - public int getFXLayer(){ - // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. - return 3; - } - - @Override - public void setParticleTextureIndex(int index){ - this.particleTextureIndexX = index % getXFrames(); - this.particleTextureIndexY = index / getYFrames(); - } - - // Overridden to bind the new texture. I think this can be done with TextureAtlasSprite, but this works as it is - // so I'm not changing it for the time being. - @Override - public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, - float rotationYZ, float rotationXY, float rotationXZ){ - - GlStateManager.pushMatrix(); - - this.applyGLStateChanges(); - - // This stuff does the shading. It vanilla does this later on for each point, but this also seems to work. - int brightness = this.getBrightnessForRender(partialTicks); - int lightmapX = brightness % 65536; - int lightmapY = brightness / 65536; - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)lightmapX / 1.0F, - (float)lightmapY / 1.0F); - - RenderHelper.disableStandardItemLighting(); - - Minecraft.getMinecraft().getTextureManager().bindTexture(getTexture()); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); - - float u1 = (float)this.particleTextureIndexX / (float)getXFrames(); - float u2 = u1 + 1.0f / getXFrames(); - float v1 = (float)this.particleTextureIndexY / (float)getYFrames(); - float v2 = v1 + 1.0f / getYFrames(); - float scale = 0.1F * this.particleScale; - - // I'm pretty sure these were always static. - Particle.interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks; - Particle.interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks; - Particle.interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks; - - float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); - float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); - float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); - - buffer.pos((double)(x - rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), - (double)(z - rotationYZ * scale - rotationXZ * scale)).tex(u2, v2) - .color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos((double)(x - rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), - (double)(z - rotationYZ * scale + rotationXZ * scale)).tex(u2, v1) - .color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos((double)(x + rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), - (double)(z + rotationYZ * scale + rotationXZ * scale)).tex(u1, v1) - .color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos((double)(x + rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), - (double)(z + rotationYZ * scale - rotationXZ * scale)).tex(u1, v2) - .color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - ; - - Tessellator.getInstance().draw(); - - this.undoGLStateChanges(); - - GlStateManager.popMatrix(); - - } - - /** - * Override to add any GL state changes, like blending. Does nothing by default. State changes should be done - * using GLStateManager, not using GL11 directly (as is the case with all rendering code now). - */ - public void applyGLStateChanges(){ - } - - /** - * Override to undo any GL state changes, like blending. Does nothing by default. State changes should be done - * using GLStateManager, not using GL11 directly (as is the case with all rendering code now). - */ - public void undoGLStateChanges(){ - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java b/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java deleted file mode 100644 index 76dfaefb..00000000 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java +++ /dev/null @@ -1,61 +0,0 @@ -package electroblob.wizardry.client.particle; - -import net.minecraft.client.particle.Particle; -import net.minecraft.entity.Entity; -import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -/** - * Abstract superclass for particles that are linked to entities, i.e. move with a given entity. This is generally used - * for visual effects in spell casting. - * - * @author Electroblob - * @since Wizardry 4.2 - */ -@SideOnly(Side.CLIENT) -public abstract class ParticleEntityLinked extends Particle { - - /** True if the particle always renders at full brightness. Defaults to false. */ - protected boolean fullBrightness = false; - - /** The entity this particle is linked to. The particle will move with this entity. */ - protected Entity entity; - - public ParticleEntityLinked(World world, Entity entity){ - super(world, entity.posX, entity.posY, entity.posZ, entity.motionX, entity.motionY, entity.motionZ); - this.entity = entity; - this.init(); - } - - public ParticleEntityLinked(World world, Entity entity, int maxAge){ - this(world, entity); - this.particleMaxAge = maxAge; - } - - /** - * Called from both constructors to set constants, avoiding duplicate code. Common fields to set here include: - * particleScale, particleGravity, canCollide, fullBrightness and setting the texture index. - */ - public abstract void init(); - - /* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png - * to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the - * render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine - * for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was - * presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning - * you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten - * anyway since they bind their own textures. It is of course important to bind the texture every time you render a - * custom particle, but I don't see how you could do it any other way, since you don't have access to - * EffectRenderer. */ - @Override - public int getFXLayer(){ - // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. - return 3; - } - - @Override - public int getBrightnessForRender(float partialTick){ - return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick); - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java index 0e23c95f..a24cd16b 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java @@ -17,13 +17,13 @@ public class ParticleFlash extends ParticleWizardry { super(world, x, y, z); this.setRBGColorF(1, 1, 1); this.particleScale = 0.6f; // 7.1f is the value used in fireworks - this.particleMaxAge = 4; + this.particleMaxAge = 6; } @Override public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ - float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F) * 0.25F * (float)Math.PI); - this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F) * 0.25F * 0.5F); + float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * (float)Math.PI); + this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * 0.5F); float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java index 7c703f7c..bc530448 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java @@ -1,40 +1,36 @@ package electroblob.wizardry.client.particle; -import electroblob.wizardry.Wizardry; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleIce extends ParticleCustomTexture { - - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/ice_particles.png"); +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleIce extends ParticleWizardry { + private static final ResourceLocation[] TEXTURES = generateTextures("ice", 8); + public ParticleIce(World world, double x, double y, double z){ - super(world, x, y, z); - this.setParticleTextureIndex(rand.nextInt(8)); + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + this.canCollide = true; // Defaults + this.setRBGColorF(1, 1, 1); this.particleScale *= 0.75f; this.setGravity(true); this.shaded = false; } - @Override - public ResourceLocation getTexture(){ - return TEXTURE; - } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 4; + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); + } } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java index dbfab7a5..327ac57a 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java @@ -1,41 +1,47 @@ package electroblob.wizardry.client.particle; -import electroblob.wizardry.Wizardry; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleLeaf extends ParticleCustomTexture { +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleLeaf extends ParticleWizardry { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/leaf_particles.png"); + private static final ResourceLocation[] TEXTURES = generateTextures("leaf", 16); public ParticleLeaf(World world, double x, double y, double z){ - super(world, x, y, z); + + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + this.setVelocity(0, -0.03, 0); - this.setLifetime(10 + rand.nextInt(5)); - this.setParticleTextureIndex(rand.nextInt(16)); + this.setMaxAge(10 + rand.nextInt(5)); this.particleScale *= 1.4f; this.particleGravity = 0; this.canCollide = true; // Produces a variety of browns and greens this.setRBGColorF(0.1f + 0.3f * world.rand.nextFloat(), 0.5f + 0.3f * world.rand.nextFloat(), 0.1f); } - + @Override - public ResourceLocation getTexture(){ - return TEXTURE; + public void onUpdate(){ + + super.onUpdate(); + + // Fading + if(this.particleAge > this.particleMaxAge / 2){ + this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + } } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 4; + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); + } } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java new file mode 100644 index 00000000..80f43088 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java @@ -0,0 +1,167 @@ +package electroblob.wizardry.client.particle; + +import java.util.Random; + +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.world.World; + +public class ParticleLightning extends ParticleTargeted { + + /** Half the width of the outermost layer. */ + private static final float THICKNESS = 0.04f; + /** Maximum length of a segment. */ + private static final double MAX_SEGMENT_LENGTH = 0.6; + /** Minimum length of a segment. */ + private static final double MIN_SEGMENT_LENGTH = 0.2; + /** Maximum deviation (in x or y, as drawn before transformations) from the centreline. */ + private static final double VERTEX_JITTER = 0.15; + /** Maximum number of segments a fork can have before ending. */ + private static final int MAX_FORK_SEGMENTS = 3; + /** Probability (as a fraction) that a vertex will have a fork. */ + private static final float FORK_CHANCE = 0.3f; + /** Number of ticks to wait before the arc changes shape again. */ + private static final int UPDATE_PERIOD = 1; + + /** A random long value used by the renderer as a seed to generate its vertices from, ensuring they remain the same + * across multiple frames. Not synced. */ + public final long seed; + + public ParticleLightning(World world, double x, double y, double z){ + super(world, x, y, z); // Does not have a texture! + seed = this.rand.nextLong(); + this.setRBGColorF(0.2f, 0.6f, 1); // Default blue colour + this.setMaxAge(3); + this.particleScale = 1; + } + + @Override + public int getFXLayer(){ + return 3; + } + + @Override + protected void draw(Tessellator tessellator, double length, float partialTicks){ + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + // The direction of the arc drawn by the tessellator is always along the z axis and is rotated to the + // correct orientation, that way there isn't a ton of trigonometry and the code is way neater. + + boolean freeEnd = this.target == null; + + int numberOfSegments = (int)Math.round(length/MAX_SEGMENT_LENGTH); // Number of segments + + for(int layer=0; layer<3; layer++){ + + double px=0, py=0, pz=0; + // Creates a random from the arc's seed field + the number of ticks it has existed/the update period. + // By using a seed, we can ensure the vertex positions and forks are identical a) for each layer, even + // though they are rendered sequentially, and b) across many frames (and ticks, if updateTime > 1). + Random random = new Random(this.seed + this.particleAge/UPDATE_PERIOD); + + // numberOfSegments-1 because the last segment is handled separately. + for(int i=0; i= this.particleMaxAge){ - this.setExpired(); - } - - // This is in radians per tick... - double omega = Math.signum(speed) * ((Math.PI * 2) / 20 - speed / (20 * radius)); - - // v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi. - this.angle += omega; - - this.motionY -= 0.04D * (double)this.particleGravity; - this.motionZ = radius * omega * Math.cos(angle); - this.motionX = radius * omega * Math.sin(angle); - this.move(motionX, motionY, motionZ); - - if(this.particleAge > this.particleMaxAge / 2){ - this.setAlphaF( - 1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); - } - - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleScorch.java b/src/main/java/electroblob/wizardry/client/particle/ParticleScorch.java new file mode 100644 index 00000000..3523cfa6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleScorch.java @@ -0,0 +1,70 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleScorch extends ParticleWizardry { + + private static final ResourceLocation[] TEXTURES = generateTextures("scorch", 8); + + public ParticleScorch(World world, double x, double y, double z){ + + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + + this.particleGravity = 0; + this.setMaxAge(100 + rand.nextInt(40)); + this.particleScale *= 2; + // Defaults to black (which looks like a 'normal' scorch mark) + this.setRBGColorF(0, 0, 0); + this.shaded = false; + } + + @Override + public void setRBGColorF(float r, float g, float b){ + super.setRBGColorF(r, g, b); + this.setFadeColour(0, 0, 0); // Scorch particles fade to black by default + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + // Colour fading (scorch particles do this slightly differently) + float ageFraction = Math.min((float)this.particleAge / ((float)this.particleMaxAge * 0.5f), 1); + // No longer uses setRBGColorF because that method now also sets the initial values + this.particleRed = this.initialRed + (this.fadeRed - this.initialRed) * ageFraction; + this.particleGreen = this.initialGreen + (this.fadeGreen - this.initialGreen) * ageFraction; + this.particleBlue = this.initialBlue + (this.fadeBlue - this.initialBlue) * ageFraction; + + // Fading + if(this.particleAge > this.particleMaxAge/2){ + this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge/2)) / (float)this.particleMaxAge); + } + + EnumFacing facing = EnumFacing.fromAngle(yaw); + if(pitch == 90) facing = EnumFacing.UP; + if(pitch == -90) facing = EnumFacing.DOWN; + + // Disappears if there is no block behind it (this is the same check used to spawn it) + if(!world.getBlockState(new BlockPos(posX, posY, posZ).offset(facing.getOpposite())).getMaterial().isSolid()){ + this.setExpired(); + } + } + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java index a18ff4d9..e5de49f9 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java @@ -1,39 +1,36 @@ package electroblob.wizardry.client.particle; -import electroblob.wizardry.Wizardry; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleSnow extends ParticleCustomTexture { +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleSnow extends ParticleWizardry { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/snow_particles.png"); + private static final ResourceLocation[] TEXTURES = generateTextures("snow", 4); public ParticleSnow(World world, double x, double y, double z){ - super(world, x, y, z); - this.setParticleTextureIndex(rand.nextInt(8)); + + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + this.setVelocity(0, -0.02, 0); this.particleScale *= 0.6f; this.particleGravity = 0; this.canCollide = true; - this.setLifetime(40 + rand.nextInt(10)); + this.setMaxAge(40 + rand.nextInt(10)); + // Produces a variety of light blues and whites + this.setRBGColorF(0.9f + 0.1f * world.rand.nextFloat(), 0.95f + 0.05f * world.rand.nextFloat(), 1); } - @Override - public ResourceLocation getTexture(){ - return TEXTURE; - } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 4; + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); + } } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java index a94103f1..5d879ad0 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java @@ -1,66 +1,55 @@ package electroblob.wizardry.client.particle; -import org.lwjgl.opengl.GL11; - -import electroblob.wizardry.Wizardry; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleSpark extends ParticleCustomTexture { +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleSpark extends ParticleWizardry { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/lightning_particles.png"); + // 8 different animation strips, 4 in each strip + private static final ResourceLocation[][] TEXTURES = generateTextures("lightning", 8, 4); public ParticleSpark(World world, double x, double y, double z){ - super(world, x, y, z); - // Multiplied by 4 because the index works slightly differently for spark particles. - this.setParticleTextureIndex(rand.nextInt(8) * 4); + + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + this.particleScale *= 1.4f; + this.setRBGColorF(1, 1, 1); this.shaded = false; this.canCollide = false; - this.setLifetime(3); // Lifetime defaults to 3 (and is very unlikely to be changed) + this.setMaxAge(3); // Lifetime defaults to 3 (and is very unlikely to be changed) } + + // May no longer be necessary, ParticleManager seems to enable blending now - @Override - public void onUpdate(){ - super.onUpdate(); - // Well this is handy! Looks like vanilla uses the texture index like this too. - this.nextTextureIndexX(); - } - - @Override - public ResourceLocation getTexture(){ - return TEXTURE; - } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 8; - } - - @Override - public void applyGLStateChanges(){ - GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - // TESTME: Are these two actually necessary? - GlStateManager.disableLighting(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); - } - - @Override - public void undoGLStateChanges(){ - GlStateManager.disableBlend(); - GlStateManager.enableLighting(); +// @Override +// public void applyGLStateChanges(){ +// GlStateManager.enableBlend(); +// GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); +// // TESTME: Are these two actually necessary? +// GlStateManager.disableLighting(); +// OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); +// } +// +// @Override +// public void undoGLStateChanges(){ +// GlStateManager.disableBlend(); +// GlStateManager.enableLighting(); +// } + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation[] array : TEXTURES){ + for(ResourceLocation texture : array){ + event.getMap().registerSprite(texture); + } + } } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java index f63bfcfb..4aa64a35 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java @@ -1,24 +1,23 @@ package electroblob.wizardry.client.particle; -import electroblob.wizardry.Wizardry; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleSparkle extends ParticleCustomTexture { +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleSparkle extends ParticleWizardry { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/sparkle_particles.png"); - - // Implementation of colour fading (perhaps these belong in ParticleWizardry?) - private float initialRed; - private float initialGreen; - private float initialBlue; + private static final ResourceLocation[] TEXTURES = generateTextures("sparkle", 11); public ParticleSparkle(World world, double x, double y, double z){ - super(world, x, y, z); + + super(world, x, y, z, TEXTURES); // This time the textures are all one long animation + this.setRBGColorF(1, 1, 1); this.particleMaxAge = 48 + this.rand.nextInt(12); this.particleScale *= 0.75f; @@ -27,30 +26,6 @@ public class ParticleSparkle extends ParticleCustomTexture { this.shaded = false; } - // Overridden to set the initial colour values - @Override - public void setRBGColorF(float r, float g, float b){ - super.setRBGColorF(r, g, b); - initialRed = r; - initialGreen = g; - initialBlue = b; - } - - @Override - public ResourceLocation getTexture(){ - return TEXTURE; - } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 4; - } - @Override public void onUpdate(){ @@ -58,24 +33,14 @@ public class ParticleSparkle extends ParticleCustomTexture { // Fading if(this.particleAge > this.particleMaxAge / 2){ - this.setAlphaF( - 1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + } + } + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); } - - // Colour fading - float ageFraction = (float)this.particleAge / (float)this.particleMaxAge; - // No longer uses setRBGColorF because that method now also sets the initial values - this.particleRed = this.initialRed + (this.fadeRed - this.initialRed)*ageFraction; - this.particleGreen = this.initialGreen + (this.fadeGreen - this.initialGreen)*ageFraction; - this.particleBlue = this.initialBlue + (this.fadeBlue - this.initialBlue)*ageFraction; - - this.setParticleTextureIndex((this.particleAge * 11)/this.particleMaxAge); } - - /* As a side note, I see a lot of magic mods with fancy-looking particle effects that really seem to 'glow'. It's - * actually not that hard - you simply create a reasonably high-res texture with translucency and then set the - * OpenGL blend function to something like SRC_ALPHA, SRC_ALPHA or ONE, ONE. The thing is... they're not very - * Minecraft-y. I still maintain that part of wizardry's appeal is that it stays true to the game's pixelated charm, - * rather than trying to make it something it's not. Still, the newer textures are much better than the defaults I - * used to use. */ } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java b/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java new file mode 100644 index 00000000..80ce3e59 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java @@ -0,0 +1,105 @@ +package electroblob.wizardry.client.particle; + +import javax.annotation.Nullable; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +/** Superclass for particles with a second target entity or target position. */ +public abstract class ParticleTargeted extends ParticleWizardry { + + protected double targetX; + protected double targetY; + protected double targetZ; + + /** The target this particle is linked to. The particle will stretch to touch this entity. */ + @Nullable + protected Entity target = null; + + public ParticleTargeted(World world, double x, double y, double z, ResourceLocation... textures){ + super(world, x, y, z, textures); + } + + @Override + public void setTargetPosition(double x, double y, double z){ + this.targetX = x; + this.targetY = y; + this.targetZ = z; + } + + @Override + public void setTargetEntity(Entity target){ + this.target = target; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, + float rotationXY, float rotationXZ){ + + if(this.target != null){ + this.targetX = this.target.posX; + this.targetY = this.target.getEntityBoundingBox().minY + target.height/2; + this.targetZ = this.target.posZ; + } + + if(Double.isNaN(targetX) || Double.isNaN(targetY) || Double.isNaN(targetZ)){ + Wizardry.logger.warn("Attempted to render a targeted particle, but neither its target entity nor target" + + "position was set!"); + return; + } + + // I'm pretty sure these were always static. + interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks; + interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks; + interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks; + + float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); + float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); + float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); + + GlStateManager.pushMatrix(); + GlStateManager.translate(x, y, z); + + double dx = this.targetX - this.posX; + double dy = this.targetY - this.posY; + double dz = this.targetZ - this.posZ; + + // The distance from origin to endpoint + double length = Math.sqrt(dx*dx+dy*dy+dz*dz); + + // Math.atan2 computes within -180 to +180, rather than -90 to +90. + float yaw = (float)(180d/Math.PI * Math.atan2(dx, dz)); + float pitch = (float)(180f/(float)Math.PI * Math.atan(-dy/Math.sqrt(dz*dz+dx*dx))); + + GL11.glRotatef(yaw, 0, 1, 0); + GL11.glRotatef(pitch, 1, 0, 0); + + Tessellator tessellator = Tessellator.getInstance(); + + this.draw(tessellator, length, partialTicks); + + GlStateManager.popMatrix(); + } + + /** Called from {@link ParticleTargeted#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)}, + * once the appropriate calculations and transformations have been applied, to actually render the particle. Subclasses + * override this instead of overriding {@code renderParticle} directly, and inside render the particle along + * the z-axis, starting at (0, 0, 0) - it will be translated and rotated automatically. + *

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

* The new system is as follows: *

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

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

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

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

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

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

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

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

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

Defaults:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

- * Affects: All particle types - * @param shaded True to enable shading for the particle, false for full brightness - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder shaded(boolean shaded){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.shaded = shaded; - return this; - } - - /** - * Sets the entity of the particle being built. This must be specified for entity-linked particles. - * @param entity The entity to set - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder entity(Entity entity){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.entity = entity; - return this; - } - - /** - * Spawns the particle that has been built and resets the particle builder. - * @param world The world in which to spawn the particle - * @throws IllegalStateException if the particle builder is not yet building. - */ - public void spawn(World world){ - - if(!building) throw new IllegalStateException("Not building yet!"); - - if(y < 0 && entity == null) Wizardry.logger.warn("Spawning particle below y = 0 - are you sure the position/entity" - + "has been set correctly?"); - - if(!world.isRemote){ - Wizardry.logger.warn("ParticleBuilder.spawn(...) called on the server side! ParticleBuilder has prevented a" - + "server crash, but calling it on the server will do nothing. Consider adding a world.isRemote check."); - // Must stop here because the line after this if statement would crash the server! - reset(); - return; - } - - electroblob.wizardry.client.particle.ParticleWizardry particle = Wizardry.proxy.createParticle(type, world, x, y, z); - - if(particle == null){ - reset(); - return; - } - - particle.multipleParticleScaleBy(scale); - if(!Double.isNaN(vx) && !Double.isNaN(vy) && !Double.isNaN(vz)) particle.setVelocity(vx, vy, vz); - if(r >= 0 && g >= 0 && b >= 0) particle.setRBGColorF(r, g, b); - if(fr >= 0 && fg >= 0 && fb >= 0){ - particle.setFadeColour(fr, fg, fb); - }else{ - particle.setFadeColour(r, g, b); // If fade colour was unspecified, it defaults to the main colour - } - if(lifetime >= 0) particle.setLifetime(lifetime); - particle.setGravity(gravity); - particle.setShaded(shaded); - - net.minecraft.client.Minecraft.getMinecraft().effectRenderer.addEffect(particle); - - reset(); - } - - /** Resets the state of the particle builder and resets all the builder variables to their default values. */ - private void reset(){ - building = false; - type = null; - x = 0; - y = 0; - z = 0; - // NaN indicates the velocity was not set (can't use -1 since it could very reasonably be -1) - // For all other values -1 indicates the value was not set - vx = Double.NaN; - vy = Double.NaN; - vz = Double.NaN; - r = -1; - g = -1; - b = -1; - fr = -1; - fg = -1; - fb = -1; - radius = 0; - lifetime = -1; - gravity = false; - shaded = false; - scale = 1; - entity = null; - } - // Methods for spawning specific effects (similar to the FX playing methods with the ids in RenderGlobal) /** Spawns spark and large smoke particles (8 of each) within a 1x1x1 volume centred on the given position. */ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_0.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_0.png new file mode 100644 index 0000000000000000000000000000000000000000..531b56b52021c306c017a547365e2f140b1d819b GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZfTxrdFS3UFfbhOba4!kxSZQ>=yfDO z#PvM?%%n-j{FD|qanEr3o-kE($MiP`Q+G6IvUI=HQDW)VR7(0dK|_gC`0tDvfA(mq zG&1^Eb|1Fw;8@kw!4SY_dujWU+d>S?3Q9F{?kTqlF7S$2Bkew~_ zggM9S<=syE?z=dDq596A<+V9ZfTxrdFS3UFfdemx;TbNTux35v-oHe~dDkMV!+Y1ym$-NQ>%a7bgoGW{-}Rd3%#mSM-gJ>$?*7mJzmDa$9ZfV|!ng1#o7#Pw#T^vIsE+;1_u-g3i z`}zOM^Y8yDcN;1d-~03XbN$2j{yg^Y>{AkIKKCs=b!_HD&d7s%*Uy)5nYTCXNAY*Y z!_mH}B4>H>|NZ?L|L5Dm|Hsz8{-3<{|CQ(EJ5(hlBqVl~=l?(Nz{kMA{7Qd=P0;JP Q3=9kmp00i_>zopr0Aw9fPyhe` literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_3.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b12745e939ce781a0af09df2ee45a53061b1dcf9 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZfV|!ng1#o7#Ms!T^vIsE+;1}u&Vg* z`}zNw{_p>_f1Ei%_5PpVpZ_1*Kc6Q*eossH#sd<|?e_n^|L-3s^Zm}xJZt{c%;5TV pXV<|4-yf+u?=4qQE|ukFxa}Z&@742Qeg*~x22WQ%mvv4FO#tG8Me+au literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_4.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_4.png new file mode 100644 index 0000000000000000000000000000000000000000..389abbd7b66592b6bdfc8712edbc5ffb7c927abc GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZfV|!ng1#o7#P-hx;TbNT+Z#c=3@+$ zXx(ou`AASv`J&GgEs?0`jZD8c@ciB&V5N0eKiI?OSh9zN`S);zSwB|=&zV!hzHfz= zE6e@~DxQUoE&-u?zRT>nTsdvko_S|Bi!d-NC@nElD~elwU3ahBnt#u&bv n@rch|t@+{oFc+@)J&Y9%K|#}hxkfWEFfe$!`njxgN@xNAz;kHb literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_5.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_5.png new file mode 100644 index 0000000000000000000000000000000000000000..e1bdc75dbac565c8c5d94de7eebc45df46b89b4f GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZfV|!ng1#o7#Jpax;TbNTwdDe$kh}e z!tlIXkVW!}Z4_JMY=8C_KCuf{ABo?R|8`TEqT(@g!NP?eX*aVcvv;If8}R(``d8-} zAev;P&A{gnAbP3WIl5Sicfo6h0^hXAp5|Cw0 zr{lWWjn3nrUarvSD)64Y;am9MCZ-#2%7xS{qq6@!Xa2I=rC=M2r5XbR1B0ilpUXO@ GgeCx)zFGhP literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_6.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_6.png new file mode 100644 index 0000000000000000000000000000000000000000..c597f4151ffab8cc5bb129c233b3b641eab0c5f8 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZfU-Xg!P9R7#KV}T^vIsE+;1}u(J62 z^KN~Lov_jKv-|D;m)qB#Xb5%uc$=Lk{@=gU2LV&kGpsj>=W%iODE|F={r}bH-wbPh je{F8;?rrYsV`F$IBXu?4vh+p<1_lOCS3j3^P69ZfU-Xg!P9R7#LhUT^vIsE+;1}kh1vt z^X`B1|Ns8ffB60UzvlP#|MlyBH#CBPU}WI^#nJ!g7i~7=h~IxYAocN?j;l+Kt$qF9 d_<}eCgQ>gJMQ?W&RR#tI22WQ%mvv4FO#l$FK5hU2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_particles.png deleted file mode 100644 index 96c99eade3c961c321562308511aee20aa2b9463..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 957 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)2UEx*7DJwkCaI zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifvPz0^Fa~=}*vG)Y?B(g=7!q;#?KJ-k z>2QH#^{YL$C8>5PORKx}{@XIaWO@wOOVxlLep``buYAofv#N_)R0;m3=WEbj-M3^UjXHY_jK|aM3BVpJ(qpnUlCsUzfSy>E4OU zSU#UGz2iFdP3PlJr~B=~q9)gG-sx6RH!n=yVbz-bU(PS#l;O@_?snPan40>NaQ^qF z@0tX!T620e|GRCyd;c9@zy6Ez(wfD2aWb5ja#YtAXG)^dLc9l%5txMexh~Pi_=ecPL%mqF4XnUU~||^*7HG&mi21vPgog|F{?!}TC^ zl;`sVUUn~FVfrE=+B50gi`IwB_CJ2ryt~LUJ}Dz(#YCH|Tc6sG+iy+{fBBMYTkYp- zic2{ZJB~kIvu@oa4;6{oa}rLkTlC{^%+G?9|4%-|Tk+TMO|fYYQ~i_w+u<+gyZArz zw&&G*-CA9==Gn(9&kZ+3KHQnS`Lf@J<=mYwugq9GE%J+V%*W3x?KMXinE&s|iq~(R zc6en%htt=5J=ODXG8yX{!c@Ol>s|foWUczfmf8AG4*TL3KC2fCn)&#c{xjT=e*4d> TIr}>U0|SGntDnm{r-UW|XzIi8 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_0.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_0.png new file mode 100644 index 0000000000000000000000000000000000000000..6c1dabf2c8c5534f2ed11fe1485825402b5fb788 GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=eE{Yo_Ugifq@~=)5S4F;&O6=g4hZ1 z6Gkhxu1e@IKB#ij^`>N8e8t&Dju!7*9-wC2;Jzd)vYy85}Sb4q9e0OjaIJOBUy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_1.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_1.png new file mode 100644 index 0000000000000000000000000000000000000000..990fba4b9a20f30668c5755e564f7cc141052754 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=eE{Yo_Ugifq}up)5S4F;&O7r0;wGp zA0O54;d;WIBB>X*=g0s5|Nm=n%}nU=_qR8U*;Uf{@X}Imjb(<1B(m0O@vPV1la`Q> ikWjJzm-5#;=NK4_x65pwloB`%WT>aBpUXO@geCy7SwCO^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_10.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_10.png new file mode 100644 index 0000000000000000000000000000000000000000..bdc4dc438bfa86c56d20384525c5bd9168fcfa13 GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=e9PyIqgd_0|SGrr;B5V#O34!1@@Rd z6(9H4H0m&efbgy-|NsC0AHS=F^IZBN_0B~MYAcs7Z@+yHEV`${@J<~MYlZ4YF9QPu b28Nh>dfHpyY-sCq-=2dMAygwO6J;Q2ZczyYlwVi7FGGu(30o;ZaFUoABi4#@&-uwrv)C i|Kio8fY2lF=R|H$wr1(P_=bUjfx*+&&t;ucLK6TG6+h?z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_12.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_12.png new file mode 100644 index 0000000000000000000000000000000000000000..abc966748735ed65bb9791492de577f78187a93d GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=e9O-n7{NU0|SGPr;B5V#O1ZU8+jWX zc$j6`yuK|?=6SW|6Ssw_Z1W5)p*=4SJe{k{9Pbol=Ipsji^0L=#wWGAvawYjlO`=W o6H@$o{qILIv)BG^tS@5Rb5qB9|JBn@3=9kmp00i_>zopr02Dz$K>z>% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_13.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_13.png new file mode 100644 index 0000000000000000000000000000000000000000..85124935f27096f74edcb5c5cc4186127f47e40d GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=e9O-n7{NU0|SGjr;B5V#O0-@4ssqa z;9)sv?O_{qag|42#%CdmO36L?ozgFtynDvM_~)bX@hI;}B7#gC-tx~VeDLJ&O0BXv dGq08ESL~39S;<*i$-uzC;OXk;vd$@?2>`qLJAnWI literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_14.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_14.png new file mode 100644 index 0000000000000000000000000000000000000000..50a9fc7007a62c3b58da8b13bd85d7ecf9a1e544 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=e9O-n7{NU0|SGTr;B5V#O1kt2YDS7 zd7Lg<@JpAz*d#E|#Pp;5zV}xcR2lSBmR+}9m3VuSLT2{gZ=p9CCrx0P+fq|jH)5S4F;&N}_M&3gP zBCO{*G*f4#G=Gt6QDQx15D>xDDqa|s=6GK>=Yh_ISAnceEiB=-wy}jDn78v8PyT+d z^@ic})@5sV%#nW+rue*PW~R;Et6N0Nv>EafPk$`9dR#Ec-OF=QO4_6^Lf;sQBO5OI q3jd0dN^-Zq^2PbA*{u2sroC=P_j>I0S28d#FnGH9xvX|#sK7s%M literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_3.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_3.png new file mode 100644 index 0000000000000000000000000000000000000000..d2a7c3c6244a2ba1b913337413cf11ae64e8d0c6 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=eE{Yo_Ugifq}uq)5S4F;&O6=0(;D! zijVeTo&W#;|L;CM#VNexU3>lPMC6w}y$n>C%ha^W#4VusZ)V6xD(99(E->>M>}GTFvFWHpVu_$=|=< iF+P6FtMhQc?>PTm~{d>9xQ7(8A5T-G@yGywp}K}53v literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_5.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_5.png new file mode 100644 index 0000000000000000000000000000000000000000..1aa1c4309daffad3525edf44c481244325ac1ff7 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=e9OjH}S|<1_p*APZ!4!iOX|)cXPHl zh`9DA=}Aj;bxNGeG5(gwtyE?-(d==x>I|;mD<4Sq8tCLa=;ga3e`jJx#1k7Q^X(?i zy)$R7ihHPZXrt_&Y5qxS+zhL_iuoGc?X3Gp;|rdsnbmpw~|+shosa%dU#lP0eN1T)H9d$(-ySL!M&(W3MyH?LxfO Wq)jKxxy``9z~JfX=d#Wzp$P!TUr{~) literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_7.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_7.png new file mode 100644 index 0000000000000000000000000000000000000000..e0a4a7962ed6d8055cdbec20dda86f05ce4e7ed8 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=e9OjH}S|<1_p*wPZ!4!iOb0e3alr@ zPZ*sLKe4F8(8$2RAZAa+$Nl$fVqOX=K%sJXE{(pbP$4B)N0okF60z6OC z6F{Kx<%P?alXsN76k=v(W&Imv%2X=zGI zbvNdjpUG9@X}tdNu+noM&7*s6zspPH*s_vw14}??*4iI+uWny!4-NO!EL}JyNw4hT z7YSB_P}fk#T^j!)W=l=~do`xluuI$iH`DQ{UVGMTSf#?iz`)??>gTe~DWM4fi`!bn literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_9.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_9.png new file mode 100644 index 0000000000000000000000000000000000000000..29c3868df82e4a2dcbcd9235e337ca9ca7694a57 GIT binary patch literal 243 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=e9PyIqgd_0|P^Yr;B5V#O2=JoxDtj zA};eUdaXO4sN~op)*8U&bVMNdWOM4gVTsnU_n&Ghp(}d!8v#u3<-oPDPBwxktgyT1FO1rbDi!z>c7DCqo24B zbKolHnjMR!xMn2h=U=x_Si>Q4@=|4bT6$U8z1ghix?A=#oK4&^Eg~v=+WRh+^`==T z(jpyS7XK2pWiT+#Uc2*Z)=DQPp+AQ|`|})#>|C3kyL4+>S{a*?Qpde?<+9mxtN!ih zVp#uv|H-K?EjiPs%7`!L76`11`Ygh*!TfG0yG4qUlg#mZ54^o4zA?4zJ+LyLPdTUT zRqLBv!P*<#Ug3+jK2!0$@%laYA8X&g@zW;RE~Ql9_BJ(rfpe=GOxH}d}T;gqtOY|f^OQO1G~ zKkjZkl_qJ|XFt6}>2BWk2eVa9UfLU;XA?fZ!>{ASb?3CJVKZg_cifol{UB}H#jVdi zl^%STzI5G^%qWS)kH58~+RPSMW11zgU47@=YqKt!l**mRackU>KPB9^B1lPcJ+3D z|7-TL|Ie{^+_@Z?c{x=-`)^>2bvg4F_rOA_T~={yZ3#E?{N}Ic?~2NnyEFUqQa9dT z8rtd#7G;TdWVY%#S$a>+yEkKldA0blT$$ZXx}V?oE9vuxs8%lwRXTL?v}0yi{rvZ= zc?RjbLOMFU@*BV36lY+by6l1dtu=Np`;~IaU)`|lf8V(N+`BzjmBQxqGB7YOc)I$z JtaD0e0s!9`VEF(5 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_0.png new file mode 100644 index 0000000000000000000000000000000000000000..e8961570f2e981b36b7fd73e0c8942199a073557 GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgKGq`#ks=7#L(TLn2C?^K)}k^GX;% zz_}y(O3Z(G%s9 zCfc48N`(FdoPJWGsIh8N$1UN_`GU1oyX-V(#YTvjZVGD9ZgKGq`#ks=7#L(TLn2C?^K)}k^GX;% zz_}OC9n!DV;&3>7=S@wiN<*dugzwL|Xu~PFob1LQjtGZb^dE2)1 y-sJqwXY%W~_rE9ZgB|(#?W~T3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*Ru*1{EF~s8Z*2#`S%z^^0`==Ne^69z6cN7<_ zJg3CrbY_WGSg^_e%F7H49Gv_6Cmc9aZ>OTN{kB${b5B#p&U0IQbEb$JR!8`Tdv@$D zRFk;4a!I{Vk7>iz_g5yp$$Io)$(ipirLl*yI$HNUTNM3T!{bN{huE>-Q)cGqO}Dmu zdXK>&N95}Jo$oeomEN4b*oNV{?3Z1aHokN!@_rNe3m>%pU1jaAkTTa`njxgN@xNA43mDL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b78a86ffc0ea7f82be90dde28ee6e692ffa060df GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgB|(#?W~T3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*Ru+`JWF~s6@Z}36EBMKaM?!@>;wTqRg@J_Vy z3BIHJ%0Nry%m;zQyRo7S40;jAR$Ga8oVc^*weHz}=>l25PuqPyV(sbT(tIP(@z|HP z{n~Th?)frFrFHN19SoLoddz2CPG>OcnHWpF_$pldruuf}+pT3YZmBP4SB~Flf8o8` zx{&$_$;-7hdxT7`Ci7k>Irqym=m(?1^GDhY;vQVz6Z*6rJ~h5so)dTf^9Cjc@l8Ho f_UE#GwE4k&E$>syME6A=AfI`<`njxgN@xNAj{kX; literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_0.png new file mode 100644 index 0000000000000000000000000000000000000000..60d2e3d2d06ed7d67d4d84d3b295a6489f156570 GIT binary patch literal 315 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgB|(#?W~T3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*RFyGU~F~s8Z(#aPETMRf{%+14t*C?B{n6;E1 zS+;}Uuvu>2lPBtllVau0FjO2AtxaT&QB+EtEWX3Z>l00P*z~^yVYRxlAiNGsQa$AFp7!-70TdM!HkN@`8ulls7$$_Z{rmnG(y>Of{{%4uG z>Z~alm%djk*`|9ZbY5D2cfzFGHVgr)cWi$s^k-v0#imR0s)-BV`doTx4Dy4gtDnm{ Hr-UW|8GLJg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_1.png new file mode 100644 index 0000000000000000000000000000000000000000..0d98efd635c912585b96c3487f16a281e94b3ebb GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgB|(#?W~T3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*RaNN_yF~s6@Z}3IlRs|lL9^->D1{0>X7Vt%^ zdhh&1bd8sA5ZBA6?=%ibXwJ_zns!aasM?x$lfu*IZJBDC%`naKMdjT4&ByzZjui2tEa1<%Q~loCIBxXekA|^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_2.png new file mode 100644 index 0000000000000000000000000000000000000000..19d23ff3afacd87655c4d4c9a723026062dc0fc7 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgI(Qwp0!V1_s&8kcblJ{M_8syb=Zw za4t$sEJ;mKD9TWoKYuIO6Hz7-DgH>g3ykM-(_*^)*jjNt6oOrm)s| zc2a!-d(7t~wZ(}n=UG|8!lEvTp3h-<5$ED^{kDpR zDjK|9?}gT>>i8rvT($fC$@Z+v!uw07oMmxNN?2v<%_Dh0`R#1ZvQTr+8Cm}s9)x;( z&OOP}n05YfeDmbhXE*+TJ@1zJm(MRcKJI*|WZrrFoUq_(9XS>+4%_;BotYbM2t_FE vs*;Xsw&AEV=i~Hl`n>Xp^=JJrUv7wpu6q9R7~7;PAdh;w`njxgN@xNAuE2ku literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_3.png new file mode 100644 index 0000000000000000000000000000000000000000..ab8dbf037ccec30b0c42c9792db459cef33ae0eb GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgI(Qwp0!V1_s&8kcblJ{M_8syb=Zw za4t$sEJ;mKD9TWoKYu*yriu7-DgHYVd8r!wNjYG3kqnFSN>tDHTsx zdZnK!T`n)`|B)X_o)K&}T=kmvJDERGQps$3VkBc*BzUYKM>=Y)=~Jd-8ya}l%&lEh zJFBSioUg#w#|$eNZ(YCdqs~~sa6p2OA*guAXQsIGYr9<61tp)zXP)&$(qS^U)}6|) za}0H4tZ(wCPEY4q)F{=#c27?*dyD7!>k65-o-gzDDLu64)6=NE+jbbdbH4OunbKj- on>!8nwCkT;mRhb~l=@Tgp5$VVB@FVdQ&MBb@0PiPy8~^|S literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_0.png new file mode 100644 index 0000000000000000000000000000000000000000..4b189159fe0ba8bea994cb30d62646c764928406 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgI(Qwp0!V1_s&8kcblJ{M_8syb=Zw za4t$sEJ;mKD9TWoKYunCR)^7-DgHX|N+-g94BCG4qGkADj=gKal;g zvMO?lf<}U{kkhqNZE1t933V*(ER*JXo_fGmnK`Mqt&4p_{(7s^CXrf^)wMe&JyQzR z{}lH$&U(J+g$#xrq239ZgI(Qwp0!V1_s&8kcblJ{M_8syb=Zw za4t$sEJ;mKD9TWoKYuSm^2E7-DgHY0yEz!wNi;i)V5^YiMl}Z?a6# z{C+X!wX#L4n?7IkG#!SpiLaZV#V9IGcK(&tyhk!++5?BBj2G+Itu&bzXy@WG;dSDj z&2jnjB{>*`VisKzVsKkG;eo?poh{9u*EGgNrYBlWcyMWF`75tAn-_Nfy8cS~;(fO5 zGpD|gy!cu53}4CWb%%dHWLbQm?Yw14!iw`L8`cXwtH1YZLj6j8@!#|QG-k{R0r|qy L)z4*}Q$iB}mMC9ZgHt|{3e?i7#L(TLn2C?^K)}k^GX;% zz_}=K> z@@K4^iVK9Rqc)XA&t{Bwl(~NLNT7?0`4V;iBez4|9ZgHt|{3e?i7#L(TLn2C?^K)}k^GX;% zz_}bP0l+XkKFF9ZgHt|{3e?i7#L(TLn2C?^K)}k^GX;% zz_}>0pL(PJtkyJi@8%Pq^2L^@#?^NJnsg)l!LpFE zi$Y6`XK-8!pPSt5y_EBYx*=2c6G6H9gB2V{WI8%jPAC}{tPCk*I1u^V+4#VlsDm%o iv`p*OToCWT@PLI!a?{6mGy1zgZuNBab6Mw<&;$VK>|ufc literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_1.png new file mode 100644 index 0000000000000000000000000000000000000000..bd62e1cad475123ac8513ecedbd5d6d68b5fcb26 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgHt|{3e?i7#L(TLn2C?^K)}k^GX;% zz_}Ur zUD>O<%sIw!AFqy*_^iw4=610a*ff83EQ+tl?aN5jWR!ZvknO8|n<=C94$G-aC*74# z=Xlk<6r38ZF|qb@-aQSCH+Dupf5hEpY{<%7@g%2V=HBpv@9W>(s$lsdF2L}EftPL1 U?3)>#+d&@kboFyt=akR{08IOEKL7v# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_2.png new file mode 100644 index 0000000000000000000000000000000000000000..e5c306fa53cf661786fa75dfcae71bf0045396cf GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgJ_I94smf3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*Ru-MbZF~s8Z(#a1w8x%xZ-gg>bmDw7wYr?sO z-m&!|Z(0+|6j~nKt@UT#;`qLc6IjIB?)t2{xXbhUv+bM=cRVY%*B@q|X9x0! Mr>mdKI;Vst01kL_O#lD@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_3.png new file mode 100644 index 0000000000000000000000000000000000000000..ee15f8724ab27649aef79244ce1523d6cddc5b4c GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgJ_I94smf3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*RFv-)!F~s8Z+R1l$8x(k2{M!y$mMEqu&S9Ru zia+TfS4YNVHlY{St?L*h&q9ZgJ_I94smf3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*RQ19vD7-Dhy?WBW(41zqa`RX5Z&5ZeXhV?f)KT=ZC zYcUa?FpZDFKArcD_Ey^tNL!mw9ZgJ_I94smf3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R(CF#n7-Dhy?WEnj4F&?v@hWLemI;a{oD%ys zOwl~CkU{X#<$wgu-qhc9jq=YqHtyHkGQDt82}fj!z@xB?4GVfLwI@{Qb2=S)8yy9ZgCm)oQdrW3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R(C6vm7-DhyZO}npCPSWLm9(tq8SIPBIwkgP zm{KXD+h{FYpf4BE6%x7esS4}A8|{_V*Nb+U+s&A@e1>YNA$!&}-^;T^4cJdc8pIz_ zN#9&4eUxE_d88`C6xF#;i{3UTcz%|xys~DKp*h1A+ly7~f~WaHoK_`%OEEdKe9ZgCm)oQdrW3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R(Cz8s7-DhyZP0DrBMLmlOJ;LEYiQItZCbivg2sg8o1$koGAuGMt`{gh z*KW-oxQ$UD^_JBJ5e9~k+eZR(j|No)=bnDiP*&vcByBkFQ3bnl6?@5pSFcQM>|K7I nDcv`(ROiFL`#bjjnI6HYvw9ZgCm)oQdrW3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*RFu~KsF~s8Z(jZ5^!wNjbtM+#8ZMMzmvDMh4 zTyx6WXX-9Kj@(*L5y9iz7~BH9EqJ%OOp-g<)V;&!!Kv>#ccf0wG_+ZI<$57^7Q=)k zSIiq~&a9I1XnNxHWo_2abhD^?*Yf_SJM#8024(#}@R(0iv}fVs6zh^JZ>H+JZjJO< sDf~WqU%TSDma1>s{f9s2Z22W?7q+{NGc51WCXk~&UHx3vIVCg!05$4qH~;_u literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_1.png new file mode 100644 index 0000000000000000000000000000000000000000..6607b21f69b726bba24357ff416213d8066756dc GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgCm)oQdrW3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*RFwfJ)F~s8Z+MwHlM-(_>j8=NSzR-51Z3~~~ zs~!C|&%P-6>1~haVLq+Lka5EFLHZLZ7nd{@Zn;N>2SfgyIaYM@jn9%pANRG^=j@$W zGgaDTx&HaZI}UfnD4t`{`Xj~n!R%s~xMui)+gG$N=ugmgc@l8z%KG0e{<~aS-Tw=& zCMHB-&=Ncv3==b8a2;6wVpy6Ouj~fxO`9>gTe~ HDWM4fu3m63 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_2.png new file mode 100644 index 0000000000000000000000000000000000000000..706d10a143326c72e17759947dbc0a54ca2a0bf9 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgJUw?1h313=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R(C6vm7-DgHY4B~{!wNhmJg(0dFtesB8n;Kj z`sBQ*qiNyEzYRKXsu^6wTwYqba2_b>SU!CN+Y<9n!VFiwp4Z7ctKy}yE1J3H_MKY} zJhx}fJyo-@KZ|>w|IfdF`&loxNZfdO$hql#dihR+qzC&ZRTnN=7W&A)?W%Xt&JTZT r&Tp4|8f0OLJGsk{3##%6Ru3dY;d&z^JASZje`njxgN@xNAi~Vii literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_3.png new file mode 100644 index 0000000000000000000000000000000000000000..4a67952bd9672409682aa22f668f9bf5973e5426 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgJUw?1h313=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R(C6vm7-DgHY0yQ%Rs|kzzSiOoY(g1@UiXk(EYg~VgE5Z z9fdxHILDaZ`(I`7-hUl-wsiSKiL7&*r={?JG+#fu&CGM9)iStN0O`dpBcJzf1=);T3K0RXi)VNd`7 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_0.png new file mode 100644 index 0000000000000000000000000000000000000000..07ac3f770353bbd5c0d58d14ad64e1157663b4e5 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgJUw?1h313=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*R(C+Et7-DgH>7={74GKIh{*Qc&+I3uFIG!I^ zdX9a`Kjy366%9{*eT{0E4`T i#c-4_`^&TV?}6IB)g3)=SpKwu-0JD-=d#Wzp$P!O%w>cC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_1.png new file mode 100644 index 0000000000000000000000000000000000000000..c7a7d8746bc7b78c057a48f785effaf6655462da GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgJUw?1h313=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*RFxS(?F~s8Z+)06aEebp?@@eOnJioxLSgl~g z9=ED)gM^9bEut?#2cHu*Oh1CZc0Jhkm%C*i zbFAk4sU2O-b2hL1QhcM1S+Fvsa?NaZP3xMKc`|dZUtylGYzgb98y~KLeBkNo=d#Wz Gp$PzBt8X&^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_2.png new file mode 100644 index 0000000000000000000000000000000000000000..3dddd174e6b1d1a67753ca6dc34391595e7a0122 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgIJjNgq}-FfhnwhD4M&=jZ08=9Msj zfOAo5Vo7R>LV0FMhJw4NZ$OG(Dmw!M!yHc+#}JFtODCP=J)*$lYOi7HC>wBrfp?~r zPvGO70+W~%PwrW)`rp;epvl7KjA6S)M@NH2!;dJXwvL?cCB>PwKjRjwz0iFfDqF~= zC4S(x?(?uj>un)(^b literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_3.png new file mode 100644 index 0000000000000000000000000000000000000000..e84fbc4d371b451cfa8bf9be839e6c370476922c GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgIJjNgq}-FfhnwhD4M&=jZ08=9Msj zfOAo5Vo7R>LV0FMhJw4NZ$OG(Dmw!M!xT>!#}JFtOM`Cn9#-J7S#)N~xrusDHVB+y zbbk7)u_NQvk-X|j^*Z;x8SW@fegEyb@}##r&R4z{eYtpIv-^_f*G&_&Kh((V=Jd-* zxm~&9!Rs|8@~tKlD-}2!eu#-@O!WO8(xNia>ra8vyj&-(L!~#J)=4+ST667mGd?)M xN$*nUyaiu-esH&)etPfk#601sclWsV2gR#S=#wmB%bo{vxTmY1%Q~loCIGnZa1Q_g literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_0.png new file mode 100644 index 0000000000000000000000000000000000000000..7bc98d4e0bfc28f39013bd482952ab8e9b98fcda GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgIJjNgq}-FfhnwhD4M&=jZ08=9Msj zfOAo5Vo7R>LV0FMhJw4NZ$OG(Dmw!M!(2}n#}JFtdnaAwJ*>dv(!av^pv(q=M8$Hx za?S6`en}jenMzmVBR=#!Hu&&eX&9ZgIJjNgq}-FfhnwhD4M&=jZ08=9Msj zfOAo5Vo7R>LV0FMhJw4NZ$OG(Dmw!M!*Wj-#}JFtdnX;_J*>dv%6rPkfL$kLkH8s5 z@15*x*g94&3ez-~*?assd&BU`wyceVMV--7L53HXJTEL3 zGB$qFW#oQyGGD)Q9*^_i$ORPz$syykz#iysM znIW1}|Cpn=fRka(wLc$U{^j6MQVPEH^q9ZgIJjNgq}-FfhnwhD4M&=jZ08=9Msj zfOAo5Vo7R>LV0FMhJw4NZ$OG(Dmw!M!x~Q)#}JFtdnX?hJfgtiYHz*rbP0l+XkK7esl+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_3.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e8abb6fb78b65e2ed76597bf4217785e6aaed7 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZgKg2sRwKs7#L(TLn2C?^K)}k^GX;% zz_}J=a*G zw5OOMe^YY#{co`b*y7{k~5n?_blFW$_=G6f0(S TrDgmn1$oEQ)z4*}Q$iB}ThDYf literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_particles.png deleted file mode 100644 index 94dc49c5599146bf0eafd875870a572fb499be3f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2602 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 S44ofAY2DM+&t;ucLK6Um(}o=Y literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_2.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_2.png new file mode 100644 index 0000000000000000000000000000000000000000..8a908c4359e903e7884011f9315c56f39aed63ff GIT binary patch literal 874 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^MeG;2pW})eH;_ zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y+NfF+q9eyI#5s3=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*Rbk5VoF~s6@?&R~{%IOlv?eo*_te9MGP@<+N znv}8m#ICZpdESb_nn6w*-9J9My1G5CdPRGK`2VJVoNrSXPLZ4A?V9EILQ!)|_nIX> z?Tb2Z8BG3}Sf2dlt*Yjxua@@rpa1+&Gk^Vqc|l%h8QwFoeGuBgXrg%J=j^?Ycps_+ zuw^v}9{*S!bn1Nr_XFn#>yO6c@lcPY!_3PK=x8BZ8E-Tx%VcWKEOh33Qq<66R zl`g%aGlBc?g|gW1-D#U6E$r;fY|hW_Sfp_|$Lwv5UA?sH#BE!*US-ufz!DJXRlA;f zThObMM~}L0y!`UXuDkD+y#Fn{?|t^)x_AZ_M+KvqJiTs@Kc78&_S2_NpQbx?%s*zn zVY151zC{|dm%VJ(=-Ohyb2Nfyf=cI%`Sa`d?%w_T&bGI~3sy~G`moh)vEkgaX`xGl zJhi5Jg=mNvt$QtY$l%PKtrot)e_y7`r&mYIgGdeeiKW!{ULR;s*IMxxDd#;jRhjq~g_t)HjTSt9e?b!Et__3PI8 zy?^t@MkaX1vX#@OO^eIT$(iF4Xp$Kjw&3+H{y(~I^&c1?^mrV4`}Xa6>$!emmrbs| z{wgVdX%{~>^IjBksq-fA7k$P{JXtj$Gyueh~iPX~x6LV0FMhJw4NZ$OG(Dmw!M(+p1+#}JFtrIYV^PfnCLR)5~CxNghyyE3aY zzlhCXi_TcjTsosxK&8asgM-z}1I>KDv^RbJC45NO(8|lT$>W2A*4c-*I>lD1-t3q) z`~0%Zn>(y4d4+fT&zt;uSH-*8_m^5Exg24NYFvN7Yy<0@0I#*O*H$U_EN@`A!1$v< z+<_y5@siid?d-PmnA4;)3XaMin{ngHl`FamQ%GVYf&C7f(g9C~{*D&cCBi>AdrZyD>gLRt;i03W^CHJAdal>fb#LCh zsR#=Td)L$7fB*c`qV&eg2UrC+PVF$+nR&8k=bb3M>4$&T*j>4OyZWxgVumf(l5UqB zEu3?A-@bk4KUVxH))A9te`fRU9j`-4X6DO7Cr+GL8lqL2d!HwvC-7*}#b6z=y{Au~ zKIpY{QG?Kicg(LEyDwk99G;$@etya2%vurYxb@SwZQHgs#pvhBZEr&p#6SFQc=uU7eIzqQ&n?Pq-7=zrkRuU}Qc zN)t7XByBw2>5^1jQ1D@?;j*pUwtZ{#POg(zna_P`Sw{%-`i5!Go;{oDppeku6dry( z%0NOVW9@zBs|O?kmQOh)AG)kc;icHC-s~N(?lp00i_>zopr0I*$s#{d8T literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_4.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_4.png new file mode 100644 index 0000000000000000000000000000000000000000..65765f7b4f938d34d37ddbdac11e7c79a896c293 GIT binary patch literal 848 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^MeG;2pW})eH;_ zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y+NfF&;*?ebOMKWHUn|N}Tg^b5rw57(l?e zC^fMpHASI3vm`^o-P1Q9MK6_|fq`j@r;B5V#p%+?_8HRY636Q2zw_z4<657@I#3s7INATR;Z;Y`=w*Ia_#G^OwqIRllEdG=WR4l$5gtRmpQlP8LsUL@(2mu znIL+6j$Ww!%arSz7VXwQ%_(DEd3^f!?;q^;oY$`K*Ic@e*{VP@YiXl>tHA%5IilhR zqz_mWNWWmLXAawcfBv=7znTRsG8~Fg%x?DV=?(qXbI-}1-W0Wa_wM;migt?s{{4IV zuDkD+2Ccl(_u#qL%GXXE;qN&Z7$hslm=UsbQ(lc}B%;|lPa~Sr&nAp2~Tdw)_ zYuD=5glL85-nLtP{dLstyJ8GMUK_V;37Ii(-n(<>&tI20zLN2JgA0!b>iC}C z-cp9GJ9o~MIlyrI_;DvM$;m-kXVWgPxte8}AhJWK``lF-Ik~#GzxO@-z3<*?Lg+ZtuqP+_xf+xG4Gxj8vCd=GZLyMBP> z!)m>j49%r$a?E~f%s%^X;gnt3v!0!GS~y{HP?oc^^TO1~QzmC0Jb3UR`gq|!X-UbQ z-~EJI1^gHN5pNafUpj^V*|TSTufG18nzXSZVr`i5OrK{@o;-PC6cFNN+A7f7?PLt=2XmqQ xoPXH-WMzw7#L(TLn2C?^K)}k^GX;% zz_}5!+3V~EA+*2(AnlS4(0+b^$8*!s3PYyOwc z#!GfQGt@d*nplLHHzzOZw07#zKKbU4cv|D^n?K|?%yF50bH;{QM-mi_mnbPpYP!ZP zH*wyw)p#HKcHCv@Wz{~3@8JKz(-FG*Dt}*J-@5h>1`}3?XkBmQR9LmO zZu?Jvc1NvEGo5|*$fHM#KGoXSR#g008T4xF#EBF0qt;&2J-un$)@%MQ zOEOzJjl5P$pG^5wD8O>@?%mkc7c-93+>hUo`}^gwV{Kda?D>;WTKe_bix)5Qr=^A- z$~RN3sgpt*3?}x5)wN!M7YjBd;VO$uebMa zPUJQI1G^ZvG`2h3+4eR~Y2t~iufMLV+AC*kX(`BX{xgfhT)+K6dee9v5VY!a>0QR9S6Du56YP81TVYd|H|yEX%vt(X)z!W8=FRh1-sPgS(D(A5 zIdkUN%$+^Ec=__>@4HXLK5%EY5Sv)t>hv)5c;TJLk019J@0`Q<;CCI%0TW+a6O)p{ zva+;_dD8_ZmM&nG5c>5%cESD-t-CfB78}yj(oSh>Ykz+H_;I~O-{&O}I(+FyGoN#F zbH97@=1sZR%6}*`x~@7BtFdt>(DQU2})ThB48A8@~#RjN7vd_6zQfmiqL-J2VsQ#SGZ^Y_eLJCv2q zuAZjJwuhgm?WCT|lXcgA6(3-VNr-j%^IvA>HLGP?-(8R5Z+m|5!p8rXye$`*R@~3| Rxe}DjJzf1=);T3K0RVxhlLr6* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_6.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_6.png new file mode 100644 index 0000000000000000000000000000000000000000..454b064c5764e47225c752d8cc3aa8859587ce13 GIT binary patch literal 865 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^MeG;2pW})eH;_ zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y+NfF@6yTzcp113=FcFArU3c`MJ5Nc_j=W z;9QiNSdyBeP@Y+mq2TW68<3)x%Fe*Rbkx(uF~s6@>10Qb+37OJ>ets@+EMp$?dth+ zb(R_IH=WpdYnt2hgQ8JxoILH)%!k7!+^Z_FJ}X!C;^twqR}0zsTbr65Byw2qIC<(y z){kE^{vM*4(;sidM&o1syI^gX)>xl|GpYtY9_0!f4MNCqA*iHlZXp_wC)QSFd`n zdp(cs9OLspCI6XSR37;6-@R{N-QmJH{4Ptf%gfDo?b(x)pOZ7^TGan{7UxXwmq)tX z$`YQ#(#JS4LZ>V}D@$wN=FOi&wWhv`ij2H?GG$X~S=qPXhQELRW*=C8ppfD4{F;R^ zdi>ID4;kA3{{8ExG_hj;?%lsLs;hrTWM^kD-MI1NSqFuJvXqo3(GQF^Xec$_Vz+r* zdCz?Egwp&2u*x_^~Y6~^oFDGdL?e&{=Ugz1(m*-?_{@ys* zYvt|G`Kx~WT&=VJbo(d!hX(cof)_adESRFTMy+Lz1?3_YAfgS SLtq{#rF**ixvX87WPV~EA+(#ih*$*dwr>$krTU0#1LyZh+2 zOvhD0$}3mSxLML+6)dh+rYz5p)S-R&QvQQ`bK?(03LI?_^^uC5F+s}9)8h}brm>*( z%0{E7d+ly%z9?D8z5JNTx!8Mmir<~w`<&yvM(A8-qlT^%+gJUX)M0Y``5D6isU2)Z z2d+GQ`ZV{j!Mf0^%wDUaSZDoLH9Br~kBR93!-BBYdsAHk}If8F)hmp@k27)bD(aZ&nsqHs>e#)vfx z+e5yx3l_R_y{nk_eP3#1d`@0o-PVm84a4=O%U{XbdZNIh=Sb4VM60=c&x&?V&f6Z{ z=c069db3XLbW~h`O5Ejr;fa-_0;_TKD=C2hWAqUyl^Z#IFqbm7JORviN~S z26L@^0rLlD@lKaVTQ0w}`Ch-zfTwx#WZ~7f-`-kiYLt%OO_K@}0({pau z$@IFN^-y^vy^^E-aMtZ_lNT>mUVZ<4blv{{dlL+1gkC*+QM}H7Y0&bOA+K70{;d3H zqtEwX*E;?K+j7sQZLVLtZr!`k)mP2M#Kqq;#xwuV3AkF`pd_#^L`yy=Ki_|A)Y^u} z7Hx?VI{NzdH*VhaJbUh3S$J63JytumI>CwgZd`l~!3$*ikLz={9;(!u%EivqcsxBl zz0ql5!TtaZlUr}Ubw7Xpe7>)rU!9TBLQVxG{?Mxoa!-qP&R={nLrUO!sq(z%cW2C; zxs#p6c;=ZcnX|q(PIrC6;Bf5F6ozLF=8ave>aM*0+B7ZoF6**}_l?h8mzW+pVZ3OL o*u-h8?p5CUCHkVnBfsWbe!&_WCZ;JSn?R}G)78&qol`;+0BOdT=>Px# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_0.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_0.png new file mode 100644 index 0000000000000000000000000000000000000000..53ed7b630ce95cdff80e074c99115bc77c646b83 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0y~yU|<1Z4mJh`hLs=Z)iE$IuqAoByD}*Zs1B{WjH#E|D)Pnuj>p93=E#GelF{r5}E*$2q=00 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_1.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_1.png new file mode 100644 index 0000000000000000000000000000000000000000..6d792d6d11ca3f2695fac0ac7f7baa3356611d33 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0y~yU|<1Z4mJh`hLs=Z)iE$IuqAoByD mY;0_75@#DGH!F4UFqC~4ek-#t^)Lei1B0ilpUXO@geCxB;U_Nu literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_2.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_2.png new file mode 100644 index 0000000000000000000000000000000000000000..6e8d60a12d4b46464df380662a03d95ff80eec29 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yU|<1Z4mJh`hLs=Z)iE$IuqAoByD@~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_3.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_3.png new file mode 100644 index 0000000000000000000000000000000000000000..3f6a9c9103abc094a04fe70802c66ac51a0f2892 GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0y~yU|<1Z4mJh`hLs=Z)iE$IuqAoByDT+!%>MJ1_w_U#}JFtZ~F|n z7z{X=KmXVNx#M-vLC4#U?))tR9z80Y4&v8mPXEL$puru@?Y7~=!O~~8heHoA?BBFu dYeJ-&#nZ^*-j6=~VGIlm44$rjF6*2UngE?=I0FCx diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_0.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_0.png new file mode 100644 index 0000000000000000000000000000000000000000..be4ee4f11107d010071c09dfe0014fe6c19ca9fa GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>ljI`2LO03X05+b7YiS_iQ_?P})iUwNWK%_^Z10HCadw|zi(NM7f(4bP0 Hl+XkK;qH7$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_1.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_1.png new file mode 100644 index 0000000000000000000000000000000000000000..5264ba887f361713f4fa199c8fd97a7014e2f32f GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>llx@8 g|NraT961;w&M^OV-v6$Vfq{X+)78&qol`;+0Oh+RNdN!< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_2.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_2.png new file mode 100644 index 0000000000000000000000000000000000000000..8db620f5c545f695dbb711fd1f0d591160564427 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lJ<=R3>8dCJvQooglr^e4!@YWns)>I-YBx~=DrjB}o8(^j35c)V>V!=1fV?`KHv zEx)t(hp!t;_S#jeqOwC>44&7Rr=-m-K6Qq{!1$cy)S0XWD_3o~mhztWz`fbmX02FN oWB4x4Tutep*@?^D?t2-YW&6H9nR5Cs0|Nttr>mdKI;Vst0D+%b$N&HU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_3.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_3.png new file mode 100644 index 0000000000000000000000000000000000000000..dcad491026950949fcfa231909b87b177548aa79 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lS`MteH0%5(wzHmm;bW}i;4*@E*?VhJPO8)1?8pN8Q<(>+>v(p?$&FE z?wYzWC^>~L)el|TaiQAUcxFJTrg8k?)HH^Y?Q@G~$fuo)?~czqawB|BSiQ3z0|Ntt Mr>mdKI;Vst0IGOJKmY&$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_4.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_4.png new file mode 100644 index 0000000000000000000000000000000000000000..9f2104b40d4016109dfc5474dac51b71ab54ced9 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lvbeS z#P$5?BZp=>ZP^qcG{f$U-kLj;qzlB;7;mjOnvk0QJx*2Zuz0efnAX3ACm(FR*kG`H z_nqR0hx8{!xUvOY-+F7?(Ys%#vnwxcQMnU4>B&2I<@IZLESm`@10LA*{gs5vEJP!|4Tmln*qBRC{!3cUHx3vIVCg!02dT>zyJUM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_5.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_5.png new file mode 100644 index 0000000000000000000000000000000000000000..9783e6579a41ec9dbe5bdbb74e787db21491be55 GIT binary patch literal 243 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lEak7ae3((L$1RH z0xlQ#?`!6G74r0)X0zXfyz?99Ix0ABU=2+7$TVx^Tw?O%YCYSz6PCMIF)dj2WX|7@ zQ4BK}oH&G%OUl1XEN&NQskOg$|5E*(*JswAJAU}{-i51XNHU}yOI;Up+bg>_Gdk>; r#Jy^9!HM^F_ZaS(;^fu&zm{Qjh4)G+9`^SP3=9mOu6{1-oD!M<{n}Zu literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_6.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_6.png new file mode 100644 index 0000000000000000000000000000000000000000..985abad9b3f3b1f30b61af0c918e354d43ca32eb GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lEak7aXC3bfmJ7N z&kuXQlilL_|Nesjh;e+Cuw;TM=gpRF%GD1a=@=Y~bM!mr?LFlEak7ad~a;Zr+9f z9_C!OQ$=eIvCY)T)JSAZvyjqoSnv2q>+~o0UruSCzAcMp=;C0E+7|kGqy6kqR)lEak7ad~gABUe*^ z2*dNtvX*UC^ZG8ly|aaHSHpuvt^vPS{Aire$(Gc0_5VJzs@62yGaSmRx;hvF_@+%S z7O6dbM#5R5EhpTN{cn*>)g=GZccmjrbmK%^OU?!9*WTSP{p@w`y(5XUW(7}FzMQ0! zIVaX-jdJx94}k~1PP3M2DLqoR);$-V^YzFy(fSAMR!7`76#u>kax8lEak7aXC3bfhEmu z@97O6uLjTgyS-j2Pf4-r{o~r-x{{H-{l`IZu dds;Iv>};3oVsYr2!N9=4;OXk;vd$@?2>=#3IF$eZ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_particles.png deleted file mode 100644 index d767eac39142bcb67c04a86c38c0292df9c01e48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)2UEx*7DJwkCaI zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifvPz2cu`=(SDaOFStmNt97!q;#?bNgW z!hs@3&#w(h=?PR)?eVf!(c|fMe7uZ1cISqRE3A{Z{1JU;@KL_t@gZLCIh>u^id}t% zM_6aO37xeO?|PVQrE8ZU(3-=|bMN=={C=jA`TqBVX9{H4 zr=@OuZ1KT+wM1-;L&O=L)0<|@+&K5ppR!d)g&88I9X**csq3gx_AIxVK5ggk@9@)q z_9>%V&f)Rwat4Oj>ycib3>R+R?5wcqi>fIvH*b~C)1L3Olz~C;c;SMC%O-(3VwN*~ zF10@l|FE)W^~Pk;8z#OlcAaCmaPJ=9{qKR@;j>ruZU6MDN`-?d%z$BqYm-7kZl>h6 z+|5m)vDZtt<<5Tm(W2}ThkOHuJ0h z%72(!$=ZJX^n{5RGp{* From 224ee281efd8d5333a45a452052ee87d66714d7e Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 22:18:14 +0000 Subject: [PATCH 48/68] Cleanup --- .../electroblob/wizardry/CommonProxy.java | 5 +- .../java/electroblob/wizardry/Settings.java | 2 +- .../java/electroblob/wizardry/WizardData.java | 53 +-------- .../java/electroblob/wizardry/Wizardry.java | 6 +- .../wizardry/WizardryGuiHandler.java | 3 +- .../wizardry/client/ClientProxy.java | 4 +- .../client/WizardryClientEventHandler.java | 2 +- .../client/model/ModelArmourFixer.java | 9 +- .../wizardry/client/model/ModelHammer.java | 103 ++++++++++-------- .../client/model/ModelWizardArmour.java | 2 +- .../client/model/WizardryItemModels.java | 5 +- .../electroblob/wizardry/constants/Tier.java | 3 +- .../entity/construct/EntityTornado.java | 3 +- .../entity/living/EntityAIAttackSpell.java | 1 + .../wizardry/entity/living/EntityWizard.java | 35 +++--- .../entity/living/ISummonedCreature.java | 6 +- .../entity/projectile/EntityFirebolt.java | 3 +- .../wizardry/item/IWorkbenchItem.java | 2 +- .../electroblob/wizardry/item/ItemWand.java | 2 +- .../wizardry/item/ItemWizardArmour.java | 4 +- .../wizardry/potion/PotionDecay.java | 6 +- .../electroblob/wizardry/registry/Spells.java | 6 +- .../wizardry/registry/WizardryBlocks.java | 7 -- .../registry/WizardryEnchantments.java | 5 +- .../wizardry/registry/WizardryRegistry.java | 72 ++---------- .../wizardry/registry/WizardrySounds.java | 3 +- .../electroblob/wizardry/spell/Light.java | 1 - .../electroblob/wizardry/spell/Spell.java | 4 +- .../wizardry/spell/SpellConstruct.java | 2 +- .../electroblob/wizardry/spell/SpellRay.java | 4 + .../tileentity/ContainerArcaneWorkbench.java | 8 +- .../wizardry/util/SpellModifiers.java | 7 +- .../wizardry/util/WizardryUtilities.java | 55 ++++------ 33 files changed, 160 insertions(+), 273 deletions(-) diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index 846d65ab..473f7eef 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -134,12 +134,12 @@ public class CommonProxy { * * @param entity The source of the sound * @param sound The SoundEvent to play + * @param category The SoundCategory to use * @param volume Volume relative to 1 * @param pitch Pitch relative to 1 * @param repeat Whether to repeat the sound for as long as the entity is alive (or until stopped manually) */ - public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){ - } + public void playMovingSound(Entity entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){} /** * Gets the client side world using Minecraft.getMinecraft().world. Only to be called client side! Returns @@ -153,5 +153,4 @@ public class CommonProxy { public Set getSpellHUDSkins(){ return null; } - } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java index 0917ece2..c8bc5585 100644 --- a/src/main/java/electroblob/wizardry/Settings.java +++ b/src/main/java/electroblob/wizardry/Settings.java @@ -144,7 +144,7 @@ public final class Settings { // Gamemodes /** * [Synchronised] When set to true, spells a player hasn't cast yet will be unreadable until they are cast - * (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in + * (on a per-world basis). Has no effect when in creative mode. Scrolls of identification will be unobtainable in * survival mode if this is false. */ public boolean discoveryMode = true; diff --git a/src/main/java/electroblob/wizardry/WizardData.java b/src/main/java/electroblob/wizardry/WizardData.java index bd779fef..50291ada 100644 --- a/src/main/java/electroblob/wizardry/WizardData.java +++ b/src/main/java/electroblob/wizardry/WizardData.java @@ -507,7 +507,6 @@ public class WizardData implements INBTSerializable { NBTTagCompound properties = new NBTTagCompound(); - // ...so Java 8 allows you to do stuff like this: properties.setTag("imbuements", WizardryUtilities.mapToNBT(this.imbuementDurations, imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new)); @@ -523,7 +522,7 @@ public class WizardData implements INBTSerializable { properties.setLong("clairvoyanceLocation", this.clairvoyanceLocation.toLong()); properties.setInteger("clairvoyanceDimension", this.getClairvoyanceDimension()); - // THIS is why I wrote the list/map <-> NBT methods. Look how neat this is! + // Mmmmmm Java 8.... properties.setTag("allies", WizardryUtilities.listToNBT(this.allies, WizardryUtilities::UUIDtoTagCompound)); properties.setTag("allyNames", WizardryUtilities.listToNBT(this.allyNames, NBTTagString::new)); properties.setTag("soulboundCreatures", WizardryUtilities.listToNBT(this.soulboundCreatures, WizardryUtilities::UUIDtoTagCompound)); @@ -661,54 +660,4 @@ public class WizardData implements INBTSerializable { } - // Ended up deleting IWizardData because it was unnecessary. This is the comment that was at the start of it: - - /* I'm not going to lie, I will never find the capabilities system even remotely intuitive so this is a bare-minimum - * approach just to get things working (four classes where one would have done?!) At one point I considered simply - * wrapping my old IEEP inside a single-field capability, but I eventually decided I would at least *try* to do it - * properly. - * - * "...without having to directly implement many interfaces." - Forge Docs. I still can't see what's wrong with - * implementing many interfaces; surely that's what Java interfaces are designed for? - * - * Other things I find annoying: - IStorage. It's completely redundant in the majority of cases, and I don't - * understand why we need yet another separate class. - Making an interface, only to implement it once and once - * only. This completely defeats the point of interfaces. - The EnumFacing parameter, which is again redundant for - * everything that isn't a tile entity. So much for a clean, neat system. - * - * What Forge has effectively done is conflated two different functions: attaching data to stuff and cross-mod - * integration/soft dependencies. I think this is bad design; it would have been better to keep the two features - * separate. - * - * Here's my current understanding of how the capability system works: - You make an interface which defines the - * things your capability can do (this class). I will call this the TEMPLATE. - You implement that interface with - * your default implementation (WizardData). This is the closest analog to your old IEEP implementation class. THIS - * CLASS STORES ALL THE VARIABLES, and hence has one instance for each instance of whatever it is attached to. I - * will call this the DATA. - The DATA class implements INBTSerializable (assuming you want it to be saved, which is - * nearly always the case) - Despite its name, Capability does NOT represent a capability itself. Instead, it - * acts as a sort of identifier/key, the idea being that you can access a particular instance of your DATA given the - * key (which tells forge that you want a capability of type TEMPLATE) and the object you want the DATA for. This is - * what Entity.getCapability(...) does. - * - * To really understand what's going on though, you need to sift through Forge's verbose data structures and find - * where capabilities are actually hooked into vanilla: - Anything that implements ICapabilityProvider will have a - * private CapabilityDispatcher field. This holds other ICapabilityProviders. (I know. This inheritance pattern DOES - * NOT MAKE SENSE, because these could, in theory, be OTHER ENTITIES!) - This field is assigned a value through - * Forge's event factory, which, as we are all familiar with, calls all the methods marked with @SubscribeEvent. - * These methods add individual ICapabilityProviders to a Map stored in the event, which the event factory then - * wraps in a CapabilityDispatcher (which is itself an ICapabilityProvider) for the object that called it. - In your - * event handler, you return a custom ICapabilityProvider which is effectively bolted on to the player, and - * duplicates the ICapabilityProvider methods so you can hook into them and return an instance of your DATA class. - - * Where before there was a simple collection of IEEPs stored in the player, there is now a tree of - * ICapabilityProviders: - * - * - Entity/TileEntity/ItemStack - Vanilla ICapabilityProviders, mostly IItemHandlers, stored as fields. - - * CapabilityDispatcher, stored as a field. - Custom ICapabilityProviders - Custom CapabilityDispatchers - ... - * - * Most importantly, EACH PLAYER HOLDS THEIR OWN INSTANCE OF THIS TREE. - * - * When a capability is retrieved, the following process happens: 1. For the Entity/TileEntity/ItemStack instance, - * ICapabilityProvider.getCapability(...) is called. 2. The request propogates through the tree and finds the - * requested capability. */ - } diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index c746803a..732b36ae 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -79,7 +79,6 @@ public class Wizardry { // TODO: Switch from IInventory to IItemHandler (Or don't. It's only useful for automation really.) // TODO: Have particles obey Minecraft's particle setting where appropriate // (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java) - // TODO: Interfaces for various things, like 'stuff that can be put in the central slot of an arcane workbench' // TODO: Go over all the worldgen code, use IWorldGenerator // TODO: Implement a continuous sound system using MovingSoundEntity, allowing continuous spells to have a long sound // loop as well as a start and end sound @@ -88,6 +87,9 @@ public class Wizardry { // TODO: Replace spell IDs in packets with ResourceLocation strings // TODO: Forcefield needs looking at, esp. with regards to projectiles and explosions // TODO: TileEntityArcaneWorkbench needs looking at, esp. regarding inventory and markDirty + // TODO: Fireskin somehow lost its particles + // TODO: Convert settings over to the @Config system + // TODO: Go through listeners of LivingHurtEvent and decide whether they should change to LivingDamageEvent // NOTE: Add melee upgrades to loot tables when they are added. @@ -208,7 +210,7 @@ public class Wizardry { for(RegistryEvent.MissingMappings.Mapping mapping : event.getAllMappings()){ if(mapping.key.getResourceDomain().equals(Wizardry.MODID)){ - Item replacement = null; + Item replacement; switch(mapping.key.getResourcePath()){ diff --git a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java index 13cfaaa6..5bd9364c 100644 --- a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java @@ -1,5 +1,6 @@ package electroblob.wizardry; +import electroblob.wizardry.client.gui.handbook.GuiWizardHandbook; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.item.ItemWizardHandbook; import electroblob.wizardry.spell.Spell; @@ -45,7 +46,7 @@ public class WizardryGuiHandler implements IGuiHandler { } }else if(id == WIZARD_HANDBOOK && (player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook || player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook)){ - return new electroblob.wizardry.client.gui.GuiWizardHandbook(); + return new GuiWizardHandbook(); }else if(id == SPELL_BOOK){ if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){ return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.get(player.getHeldItemMainhand().getItemDamage())); diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 82630f2d..685455be 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -533,8 +533,8 @@ public class ClientProxy extends CommonProxy { RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new); // Creatures - RenderingRegistry.registerEntityRenderingHandler(EntitySpiritWolf.class, manager -> new RenderSpiritWolf(manager)); - RenderingRegistry.registerEntityRenderingHandler(EntitySpiritHorse.class, manager -> new RenderSpiritHorse(manager)); + RenderingRegistry.registerEntityRenderingHandler(EntitySpiritWolf.class, RenderSpiritWolf::new); + RenderingRegistry.registerEntityRenderingHandler(EntitySpiritHorse.class, RenderSpiritHorse::new); RenderingRegistry.registerEntityRenderingHandler(EntityWizard.class, RenderWizard::new); RenderingRegistry.registerEntityRenderingHandler(EntityEvilWizard.class, RenderEvilWizard::new); RenderingRegistry.registerEntityRenderingHandler(EntityDecoy.class, RenderDecoy::new); diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java index ced104f6..b06ef376 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -48,7 +48,7 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; /** - * Event handler responsible for all client-side only events, mostly rendering. + * Event handler responsible for client-side only events, mostly rendering. * * @author Electroblob * @since Wizardry 1.0 diff --git a/src/main/java/electroblob/wizardry/client/model/ModelArmourFixer.java b/src/main/java/electroblob/wizardry/client/model/ModelArmourFixer.java index ced31285..793f21e8 100644 --- a/src/main/java/electroblob/wizardry/client/model/ModelArmourFixer.java +++ b/src/main/java/electroblob/wizardry/client/model/ModelArmourFixer.java @@ -4,9 +4,14 @@ import net.minecraft.client.model.ModelBiped; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityArmorStand; -public class ModelWtfMojang extends ModelBiped { +/** + * Fixes custom armour models 'breathing' on the stand and rotates the helmet properly. + * @author Shadows-of-Fire + * @since Wizardry 4.1.2 + */ +public class ModelArmourFixer extends ModelBiped { - public ModelWtfMojang(float modelSize, float rotationYOffset, int textureWidth, int textureHeight) { + public ModelArmourFixer(float modelSize, float rotationYOffset, int textureWidth, int textureHeight) { super(modelSize, rotationYOffset, textureWidth, textureHeight); } diff --git a/src/main/java/electroblob/wizardry/client/model/ModelHammer.java b/src/main/java/electroblob/wizardry/client/model/ModelHammer.java index 85a164f7..c28c4d6e 100644 --- a/src/main/java/electroblob/wizardry/client/model/ModelHammer.java +++ b/src/main/java/electroblob/wizardry/client/model/ModelHammer.java @@ -5,64 +5,71 @@ import net.minecraft.client.model.ModelRenderer; import net.minecraft.entity.Entity; public class ModelHammer extends ModelBase { - ModelRenderer Shape1; - ModelRenderer Shape2; - ModelRenderer Shape3; - ModelRenderer Shape4; - ModelRenderer Shape5; - ModelRenderer Shape6; + + ModelRenderer hammerHead; + ModelRenderer handle; + ModelRenderer handleEnd; + ModelRenderer handleBase; + ModelRenderer ring1; + ModelRenderer ring2; public ModelHammer(){ + textureWidth = 64; textureHeight = 64; - Shape1 = new ModelRenderer(this, 0, 0); - Shape1.addBox(0F, 0F, 0F, 20, 12, 12); - Shape1.setRotationPoint(-10F, 12F, -6F); - Shape1.setTextureSize(64, 64); - Shape1.mirror = true; - setRotation(Shape1, 0F, 0F, 0F); - Shape2 = new ModelRenderer(this, 0, 24); - Shape2.addBox(0F, 0F, 0F, 4, 14, 4); - Shape2.setRotationPoint(-2F, -2F, -2F); - Shape2.setTextureSize(64, 64); - Shape2.mirror = true; - setRotation(Shape2, 0F, 0F, 0F); - Shape3 = new ModelRenderer(this, 0, 49); - Shape3.addBox(0F, 0F, 0F, 5, 5, 5); - Shape3.setRotationPoint(-2.5F, -7F, -2.5F); - Shape3.setTextureSize(64, 64); - Shape3.mirror = true; - setRotation(Shape3, 0F, 0F, 0F); - Shape4 = new ModelRenderer(this, 0, 42); - Shape4.addBox(0F, 0F, 0F, 5, 2, 5); - Shape4.setRotationPoint(-2.5F, 10F, -2.5F); - Shape4.setTextureSize(64, 64); - Shape4.mirror = true; - setRotation(Shape4, 0F, 0F, 0F); - Shape5 = new ModelRenderer(this, 20, 24); - Shape5.addBox(0F, 0F, 0F, 2, 14, 14); - Shape5.setRotationPoint(-8F, 11F, -7F); - Shape5.setTextureSize(64, 64); - Shape5.mirror = true; - setRotation(Shape5, 0F, 0F, 0F); - Shape6 = new ModelRenderer(this, 20, 24); - Shape6.addBox(0F, 0F, 0F, 2, 14, 14); - Shape6.setRotationPoint(6F, 11F, -7F); - Shape6.setTextureSize(64, 64); - Shape6.mirror = true; - setRotation(Shape6, 0F, 0F, 0F); + hammerHead = new ModelRenderer(this, 0, 0); + hammerHead.addBox(0F, 0F, 0F, 20, 12, 12); + hammerHead.setRotationPoint(-10F, 12F, -6F); + hammerHead.setTextureSize(64, 64); + hammerHead.mirror = true; + setRotation(hammerHead, 0F, 0F, 0F); + + handle = new ModelRenderer(this, 0, 24); + handle.addBox(0F, 0F, 0F, 4, 14, 4); + handle.setRotationPoint(-2F, -2F, -2F); + handle.setTextureSize(64, 64); + handle.mirror = true; + setRotation(handle, 0F, 0F, 0F); + + handleEnd = new ModelRenderer(this, 0, 49); + handleEnd.addBox(0F, 0F, 0F, 5, 5, 5); + handleEnd.setRotationPoint(-2.5F, -7F, -2.5F); + handleEnd.setTextureSize(64, 64); + handleEnd.mirror = true; + setRotation(handleEnd, 0F, 0F, 0F); + + handleBase = new ModelRenderer(this, 0, 42); + handleBase.addBox(0F, 0F, 0F, 5, 2, 5); + handleBase.setRotationPoint(-2.5F, 10F, -2.5F); + handleBase.setTextureSize(64, 64); + handleBase.mirror = true; + setRotation(handleBase, 0F, 0F, 0F); + + ring1 = new ModelRenderer(this, 20, 24); + ring1.addBox(0F, 0F, 0F, 2, 14, 14); + ring1.setRotationPoint(-8F, 11F, -7F); + ring1.setTextureSize(64, 64); + ring1.mirror = true; + setRotation(ring1, 0F, 0F, 0F); + + ring2 = new ModelRenderer(this, 20, 24); + ring2.addBox(0F, 0F, 0F, 2, 14, 14); + ring2.setRotationPoint(6F, 11F, -7F); + ring2.setTextureSize(64, 64); + ring2.mirror = true; + setRotation(ring2, 0F, 0F, 0F); } public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){ super.render(entity, f, f1, f2, f3, f4, f5); setRotationAngles(f, f1, f2, f3, f4, f5, entity); - Shape1.render(f5); - Shape2.render(f5); - Shape3.render(f5); - Shape4.render(f5); - Shape5.render(f5); - Shape6.render(f5); + hammerHead.render(f5); + handle.render(f5); + handleEnd.render(f5); + handleBase.render(f5); + ring1.render(f5); + ring2.render(f5); } private void setRotation(ModelRenderer model, float x, float y, float z){ diff --git a/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java b/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java index ee371d3c..20429a71 100644 --- a/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java +++ b/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java @@ -3,7 +3,7 @@ package electroblob.wizardry.client.model; import net.minecraft.client.model.ModelRenderer; import net.minecraft.entity.Entity; -public class ModelWizardArmour extends ModelWtfMojang { +public class ModelWizardArmour extends ModelArmourFixer { ModelRenderer Shape1; ModelRenderer Shape2; ModelRenderer Shape3; diff --git a/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java b/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java index 0f5cec39..f9d101c8 100644 --- a/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java +++ b/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java @@ -166,9 +166,8 @@ public final class WizardryItemModels { * Registers an item model, using the item's registry name as the model name (this convention makes it easier to * keep track of everything). Variant defaults to "normal". Registers the model for metadata 0 automatically, plus * all the other metadata values that the item can take, as defined in - * {@link Item#getSubItems(Item, net.minecraft.creativetab.CreativeTabs, java.util.List)}. The passed in item - * must allow null to be passed in for the creative tab parameter in the aforementioned method, or a - * {@link NullPointerException} will result. + * {@link Item#getSubItems(Item, net.minecraft.creativetab.CreativeTabs, java.util.List)}. The creative tab supplied + * to the aforementioned method will be whichever one the item is in. */ private static void registerItemModel(Item item){ diff --git a/src/main/java/electroblob/wizardry/constants/Tier.java b/src/main/java/electroblob/wizardry/constants/Tier.java index 8d9c0e77..2cadd2a0 100644 --- a/src/main/java/electroblob/wizardry/constants/Tier.java +++ b/src/main/java/electroblob/wizardry/constants/Tier.java @@ -68,8 +68,7 @@ public enum Tier { int totalWeight = 0; - for(Tier tier : tiers) - totalWeight += tier.weight; + for(Tier tier : tiers) totalWeight += tier.weight; int randomiser = random.nextInt(totalWeight); int cumulativeWeight = 0; diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java index a2c6248c..3571aaa4 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java @@ -137,8 +137,7 @@ public class EntityTornado extends EntityMagicConstruct { Type type = null; if(block.getMaterial() == Material.LEAVES) type = Type.LEAF; - if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW) - type = Type.SNOW; + if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW) type = Type.SNOW; if(type != null){ double yPos1 = rand.nextDouble() * 8; diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java index 57e5cadf..85b9d65d 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java @@ -108,6 +108,7 @@ public class EntityAIAttackSpell extends new PacketNPCCastSpell.Message(attacker.getEntityId(), target == null ? -1 : target.getEntityId(), EnumHand.MAIN_HAND, spell.id(), modifiers), // Particles are usually only visible from 16 blocks away, so 128 is more than far enough. + // TODO: Why is this one a 128 block radius, whilst the other one is all in dimension? new TargetPoint(attacker.dimension, attacker.posX, attacker.posY, attacker.posZ, 128)); } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 1e71a7c2..7115fcd9 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -146,29 +146,26 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp this.tasks.addTask(7, new EntityAIWander(this, 0.6D)); this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F)); - this.targetSelector = new Predicate(){ + this.targetSelector = entity -> { - public boolean apply(Entity entity){ + // If the target is valid and not invisible... + if(entity != null && !entity.isInvisible() + && WizardryUtilities.isValidTarget(EntityWizard.this, entity)){ - // If the target is valid and not invisible... - if(entity != null && !entity.isInvisible() - && WizardryUtilities.isValidTarget(EntityWizard.this, entity)){ - - // ... and is a mob, a summoned creature ... - if((entity instanceof IMob || entity instanceof ISummonedCreature - // ... or in the whitelist ... - || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist) - .contains(EntityList.getKey(entity.getClass()))) - // ... and isn't in the blacklist ... - && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist) - .contains(EntityList.getKey(entity.getClass()))){ - // ... it can be attacked. - return true; - } + // ... and is a mob, a summoned creature ... + if((entity instanceof IMob || entity instanceof ISummonedCreature + // ... or in the whitelist ... + || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist) + .contains(EntityList.getKey(entity.getClass()))) + // ... and isn't in the blacklist ... + && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist) + .contains(EntityList.getKey(entity.getClass()))){ + // ... it can be attacked. + return true; } - - return false; } + + return false; }; this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); diff --git a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java index a3bbfcee..b510dc9c 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java @@ -157,7 +157,7 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { * Called by the client when it receives a Entity spawn packet. Data should be read out of the stream in the same * way as it was written. Implementors must call super when overriding. * - * @param additionalData The packet data stream + * @param buffer The packet data stream */ @Override default void readSpawnData(ByteBuf buffer){ @@ -241,11 +241,11 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { * to do something when a successful attack is made. This was added because the event-based damage source system can * cause parts of attackEntityAsMob not to fire, since attackEntityFrom is intercepted and canceled. *

- * Usage examples: {@link EntitySliverfishMinion} uses this to summon more silverfish if the target is killed, + * Usage examples: {@link EntitySilverfishMinion} uses this to summon more silverfish if the target is killed, * {@link EntitySkeletonMinion} and {@link EntitySpiderMinion} use this to add potion effects to the target. */ default void onSuccessfulAttack(EntityLivingBase target){ - }; + } // Delegates diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java index d0bfcf28..50c5e648 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java @@ -34,8 +34,7 @@ public class EntityFirebolt extends EntityMagicProjectile { if(world.isRemote){ for(int i = 0; i < 8; i++){ world.spawnParticle(EnumParticleTypes.LAVA, this.posX + rand.nextFloat() - 0.5, - this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, - 0); + this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0); } } diff --git a/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java b/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java index 22af5327..704bebec 100644 --- a/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java +++ b/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java @@ -7,7 +7,7 @@ import net.minecraft.item.ItemStack; /** * Items that implement this interface may be placed in the central slot of the arcane workbench as long as - * {@link IWorkbenchItem#canPlace(ItemStack)} returns true.The number of spell book slots displayed is also specified + * {@link IWorkbenchItem#canPlace(ItemStack)} returns true. The number of spell book slots displayed is also specified * using {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}. *

* Items that implement this interface define what happens if they are in the central slot of the arcane workbench and diff --git a/src/main/java/electroblob/wizardry/item/ItemWand.java b/src/main/java/electroblob/wizardry/item/ItemWand.java index d772ad55..950a5a5d 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWand.java +++ b/src/main/java/electroblob/wizardry/item/ItemWand.java @@ -52,7 +52,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; * written the {@link WandHelper} class. I strongly recommend you use it for interacting with wand items wherever * possible. *

- * It's unikely that anything in this class will be of much use externally, but should you wish to use it for whatever + * It's unlikely that anything in this class will be of much use externally, but should you wish to use it for whatever * reason (perhaps if you extend it), it works as follows: *

* - onItemRightClick is where non-continuous spells are cast, and it sets the item in use for continuous spells
diff --git a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java index 898576b5..c3d42872 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java +++ b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java @@ -37,9 +37,9 @@ import net.minecraftforge.fml.relauncher.SideOnly; @Mod.EventBusSubscriber public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { - //VanillaCopy, ItemArmor has this set to private for some reason. + // VanillaCopy, ItemArmor has this set to private for some reason. public static final UUID[] ARMOR_MODIFIERS = new UUID[] {UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")}; - //Damage reduction values that used to be in WizardryItems.SILK [feet, legs, chest, head] + // Damage reduction values that used to be in WizardryItems.SILK [feet, legs, chest, head] private static int[] reductions = new int[]{2, 4, 5, 2}; public Element element; diff --git a/src/main/java/electroblob/wizardry/potion/PotionDecay.java b/src/main/java/electroblob/wizardry/potion/PotionDecay.java index db22ee7e..91a6c854 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionDecay.java +++ b/src/main/java/electroblob/wizardry/potion/PotionDecay.java @@ -34,11 +34,11 @@ public class PotionDecay extends Potion { } @Override - public boolean isReady(int p_76397_1_, int p_76397_2_){ + public boolean isReady(int duration, int amplifier){ // Copied from the vanilla wither effect. It does the timing stuff. 25 is the number of ticks between hits at // amplifier 0 - int k = 25 >> p_76397_2_; - return k > 0 ? p_76397_1_ % k == 0 : true; + int k = 25 >> amplifier; + return k > 0 ? duration % k == 0 : true; } @Override diff --git a/src/main/java/electroblob/wizardry/registry/Spells.java b/src/main/java/electroblob/wizardry/registry/Spells.java index 64abadc4..eb775f1e 100644 --- a/src/main/java/electroblob/wizardry/registry/Spells.java +++ b/src/main/java/electroblob/wizardry/registry/Spells.java @@ -54,7 +54,8 @@ import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.RegistryBuilder; /** - * Class responsible for defining, storing and registering all of wizardry's spells. + * Class responsible for defining, storing and registering all of wizardry's spells. Use this to access individual + * spell instances, similar to the {@code Blocks} and {@code Items} classes. * * @author Electroblob * @since Wizardry 2.1 @@ -75,7 +76,8 @@ public final class Spells { public static void createRegistry(RegistryEvent.NewRegistry event){ // Beats me why we need both of these. Surely the type parameter means it already knows? - RegistryBuilder builder = new RegistryBuilder(); + // EDIT: It's probably because of type erasure, thinking about it. + RegistryBuilder builder = new RegistryBuilder<>(); builder.setType(Spell.class); builder.setName(new ResourceLocation(Wizardry.MODID, "spells")); builder.setIDRange(0, 5000); // Is there any penalty for using a larger number? diff --git a/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java b/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java index 3fcb2495..a88bff23 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java @@ -26,13 +26,6 @@ import net.minecraftforge.registries.IForgeRegistry; @Mod.EventBusSubscriber public final class WizardryBlocks { - // I get registry events, they make sense - even I doubted myself with when to do various things in the load - // process, - // so I can see why the folks at Forge wanted to save us having to think about it. - // What I do not understand is why you would use @ObjectHolder for your own blocks and items. What's the point in - // making your code longer and more complicated, when you can just define the blocks as constants and register them - // later? - // Found a very nice way of registering things using arrays, which might make @ObjectHolder actually useful. // http://www.minecraftforge.net/forum/topic/49497-1112-is-using-registryevent-this-way-ok/ diff --git a/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java b/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java index 09288bb2..2c3ba970 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java @@ -17,12 +17,11 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber public final class WizardryEnchantments { - // At the moment these enchantments generate on books in dungeon chests due to a bad bit of code - // (EnchantRandomly:50). + // At the moment these enchantments generate on books in dungeon chests due to a bad bit of code (EnchantRandomly:49). // No idea how to fix this because I have no way of hooking into that code... removing the enchantments from the // registry works, but breaks everything else! - // TODO: For the time being, a dynamic solution will have to do, i.e. intercept the book when it is generated and + // For the time being, a dynamic solution will have to do, i.e. intercept the book when it is generated and // reassign its enchantment. // All of these have custom classes, so the unlocalised name (referred to simply as 'name' for enchantments) is diff --git a/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java b/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java index 62f863f4..6b150adc 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java @@ -1,74 +1,18 @@ package electroblob.wizardry.registry; -import java.util.List; - import com.google.common.collect.Lists; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.entity.EntityMeteor; import electroblob.wizardry.entity.EntityShield; -import electroblob.wizardry.entity.construct.EntityArrowRain; -import electroblob.wizardry.entity.construct.EntityBlackHole; -import electroblob.wizardry.entity.construct.EntityBlizzard; -import electroblob.wizardry.entity.construct.EntityBubble; -import electroblob.wizardry.entity.construct.EntityDecay; -import electroblob.wizardry.entity.construct.EntityEarthquake; -import electroblob.wizardry.entity.construct.EntityFireRing; -import electroblob.wizardry.entity.construct.EntityFireSigil; -import electroblob.wizardry.entity.construct.EntityForcefield; -import electroblob.wizardry.entity.construct.EntityFrostSigil; -import electroblob.wizardry.entity.construct.EntityHailstorm; -import electroblob.wizardry.entity.construct.EntityHammer; -import electroblob.wizardry.entity.construct.EntityHealAura; -import electroblob.wizardry.entity.construct.EntityIceSpike; -import electroblob.wizardry.entity.construct.EntityLightningPulse; -import electroblob.wizardry.entity.construct.EntityLightningSigil; -import electroblob.wizardry.entity.construct.EntityTornado; -import electroblob.wizardry.entity.living.EntityBlazeMinion; -import electroblob.wizardry.entity.living.EntityDecoy; -import electroblob.wizardry.entity.living.EntityEvilWizard; -import electroblob.wizardry.entity.living.EntityIceGiant; -import electroblob.wizardry.entity.living.EntityIceWraith; -import electroblob.wizardry.entity.living.EntityLightningWraith; -import electroblob.wizardry.entity.living.EntityMagicSlime; -import electroblob.wizardry.entity.living.EntityPhoenix; -import electroblob.wizardry.entity.living.EntityShadowWraith; -import electroblob.wizardry.entity.living.EntitySilverfishMinion; -import electroblob.wizardry.entity.living.EntitySkeletonMinion; -import electroblob.wizardry.entity.living.EntitySpiderMinion; -import electroblob.wizardry.entity.living.EntitySpiritHorse; -import electroblob.wizardry.entity.living.EntitySpiritWolf; -import electroblob.wizardry.entity.living.EntityStormElemental; -import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; -import electroblob.wizardry.entity.living.EntityWizard; -import electroblob.wizardry.entity.living.EntityZombieMinion; -import electroblob.wizardry.entity.projectile.EntityDarknessOrb; -import electroblob.wizardry.entity.projectile.EntityDart; -import electroblob.wizardry.entity.projectile.EntityFirebolt; -import electroblob.wizardry.entity.projectile.EntityFirebomb; -import electroblob.wizardry.entity.projectile.EntityForceArrow; -import electroblob.wizardry.entity.projectile.EntityForceOrb; -import electroblob.wizardry.entity.projectile.EntityIceCharge; -import electroblob.wizardry.entity.projectile.EntityIceLance; -import electroblob.wizardry.entity.projectile.EntityIceShard; -import electroblob.wizardry.entity.projectile.EntityLightningArrow; -import electroblob.wizardry.entity.projectile.EntityLightningDisc; -import electroblob.wizardry.entity.projectile.EntityMagicMissile; -import electroblob.wizardry.entity.projectile.EntityPoisonBomb; -import electroblob.wizardry.entity.projectile.EntitySmokeBomb; -import electroblob.wizardry.entity.projectile.EntitySpark; -import electroblob.wizardry.entity.projectile.EntitySparkBomb; -import electroblob.wizardry.entity.projectile.EntityThunderbolt; +import electroblob.wizardry.entity.construct.*; +import electroblob.wizardry.entity.living.*; +import electroblob.wizardry.entity.projectile.*; import electroblob.wizardry.loot.RandomSpell; import electroblob.wizardry.loot.WizardSpell; -import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; -import electroblob.wizardry.tileentity.TileEntityMagicLight; -import electroblob.wizardry.tileentity.TileEntityPlayerSave; -import electroblob.wizardry.tileentity.TileEntityStatue; -import electroblob.wizardry.tileentity.TileEntityTimer; +import electroblob.wizardry.tileentity.*; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EnumCreatureType; @@ -91,6 +35,8 @@ import net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.ShapelessOreRecipe; import net.minecraftforge.registries.IForgeRegistry; +import java.util.List; + /** * Class responsible for registering all the things that don't have (or need) instances: entities, loot tables, recipes, * etc. @@ -101,13 +47,11 @@ import net.minecraftforge.registries.IForgeRegistry; @Mod.EventBusSubscriber public final class WizardryRegistry { - // NOTE: In 1.12, recipes have a registry (they can still stay here though since we don't keep references to them) - /** Called from the preInit method in the main mod class to register the custom dungeon loot. */ public static void registerLoot(){ /* Loot tables work as follows: Minecraft goes through each pool in turn. For each pool, it does a certain - * number or rolls, which can either be set to always be one number or a random number from a range. Each roll, + * number of rolls, which can either be set to always be one number or a random number from a range. Each roll, * it generates one stack of a single random entry in that pool, weighted according to the weights of the * entries. Functions allow properties of that stack (stack size, damage, nbt) to be set, and even allow it to * be replaced dynamically with a completely different item (though there's very little point in doing that as @@ -246,7 +190,7 @@ public final class WizardryRegistry { /** Now only deals with the dynamic crafting recipes and the smelting recipes. */ @SubscribeEvent public static void registerRecipes(RegistryEvent.Register event){ - + IForgeRegistry registry = event.getRegistry(); FurnaceRecipes.instance().addSmeltingRecipeForBlock(WizardryBlocks.crystal_ore, new ItemStack(WizardryItems.magic_crystal), 0.5f); diff --git a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java index 5b50eb61..e472c4c5 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java +++ b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java @@ -8,8 +8,7 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; /** - * Class responsible for defining, storing and registering all of wizardry's sound events. For some reason, these worked - * in the beta versions despite not being registered... + * Class responsible for defining, storing and registering all of wizardry's sound events. * * @author Electroblob * @since Wizardry 2.1 diff --git a/src/main/java/electroblob/wizardry/spell/Light.java b/src/main/java/electroblob/wizardry/spell/Light.java index b97cf15b..76b5fb9b 100644 --- a/src/main/java/electroblob/wizardry/spell/Light.java +++ b/src/main/java/electroblob/wizardry/spell/Light.java @@ -59,7 +59,6 @@ public class Light extends Spell { BlockPos pos = new BlockPos(x, y, z); if(world.isAirBlock(pos)){ - // world.playSound(x, y, z, "sound.ambient.cave.cave", 1.0f, 1.5f, false); if(!world.isRemote){ world.setBlockState(pos, WizardryBlocks.magic_light.getDefaultState()); if(world.getTileEntity(pos) instanceof TileEntityTimer){ diff --git a/src/main/java/electroblob/wizardry/spell/Spell.java b/src/main/java/electroblob/wizardry/spell/Spell.java index b7b1a930..20484baf 100644 --- a/src/main/java/electroblob/wizardry/spell/Spell.java +++ b/src/main/java/electroblob/wizardry/spell/Spell.java @@ -272,7 +272,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C return modID; } - /** Returns the ResourceLocation for this spell's icon. */ + /** Returns the {@code ResourceLocation} for this spell's icon. */ public final ResourceLocation getIcon(){ return icon; } @@ -368,7 +368,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C /** * Returns the total number of registered spells, excluding the 'None' spell. Returns the same number that would be - * returned by Spell.getSpells(Spell.allSpells).size(), but this method is more efficient. + * returned by {@code Spell.getSpells(Spell.allSpells).size()}, but this method is more efficient. */ public static int getTotalSpellCount(){ return registry.getValuesCollection().size() - 1; diff --git a/src/main/java/electroblob/wizardry/spell/SpellConstruct.java b/src/main/java/electroblob/wizardry/spell/SpellConstruct.java index bd3b4ad5..dce473e5 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellConstruct.java +++ b/src/main/java/electroblob/wizardry/spell/SpellConstruct.java @@ -40,7 +40,7 @@ import net.minecraft.world.World; */ public class SpellConstruct extends Spell { - /** A factory that creates projectile entities. */ + /** A factory that creates construct entities. */ protected final Function constructFactory; /** The base lifetime of the construct created by this spell, or -1 if the construct does not despawn. */ protected final int baseDuration; diff --git a/src/main/java/electroblob/wizardry/spell/SpellRay.java b/src/main/java/electroblob/wizardry/spell/SpellRay.java index 41c65e52..0ac28b72 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellRay.java +++ b/src/main/java/electroblob/wizardry/spell/SpellRay.java @@ -276,6 +276,10 @@ public abstract class SpellRay extends Spell { spawnParticle(world, x, y, z, velocity.x, velocity.y, velocity.z); } } + // The exact behaviour of the returned values of the following three methods can be a little confusing. Normally, + // either onEntityHit or onBlockHit (or both) will return true when the spell succeeded in hitting the block or + // entity, and false if not (note that those two methods are mutually exclusive). If false is returned, onMiss will + // be called - onMiss will never be called if either of the other methods returns true. /** * Called when the spell hits an entity. Will never be called if ignoreEntities is true. diff --git a/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java b/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java index 523f9b7a..8bd2d63f 100644 --- a/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java @@ -26,10 +26,8 @@ public class ContainerArcaneWorkbench extends Container { /** The arcane workbench tile entity associated with this container. */ public TileEntityArcaneWorkbench tileentity; - public static final ResourceLocation EMPTY_SLOT_CRYSTAL = new ResourceLocation(Wizardry.MODID, - "gui/empty_slot_crystal"); - public static final ResourceLocation EMPTY_SLOT_UPGRADE = new ResourceLocation(Wizardry.MODID, - "gui/empty_slot_upgrade"); + public static final ResourceLocation EMPTY_SLOT_CRYSTAL = new ResourceLocation(Wizardry.MODID, "gui/empty_slot_crystal"); + public static final ResourceLocation EMPTY_SLOT_UPGRADE = new ResourceLocation(Wizardry.MODID, "gui/empty_slot_upgrade"); public static final int CRYSTAL_SLOT = 8; public static final int CENTRE_SLOT = 9; @@ -260,7 +258,7 @@ public class ContainerArcaneWorkbench extends Container { if(((IWorkbenchItem)centre.getStack().getItem()) .onApplyButtonPressed(player, centre, this.getSlot(CRYSTAL_SLOT), this.getSlot(UPGRADE_SLOT), spellBooks)){ - // TODO: Sound and possibly animation for spell binding + // Probably don't need to do anything here, unless we're going to use packets to control the animation } } } diff --git a/src/main/java/electroblob/wizardry/util/SpellModifiers.java b/src/main/java/electroblob/wizardry/util/SpellModifiers.java index 59155a29..a8ee1e91 100644 --- a/src/main/java/electroblob/wizardry/util/SpellModifiers.java +++ b/src/main/java/electroblob/wizardry/util/SpellModifiers.java @@ -26,8 +26,8 @@ import net.minecraftforge.fml.common.network.ByteBufUtils; * that not all wand upgrades affect spells). SpellModifiers objects are mutable, so you can simply change the * values they contain to modify the spell. *

- * To use a SpellModifiers object within the Spell.cast methods, simply retrieve the desired multiplier - * using {@link SpellModifiers#get(Item)} for wand upgrades, or {@link SpellModifiers#get(String)} if the multiplier is + * To use a SpellModifiers object within the Spell.cast methods, simply retrieve the desired modifier + * using {@link SpellModifiers#get(Item)} for wand upgrades, or {@link SpellModifiers#get(String)} if the modifier is * not from a wand upgrade. * * @author Electroblob @@ -139,6 +139,9 @@ public final class SpellModifiers { buf.writeFloat(entry.getValue()); } } + + // These two don't use the Map <-> NBT methods in WizardryUtilities because it's better to use the strings as keys + // themselves rather than storing them separately. /** * Creates a new SpellModifiers object from the given NBTTagCompound. The NBTTagCompound should have 1 or more float diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index d8381f99..a00bfbc3 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -80,17 +80,15 @@ import net.minecraftforge.fml.relauncher.SideOnly; */ public final class WizardryUtilities { - /** - * Constant which is simply an array of the four armour slots. (Could've sworn this exists somewhere in vanilla, but - * I can't find it anywhere...) - */ + /** Constant which is simply an array of the four armour slots. (Could've sworn this exists somewhere in vanilla, + * but I can't find it anywhere...) */ public static final EntityEquipmentSlot[] ARMOUR_SLOTS; /** Changed to a constant in wizardry 2.1, since this is a lot more efficient. */ private static final DataParameter POWERED; - static{ + static { // The list of slots needs to be mutable. - List slots = new ArrayList( + List slots = new ArrayList<>( Arrays.asList(EntityEquipmentSlot.values())); slots.removeIf(slot -> slot.getSlotType() != Type.ARMOR); ARMOUR_SLOTS = slots.toArray(new EntityEquipmentSlot[0]); @@ -146,13 +144,11 @@ public final class WizardryUtilities { /** * Returns whether the block at the given coordinates is unbreakable in survival mode. In vanilla this is true for - * bedrock and end portal frame, for example. This is a shortcut for - * world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f. Not much of a shortcut any more, since block ids - * have been phased out. + * bedrock and end portal frame, for example. This is a shortcut for:

+ * {@code world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f} */ public static boolean isBlockUnbreakable(World world, BlockPos pos){ - return world.isAirBlock(new BlockPos(pos)) ? false - : world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f; + return !world.isAirBlock(new BlockPos(pos)) && world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f; } /** @@ -160,11 +156,9 @@ public final class WizardryUtilities { * Liquids and other blocks that cannot be built on top of do not count, but stuff like signs does. (Technically any * block is allowed to be the floor according to the code, but seeing as it searches upwards and non-solid blocks * usually need a supporting block, the floor is likely to always be solid). - * - * @param world - * @param x The x coordinate to search in - * @param y The y coordinate to search from - * @param z The z coordinate to search in + * + * @param world The world to search in + * @param pos The coordinates to search from * @param range The maximum distance from the given y coordinate to search. * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the * floor as would be seen in the debug screen when the player is standing on it. @@ -189,10 +183,8 @@ public final class WizardryUtilities { * Finds the nearest floor level to the given y coord within the range specified at the given x and z coords. Only * works if the block above the floor is actually air and the floor is solid or a liquid. * - * @param world - * @param x The x coordinate to search in - * @param y The y coordinate to search from - * @param z The z coordinate to search in + * @param world The world to search in + * @param pos The coordinates to search from * @param range The maximum distance from the given y coordinate to search. * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the * floor as would be seen in the debug screen when the player is standing on it. @@ -216,11 +208,9 @@ public final class WizardryUtilities { /** * Finds the nearest floor level to the given y coord within the range specified at the given x and z coords. * Everything that is not air is treated as floor, even stuff that can't be walked on. - * - * @param world - * @param x The x coordinate to search in - * @param y The y coordinate to search from - * @param z The z coordinate to search in + * + * @param world The world to search in + * @param pos The coordinates to search from * @param range The maximum distance from the given y coordinate to search. * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the * floor as would be seen in the debug screen when the player is standing on it. @@ -300,7 +290,7 @@ public final class WizardryUtilities { /** * Gets the blockstate of the block the specified entity is standing on. Uses - * {@link MathHelper#floor_double(double)} because casting to int will not return the correct coordinate when x or z + * {@link MathHelper#floor(double)} because casting to int will not return the correct coordinate when x or z * is negative. */ public static IBlockState getBlockEntityIsStandingOn(Entity entity){ @@ -331,7 +321,7 @@ public final class WizardryUtilities { * this does not exclude any entities; if any specific entities are to be excluded this must be checked when * iterating through the list. * - * @see {@link WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World)} + * @see WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World) * @param radius The search radius * @param x The x coordinate to search around * @param y The y coordinate to search around @@ -396,12 +386,11 @@ public final class WizardryUtilities { /** * Returns the entity riding the given entity, or null if there is none. Allows for neater code now that entities - * have a list of passengers, because it is necessary to check that the list is not null or empty first. + * have a list of passengers, because it is necessary to check that the list is not empty first. */ @Nullable public static Entity getRider(Entity entity){ - return entity.getPassengers() != null && !entity.getPassengers().isEmpty() ? entity.getPassengers().get(0) - : null; + return !entity.getPassengers().isEmpty() ? entity.getPassengers().get(0) : null; } /** @@ -542,8 +531,8 @@ public final class WizardryUtilities { /** * Turns the given creeper into a charged creeper. In 1.10, this requires reflection since the DataManager keys are - * private. (You could call {@link EntityCreeper#onStruckByLightning(...)} and then heal it and extinguish - * it, but that's a bit awkward.) + * private. (You could call {@link EntityCreeper#onStruckByLightning(EntityLightningBolt)} and then heal it + * and extinguish it, but that's a bit awkward, and it'll trigger events and stuff...) */ // The reflection here only gets done once to initialise the POWERED field, so it's not a performance issue at all. public static void chargeCreeper(EntityCreeper creeper){ @@ -578,7 +567,7 @@ public final class WizardryUtilities { * Helper method which performs a ray trace for blocks and entities from an entity's eye position in the direction * they are looking, over a specified range, using {@link WizardryUtilities#rayTrace(World, Vec3d, Vec3d, float, * boolean, Class, Predicate)}. Aim assist is zero, the entity type is simply {@code Entity} (all entities), and the - * filter removes the given entity and allows all others. + * filter removes the given entity and any dying entities and allows all others. * * @param world The world in which to perform the ray trace. * @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye From 201f276c8b9ec0d0e75037a21efd9ed1955dc0de Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 22:19:22 +0000 Subject: [PATCH 49/68] More cleanup --- .../java/electroblob/wizardry/CommonProxy.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index 473f7eef..6347dea8 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -37,15 +37,11 @@ public class CommonProxy { // SECTION Registry // =============================================================================================================== - public void registerRenderers(){ - } + public void registerRenderers(){} - public void initialiseLayers(){ - } - - public void registerKeyBindings(){ - } + public void initialiseLayers(){} + public void registerKeyBindings(){} public net.minecraft.client.model.ModelBiped getWizardArmourModel(){ return null; @@ -123,10 +119,10 @@ public class CommonProxy { // SECTION Misc // =============================================================================================================== - public void setToNumberSliderEntry(Property property){ - } + public void setToNumberSliderEntry(Property property){} public void setToHUDChooserEntry(Property property){} + // public void setToEntityNameEntry(Property property){} /** From 09185e5f1c42683bf9931d621c6d78c5b293a8dc Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 22:28:57 +0000 Subject: [PATCH 50/68] Introduce DrawingUtils to centralise GUI rendering utility methods --- .../wizardry/client/DrawingUtils.java | 228 ++++++++++++++++++ .../client/gui/GuiArcaneWorkbench.java | 4 +- .../wizardry/client/gui/GuiSpellBook.java | 6 +- .../wizardry/client/gui/GuiSpellDisplay.java | 73 ++---- .../wizardry/util/WizardryUtilities.java | 78 ------ 5 files changed, 247 insertions(+), 142 deletions(-) create mode 100644 src/main/java/electroblob/wizardry/client/DrawingUtils.java diff --git a/src/main/java/electroblob/wizardry/client/DrawingUtils.java b/src/main/java/electroblob/wizardry/client/DrawingUtils.java new file mode 100644 index 00000000..382fba75 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/DrawingUtils.java @@ -0,0 +1,228 @@ +package electroblob.wizardry.client; + +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.RenderItem; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** + * Utility class containing some useful static methods for drawing GUIs. Previously these were spread across the main + * {@code WizardryUtilities} class and various individual GUI classes. + * + * @author Electroblob + * @since Wizardry 4.2 + * @see MixedFontRenderer + */ +@SideOnly(Side.CLIENT) +public final class DrawingUtils { + + /** + * The integer colour for black passed into the font renderer methods. This used to be 0 but that's now white for + * some reason, so I've made a it a constant in case it changes again. + */ + // I think this is actually ever-so-slightly lighter than pure black, but the difference is unnoticeable. + public static final int BLACK = 1; + + /** + * Shorthand for {@link DrawingUtils#drawTexturedRect(int, int, int, int, int, int, int, int)} which draws the + * entire texture (u and v are set to 0 and textureWidth and textureHeight are the same as width and height). + */ + public static void drawTexturedRect(int x, int y, int width, int height){ + drawTexturedRect(x, y, 0, 0, width, height, width, height); + } + + /** + * Draws a textured rectangle, taking the size of the image and the bit needed into + * account, unlike {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int) + * Gui.drawTexturedModalRect(int, int, int, int, int, int)}, which is harcoded for only 256x256 textures. Also handy + * for custom potion icons. + * + * @param x The x position of the rectangle + * @param y The y position of the rectangle + * @param u The x position of the top left corner of the section of the image wanted + * @param v The y position of the top left corner of the section of the image wanted + * @param width The width of the section + * @param height The height of the section + * @param textureWidth The width of the actual image. + * @param textureHeight The height of the actual image. + */ + public static void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight){ + DrawingUtils.drawTexturedFlippedRect(x, y, u, v, width, height, textureWidth, textureHeight, false, false); + } + + /** + * Draws a textured rectangle, taking the size of the image and the bit needed into + * account, unlike {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int) + * Gui.drawTexturedModalRect(int, int, int, int, int, int)}, which is harcoded for only 256x256 textures. Also handy + * for custom potion icons. This version allows the texture to additionally be flipped in x and/or y. + * + * @param x The x position of the rectangle + * @param y The y position of the rectangle + * @param u The x position of the top left corner of the section of the image wanted + * @param v The y position of the top left corner of the section of the image wanted + * @param width The width of the section + * @param height The height of the section + * @param textureWidth The width of the actual image. + * @param textureHeight The height of the actual image. + * @param flipX Whether to flip the texture in the x direction. + * @param flipY Whether to flip the texture in the y direction. + */ + public static void drawTexturedFlippedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, boolean flipX, boolean flipY){ + + float f = 1F / (float)textureWidth; + float f1 = 1F / (float)textureHeight; + + int u1 = flipX ? u + width : u; + int u2 = flipX ? u : u + width; + int v1 = flipY ? v + height : v; + int v2 = flipY ? v : v + height; + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + buffer.begin(org.lwjgl.opengl.GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); + + buffer.pos((double)(x), (double)(y + height), 0).tex((double)((float)(u1) * f), (double)((float)(v2) * f1)).endVertex(); + buffer.pos((double)(x + width), (double)(y + height), 0).tex((double)((float)(u2) * f), (double)((float)(v2) * f1)).endVertex(); + buffer.pos((double)(x + width), (double)(y), 0).tex((double)((float)(u2) * f), (double)((float)(v1) * f1)).endVertex(); + buffer.pos((double)(x), (double)(y), 0).tex((double)((float)(u1) * f), (double)((float)(v1) * f1)).endVertex(); + + tessellator.draw(); + } + + /** + * Draws a textured rectangle, stretching the section of the image to fit the size given. + * + * @param x The x position of the rectangle + * @param y The y position of the rectangle + * @param u The x position of the top left corner of the section of the image wanted, expressed as a fraction of the + * image width + * @param v The y position of the top left corner of the section of the image wanted, expressed as a fraction of the + * image width + * @param finalWidth The width as rendered + * @param finalHeight The height as rendered + * @param width The width of the section, expressed as a fraction of the image width + * @param height The height of the section, expressed as a fraction of the image width + */ + public static void drawTexturedStretchedRect(int x, int y, int u, int v, int finalWidth, int finalHeight, int width, + int height){ + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos((x), y + finalHeight, 0).tex(u, v + height).endVertex(); + buffer.pos(x + finalWidth, y + finalHeight, 0).tex(u + width, v + height).endVertex(); + buffer.pos(x + finalWidth, (y), 0).tex(u + width, v).endVertex(); + buffer.pos((x), (y), 0).tex(u, v).endVertex(); + + tessellator.draw(); + } + + /** + * Makes the given opaque colour translucent with the given opacity. + * @param colour An integer colour code, should be a 6-digit hexadecimal (i.e. opaque). + * @param opacity The opacity to apply to the given colour, as a fraction between 0 and 1. + * @return The resulting integer colour code, which will be an 8-digit hexadecimal. + */ + public static int makeTranslucent(int colour, float opacity){ + return colour + ((int)(0xff * opacity * 0x01000000)); + } + + /** + * Draws the given string at the given position, scaling it if it does not fit within the given width. + * @param font A {@code FontRenderer} object. + * @param text The text to display. + * @param x The x position of the top-left corner of the text. + * @param y The y position of the top-left corner of the text. + * @param scale The scale that the text should normally be if it does not exceed the maximum width. + * @param colour The colour to render the text in, supports translucency. + * @param width The maximum width of the text. This is not scaled; you should pass in the width of the actual + * area of the screen in which the text needs to fit, regardless of the scale parameter. + * @param centre Whether to adjust the y position such that the centre of the text lines up with where its centre + * would be if it was not scaled (automatically or manually). + * @param alignR True to right-align the text, false for normal left alignment. + */ + public static void drawScaledStringToWidth(FontRenderer font, String text, float x, float y, float scale, int colour, float width, boolean centre, boolean alignR){ + + float textWidth = font.getStringWidth(text) * scale; + float textHeight = font.FONT_HEIGHT * scale; + + if(textWidth > width){ + scale *= width/textWidth; + }else if(alignR){ // Alignment makes no difference if the string fills the entire width + x += width - textWidth; + } + + if(centre) y += (font.FONT_HEIGHT - textHeight)/2; + + DrawingUtils.drawScaledTranslucentString(font, text, x, y, scale, colour); + } + + /** Draws the given string at the given position, scaling the text by the specified factor. Also enables blending to + * render text in semitransparent colours (e.g. 0x88ffffff). */ + public static void drawScaledTranslucentString(FontRenderer font, String text, float x, float y, float scale, int colour){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.scale(scale, scale, scale); + // Because we scaled the entire rendering space, the coordinates have to be scaled inversely + x /= scale; + y /= scale; + font.drawStringWithShadow(text, x, y, colour); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + } + + /** + * Draws an itemstack and (optionally) its tooltip, directly. Mainly intended for use outside of GUI classes, since + * most of the GL state changes done in this method (which are the main reason it exists at all) are already done + * when drawing a GUI. + * + * @param gui An instance of a GUI class. + * @param stack The itemstack to draw. + * @param x The x position of the left-hand edge of the itemstack. + * @param y The y position of the top edge of the itemstack. + * @param mouseX The x position of the mouse, used for tooltip positioning. + * @param mouseY The y position of the mouse, used for tooltip positioning. + * @param tooltip Whether to draw the tooltip. + */ + public static void drawItemAndTooltip(GuiContainer gui, ItemStack stack, int x, int y, int mouseX, int mouseY, boolean tooltip){ + + RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); + GlStateManager.pushMatrix(); + RenderHelper.enableGUIStandardItemLighting(); + GlStateManager.disableLighting(); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableColorMaterial(); + GlStateManager.enableLighting(); + renderItem.zLevel = 100.0F; + + if(!stack.isEmpty()){ + renderItem.renderItemAndEffectIntoGUI(stack, x, y); + renderItem.renderItemOverlays(Minecraft.getMinecraft().fontRenderer, stack, x, y); + + if(tooltip){ + gui.drawHoveringText(gui.getItemToolTip(stack), mouseX + gui.getXSize()/2 - gui.width/2, + mouseY + gui.getYSize()/2 - gui.height/2); + } + } + + GlStateManager.popMatrix(); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + RenderHelper.enableStandardItemLighting(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java index a560abd5..349ffa36 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java @@ -84,7 +84,7 @@ public class GuiArcaneWorkbench extends GuiContainer { Minecraft.getMinecraft().renderEngine.bindTexture(texture); // Main inventory - drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSizeNoTip, ySize); + DrawingUtils.drawTexturedRect(guiLeft, guiTop, 0, 0, MAIN_GUI_WIDTH, ySize, TEXTURE_WIDTH, TEXTURE_HEIGHT); // Changing slots for(int i = 0; i < ContainerArcaneWorkbench.CRYSTAL_SLOT; i++){ @@ -122,7 +122,7 @@ public class GuiArcaneWorkbench extends GuiContainer { .bindTexture(discovered ? spell.element.getIcon() : Element.MAGIC.getIcon()); // Renders the little element icon - WizardryUtilities.drawTexturedRect(guiLeft + xSizeNoTip + 5, guiTop + 34 + 10 * i++, 8, 8); + DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + 5, guiTop + 34 + 10 * i++, 8, 8); } int x = 0; diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java index 2d78b219..fccc7c25 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java @@ -46,10 +46,10 @@ public class GuiSpellBook extends GuiScreen { // Draws spell illustration on opposite page, underneath the book so it shows through the hole. Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon()); - WizardryUtilities.drawTexturedRect(xPos + 145, yPos + 20, 0, 0, 128, 128, 128, 128); - Minecraft.getMinecraft().renderEngine.bindTexture(texture); - WizardryUtilities.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256); + DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128); + + DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256); super.drawScreen(par1, par2, par3); diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java index fff4d965..6d2a0c6d 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java @@ -19,6 +19,7 @@ import electroblob.wizardry.SpellGlyphData; import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.ClientProxy; +import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.client.MixedFontRenderer; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.item.ItemWand; @@ -27,7 +28,6 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.GlStateManager; @@ -219,51 +219,6 @@ public class GuiSpellDisplay { return name; } - /** - * Draws the given string at the given position, scaling it if it does not fit within the given width. - * @param font A {@code FontRenderer} object. - * @param text The text to display. - * @param x The x position of the top-left corner of the text. - * @param y The y position of the top-left corner of the text. - * @param scale The scale that the text should be if it does not exceed the maximum width. - * @param colour The colour to render the text in, supports translucency. - * @param width The maximum width of the text. This is not scaled; you should pass in the width of the actual - * area of the screen in which the text needs to fit. - * @param centre Whether to adjust the y position such that the centre of the text lines up with where its centre - * would be if it was not scaled (automatically or manually). - * @param alignR True to right-align the text, false for normal left alignment. - */ - private static void drawScaledStringToWidth(FontRenderer font, String text, float x, float y, float scale, int colour, float width, boolean centre, boolean alignR){ - - float textWidth = font.getStringWidth(text) * scale; - float textHeight = font.FONT_HEIGHT * scale; - - if(textWidth > width){ - scale *= width/textWidth; - }else if(alignR){ // Alignment makes no difference if the string fills the entire width - x += width - textWidth; - } - - if(centre) y += (font.FONT_HEIGHT - textHeight)/2; - - drawScaledTranslucentString(font, text, x, y, scale, colour); - } - - /** Draws the given string at the given position, scaling the text by the specified factor. Also enables blending to - * render text in semitransparent colours (e.g. 0x88ffffff). */ - private static void drawScaledTranslucentString(FontRenderer font, String text, float x, float y, float scale, int colour){ - - GlStateManager.pushMatrix(); - GlStateManager.enableBlend(); - GlStateManager.scale(scale, scale, scale); - // Because we scaled it, the coordinates have to be scaled inversely - x /= scale; - y /= scale; - font.drawStringWithShadow(text, x, y, colour); - GlStateManager.disableBlend(); - GlStateManager.popMatrix(); - } - @SubscribeEvent public static void onLivingUpdateEvent(LivingUpdateEvent event){ if(event.getEntity() == Minecraft.getMinecraft().player){ // Makes sure this only gets called once each tick. @@ -501,7 +456,7 @@ public class GuiSpellDisplay { // y is upside-down so this is the other way round int y1 = flipY && mirrorY ? y + spellIconInsetY : y - spellIconInsetY - SPELL_ICON_SIZE; - WizardryUtilities.drawTexturedRect(x1, y1, 0, 0, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE); + DrawingUtils.drawTexturedRect(x1, y1, 0, 0, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE); // Background of spell hud mc.renderEngine.bindTexture(texture); @@ -510,7 +465,7 @@ public class GuiSpellDisplay { y1 = flipY && mirrorY ? y : y - height; // The 128 here is a uv value, not a dimension, and hence is left as a hardcoded number. // TODO: Since the HUD is wider than it is tall, perhaps the creative mode texture should be in the bottom half instead of the right half? - WizardryUtilities.drawTexturedFlippedRect(x1, y1, creativeMode ? 128 : 0, 0, width, height, 256, 256, flipX && mirrorX, flipY && mirrorY); + DrawingUtils.drawTexturedFlippedRect(x1, y1, creativeMode ? 128 : 0, 0, width, height, 256, 256, flipX && mirrorX, flipY && mirrorY); // Cooldown bar if(!creativeMode && cooldownBarProgress > 0 && (showCooldownWhenFull || cooldownBarProgress < 1)){ @@ -523,7 +478,7 @@ public class GuiSpellDisplay { int u = cooldownBarX; // This doesn't change, even when cooldownBarMirrorX is true, because it should int v = height; // always start with the left-hand in the actual texture file - WizardryUtilities.drawTexturedFlippedRect(x1, y1, u, v, l, cooldownBarHeight, 256, 256, flipX && cooldownBarMirrorX, flipY && cooldownBarMirrorY); + DrawingUtils.drawTexturedFlippedRect(x1, y1, u, v, l, cooldownBarHeight, 256, 256, flipX && cooldownBarMirrorX, flipY && cooldownBarMirrorY); } GlStateManager.popMatrix(); @@ -574,11 +529,11 @@ public class GuiSpellDisplay { float yNext = y1 + cascadeOffsetY; // No need to account for flipY because next is always below. float maxWidthPrev = maxWidth + (flipY ? -1 : 1) * cascadeOffsetX; float maxWidthNext = maxWidth - (flipY ? -1 : 1) * cascadeOffsetX; - int nextPrevClr = makeTranslucent(0xffffff, SPELL_NAME_OPACITY); + int nextPrevClr = DrawingUtils.makeTranslucent(0xffffff, SPELL_NAME_OPACITY); - drawScaledStringToWidth(font, prevSpellName, xPrev, yPrev, SPELL_NAME_SCALE, nextPrevClr, maxWidthPrev, true, flipX && mirrorX); - drawScaledStringToWidth(font, spellName, x1, y1, 1, 0xffffffff, maxWidth, true, flipX && mirrorX); - drawScaledStringToWidth(font, nextSpellName, xNext, yNext, SPELL_NAME_SCALE, nextPrevClr, maxWidthNext, true, flipX && mirrorX); + DrawingUtils.drawScaledStringToWidth(font, prevSpellName, xPrev, yPrev, SPELL_NAME_SCALE, nextPrevClr, maxWidthPrev, true, flipX && mirrorX); + DrawingUtils.drawScaledStringToWidth(font, spellName, x1, y1, 1, 0xffffffff, maxWidth, true, flipX && mirrorX); + DrawingUtils.drawScaledStringToWidth(font, nextSpellName, xNext, yNext, SPELL_NAME_SCALE, nextPrevClr, maxWidthNext, true, flipX && mirrorX); }else{ // Switching spells @@ -593,20 +548,20 @@ public class GuiSpellDisplay { float maxWidthNext = maxWidth - (flipY ? -1 : 1) * cascadeOffsetX * (1 - animationProgress); float scalePrev = SPELL_NAME_SCALE + (1 - SPELL_NAME_SCALE) * (1 - animationProgress); float scaleNext = SPELL_NAME_SCALE + (1 - SPELL_NAME_SCALE) * (animationProgress); - int clrPrev = makeTranslucent(0xffffff, SPELL_NAME_OPACITY + (1 - SPELL_NAME_OPACITY) * (1 - animationProgress)); - int clrNext = makeTranslucent(0xffffff, SPELL_NAME_OPACITY + (1 - SPELL_NAME_OPACITY) * animationProgress); + int clrPrev = DrawingUtils.makeTranslucent(0xffffff, SPELL_NAME_OPACITY + (1 - SPELL_NAME_OPACITY) * (1 - animationProgress)); + int clrNext = DrawingUtils.makeTranslucent(0xffffff, SPELL_NAME_OPACITY + (1 - SPELL_NAME_OPACITY) * animationProgress); if(reverse){ // Switching to previous spell // Only renders the next spell and the current one - drawScaledStringToWidth(font, spellName, xPrev, yPrev, scalePrev, clrPrev, maxWidthPrev, true, flipX && mirrorX); - drawScaledStringToWidth(font, nextSpellName, xNext, yNext, scaleNext, clrNext, maxWidthNext, true, flipX && mirrorX); + DrawingUtils.drawScaledStringToWidth(font, spellName, xPrev, yPrev, scalePrev, clrPrev, maxWidthPrev, true, flipX && mirrorX); + DrawingUtils.drawScaledStringToWidth(font, nextSpellName, xNext, yNext, scaleNext, clrNext, maxWidthNext, true, flipX && mirrorX); }else{ // Switching to next spell // Only renders the previous spell and the current one - drawScaledStringToWidth(font, prevSpellName, xPrev, yPrev, scalePrev, clrPrev, maxWidthPrev, true, flipX && mirrorX); - drawScaledStringToWidth(font, spellName, xNext, yNext, scaleNext, clrNext, maxWidthNext, true, flipX && mirrorX); + DrawingUtils.drawScaledStringToWidth(font, prevSpellName, xPrev, yPrev, scalePrev, clrPrev, maxWidthPrev, true, flipX && mirrorX); + DrawingUtils.drawScaledStringToWidth(font, spellName, xNext, yNext, scaleNext, clrNext, maxWidthNext, true, flipX && mirrorX); } } diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index a00bfbc3..bcd9872c 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -27,7 +27,6 @@ import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.spell.MindControl; import electroblob.wizardry.spell.Spell; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -68,7 +67,6 @@ import net.minecraftforge.fml.relauncher.SideOnly; *

* - In-world utilities (position calculating, retrieving entities, etc.)
* - Raytracing
- * - Drawing utilities (client-only)
* - NBT and data storage utilities
* - Interaction with the ally designation system
* - Loot and weighting utilities @@ -684,82 +682,6 @@ public final class WizardryUtilities { return result; } - // SECTION Rendering and GUIs - // =============================================================================================================== - - // Doesn't seem right to put this in the proxies since it should only ever be called from client-side code, and I'm - // not about to make a whole separate utilities class just for one method. Fully qualified names it is! - /** - * [Client-side only] Draws a textured rectangle, taking the size of the image and the bit needed into - * account, unlike {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int) - * Gui.drawTexturedModalRect(int, int, int, int, int, int)}, which is harcoded for only 256x256 textures. Also handy - * for custom potion icons. - * - * @param x The x position of the rectangle - * @param y The y position of the rectangle - * @param u The x position of the top left corner of the section of the image wanted - * @param v The y position of the top left corner of the section of the image wanted - * @param width The width of the section - * @param height The height of the section - * @param textureWidth The width of the actual image. - * @param textureHeight The height of the actual image. - */ - @SideOnly(Side.CLIENT) - public static void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight){ - drawTexturedFlippedRect(x, y, u, v, width, height, textureWidth, textureHeight, false, false); - } - - /** - * [Client-side only] Draws a textured rectangle, taking the size of the image and the bit needed into - * account, unlike {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int) - * Gui.drawTexturedModalRect(int, int, int, int, int, int)}, which is harcoded for only 256x256 textures. Also handy - * for custom potion icons. This version allows the texture to be flipped in x and/or y. - * - * @param x The x position of the rectangle - * @param y The y position of the rectangle - * @param u The x position of the top left corner of the section of the image wanted - * @param v The y position of the top left corner of the section of the image wanted - * @param width The width of the section - * @param height The height of the section - * @param textureWidth The width of the actual image. - * @param textureHeight The height of the actual image. - * @param flipX Whether to flip the texture in the x direction. - * @param flipY Whether to flip the texture in the y direction. - */ - @SideOnly(Side.CLIENT) - public static void drawTexturedFlippedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, boolean flipX, boolean flipY){ - - float f = 1F / (float)textureWidth; - float f1 = 1F / (float)textureHeight; - - int u1 = flipX ? u + width : u; - int u2 = flipX ? u : u + width; - int v1 = flipY ? v + height : v; - int v2 = flipY ? v : v + height; - - // Essentially the same as getting the tessellator. For most code, you'll want the tessellator AND the - // vertexbuffer stored in local variables. - BufferBuilder buffer = net.minecraft.client.renderer.Tessellator.getInstance().getBuffer(); - // Equivalent of tessellator.startDrawingQuads() - buffer.begin(org.lwjgl.opengl.GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX); - // Equivalent of tessellator.addVertex() - buffer.pos((double)(x), (double)(y + height), 0).tex((double)((float)(u1) * f), (double)((float)(v2) * f1)).endVertex(); - buffer.pos((double)(x + width), (double)(y + height), 0).tex((double)((float)(u2) * f), (double)((float)(v2) * f1)).endVertex(); - buffer.pos((double)(x + width), (double)(y), 0).tex((double)((float)(u2) * f), (double)((float)(v1) * f1)).endVertex(); - buffer.pos((double)(x), (double)(y), 0).tex((double)((float)(u1) * f), (double)((float)(v1) * f1)).endVertex(); - // Exactly the same as before. - net.minecraft.client.renderer.Tessellator.getInstance().draw(); - } - - /** - * Shorthand for {@link WizardryUtilities#drawTexturedRect(int, int, int, int, int, int, int, int)} which draws the - * entire texture (u and v are set to 0 and textureWidth and textureHeight are the same as width and height). - */ - @SideOnly(Side.CLIENT) - public static void drawTexturedRect(int x, int y, int width, int height){ - drawTexturedRect(x, y, 0, 0, width, height, width, height); - } - // SECTION NBT and Data Storage // =============================================================================================================== From 78189ed862b1090a447120d987a9b01c514f5541 Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 22:30:06 +0000 Subject: [PATCH 51/68] Fix a few things in the HUD skin chooser screen --- .../wizardry/client/gui/GuiSelectHUDSkin.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java b/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java index 1da12067..92a1fbe8 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java @@ -6,10 +6,13 @@ import javax.annotation.Nullable; import com.google.common.collect.Lists; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.gui.GuiSpellDisplay.Skin; import electroblob.wizardry.registry.Spells; +import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; import net.minecraftforge.fml.client.config.GuiSelectString; import net.minecraftforge.fml.client.config.IConfigElement; @@ -22,8 +25,19 @@ public class GuiSelectHUDSkin extends GuiSelectString { @Override public void initGui(){ super.initGui(); + setEntryListDimensions(); + } + + @Override + protected void actionPerformed(GuiButton button){ + super.actionPerformed(button); + setEntryListDimensions(); // Stops the entry list from resizing when a button is pressed + } + + private void setEntryListDimensions(){ this.entryList.setDimensions(150, height, 43, height-43); this.entryList.left = 10; + this.entryList.maxEntryWidth = 120; this.entryList.headerPadding = 5; } @@ -36,7 +50,7 @@ public class GuiSelectHUDSkin extends GuiSelectString { if(this.currentValue instanceof String){ - this.drawString(this.fontRenderer, "Preview:", 170, 44, 0xffffff); + this.drawString(this.fontRenderer, I18n.format("config." + Wizardry.MODID + ":spell_hud_skin.preview"), 170, 44, 0xffffff); int previewLeft = 170; int previewRight = width-10; From 13569058ae2144869f6dd61f91a6ea766b295211 Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 22:38:06 +0000 Subject: [PATCH 52/68] Handbook rewrite part 1: Formatting and JSON-ification! - Everything is now defined in a JSON file - Formatting is now done dynamically and content wraps properly no matter what font is used - Added inline hyperlinks - Added a movable bookmark for quick access to a specific page - Added next section and previous section buttons to flip through entire sections at once - Added a contents button visible on every page, which navigates directly to the main contents --- .../wizardry/client/gui/GuiButtonApply.java | 42 -- .../client/gui/GuiButtonInvisible.java | 2 +- .../client/gui/GuiButtonTurnPage.java | 47 -- .../client/gui/GuiWizardHandbook.java | 695 ------------------ .../client/gui/handbook/Contents.java | 181 +++++ .../client/gui/handbook/CraftingRecipe.java | 225 ++++++ .../gui/handbook/GuiButtonHyperlink.java | 179 +++++ .../gui/handbook/GuiButtonTurnPage.java | 63 ++ .../gui/handbook/GuiWizardHandbook.java | 566 ++++++++++++++ .../wizardry/client/gui/handbook/Image.java | 119 +++ .../wizardry/client/gui/handbook/Section.java | 429 +++++++++++ .../ebwizardry/texts/handbook_en_gb.json | 528 +++++++++++++ .../ebwizardry/texts/handbook_en_us.json | 528 +++++++++++++ .../textures/gui/arcane_workbench_picture.png | Bin 0 -> 15386 bytes .../textures/gui/flower_picture.png | Bin 0 -> 86005 bytes .../textures/gui/handbook_recipes.png | Bin 26539 -> 0 bytes 16 files changed, 2819 insertions(+), 785 deletions(-) delete mode 100644 src/main/java/electroblob/wizardry/client/gui/GuiButtonApply.java delete mode 100644 src/main/java/electroblob/wizardry/client/gui/GuiButtonTurnPage.java delete mode 100644 src/main/java/electroblob/wizardry/client/gui/GuiWizardHandbook.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/handbook/Contents.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/handbook/CraftingRecipe.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonHyperlink.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonTurnPage.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/handbook/Image.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/handbook/Section.java create mode 100644 src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json create mode 100644 src/main/resources/assets/ebwizardry/texts/handbook_en_us.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/arcane_workbench_picture.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/flower_picture.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/gui/handbook_recipes.png diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiButtonApply.java b/src/main/java/electroblob/wizardry/client/gui/GuiButtonApply.java deleted file mode 100644 index a18d9668..00000000 --- a/src/main/java/electroblob/wizardry/client/gui/GuiButtonApply.java +++ /dev/null @@ -1,42 +0,0 @@ -package electroblob.wizardry.client.gui; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.resources.I18n; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -@SideOnly(Side.CLIENT) -class GuiButtonApply extends GuiButton { - - public GuiButtonApply(int id, int x, int y){ - super(id, x, y, 32, 16, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.apply")); - } - - @Override - public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){ - - // Whether the button is highlighted - this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; - - int k = 36; - int l = 220; - int colour = 14737632; - - if(this.enabled){ - if(this.hovered){ - k += this.width * 2; - colour = 16777120; - } - }else{ - k += this.width; - colour = 10526880; - } - - WizardryUtilities.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, 256, 256); - this.drawCenteredString(minecraft.fontRenderer, this.displayString, this.x + this.width / 2, - this.y + (this.height - 8) / 2, colour); - } -} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java b/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java index c80db3af..a65e71da 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java @@ -6,7 +6,7 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -class GuiButtonInvisible extends GuiButton { +public class GuiButtonInvisible extends GuiButton { public GuiButtonInvisible(int id, int x, int y, int width, int height){ super(id, x, y, width, height, ""); diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiButtonTurnPage.java b/src/main/java/electroblob/wizardry/client/gui/GuiButtonTurnPage.java deleted file mode 100644 index f9c7a8cd..00000000 --- a/src/main/java/electroblob/wizardry/client/gui/GuiButtonTurnPage.java +++ /dev/null @@ -1,47 +0,0 @@ -package electroblob.wizardry.client.gui; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -@SideOnly(Side.CLIENT) -class GuiButtonTurnPage extends GuiButton { - - /** True for pointing right (next page), false for pointing left (previous page). */ - private final boolean nextPage; - - private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png"); - - public GuiButtonTurnPage(int id, int x, int y, boolean isNextPage){ - super(id, x, y, 23, 13, ""); - this.nextPage = isNextPage; - } - - @Override - public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){ - - if(this.visible){ - - boolean flag = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; - GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); - minecraft.getTextureManager().bindTexture(texture); - int k = 0; - int l = 192; - - if(flag){ - k += 23; - } - - if(!this.nextPage){ - l += 13; - } - - WizardryUtilities.drawTexturedRect(this.x, this.y, k, l, 23, 13, 288, 256); - } - } -} diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiWizardHandbook.java b/src/main/java/electroblob/wizardry/client/gui/GuiWizardHandbook.java deleted file mode 100644 index b3e5d884..00000000 --- a/src/main/java/electroblob/wizardry/client/gui/GuiWizardHandbook.java +++ /dev/null @@ -1,695 +0,0 @@ -package electroblob.wizardry.client.gui; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.lwjgl.input.Keyboard; -import org.lwjgl.opengl.GL11; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.client.ClientProxy; -import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryBlocks; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; -import net.minecraft.item.ItemStack; -import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; - -public class GuiWizardHandbook extends GuiScreen { - - private int xSize, ySize; - private int pageNumber = 0; - - private static final int PAGE_WIDTH = 120; - /** - * The integer colour for black passed into the font renderer methods. This used to be 0 but that's now white for - * some reason, so I've made a it a constant in case it changes again. - */ - // I think this is actually ever-so-slightly lighter than pure black, but the difference is unnoticeable. - private static final int BLACK = 1; - - public static final ResourceLocation regularHandbook = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png"); - public static final ResourceLocation ore = new ResourceLocation(Wizardry.MODID, "textures/gui/ore_picture.png"); - public static final ResourceLocation crystal = new ResourceLocation(Wizardry.MODID, "textures/items/magic_crystal.png"); - public static final ResourceLocation workbenchGui = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png"); - public static final ResourceLocation craftingGrids = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook_recipes.png"); - - private List> text; - private List

sections; - - private static final List>>> RECIPES = new ArrayList<>(); - - private int guiPage, imagePage; - - public GuiWizardHandbook(){ - super(); - xSize = 288; - ySize = 180; - } - - @Override - public void drawScreen(int mouseX, int mouseY, float par3){ - - int xPos = this.width / 2 - xSize / 2; - int yPos = this.height / 2 - this.ySize / 2; - - // Tests for crafting recipes section - if(pageNumber >= (sections.get(sections.size() - 1).pageNumber - 1) / 2 - && pageNumber < (sections.get(sections.size() - 1).pageNumber - 1) / 2 + 4){ - Minecraft.getMinecraft().renderEngine.bindTexture(craftingGrids); - }else{ - Minecraft.getMinecraft().renderEngine.bindTexture(regularHandbook); - } - - WizardryUtilities.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256); - - // Arcane workbench gui picture - if(pageNumber == (this.guiPage - 1) / 2){ - Minecraft.getMinecraft().renderEngine.bindTexture(workbenchGui); - this.drawTexturedModalRect(this.guiPage % 2 == 1 ? xPos + 17 : this.width / 2 + 7, yPos + 14, 28, 12, 120, - 118); - } - - // Magic crystal and crystal ore images - if(pageNumber == (this.imagePage - 1) / 2){ - - Minecraft.getMinecraft().renderEngine.bindTexture(ore); - WizardryUtilities.drawTexturedRect(this.imagePage % 2 == 1 ? xPos + 17 : this.width / 2 + 7, yPos + 80, 0, - 0, 64, 64, 64, 64); - - Minecraft.getMinecraft().renderEngine.bindTexture(crystal); - drawTexturedStretchedRect(this.imagePage % 2 == 1 ? xPos + 17 + 64 : this.width / 2 + 7 + 62, yPos + 80, 0, - 0, 64, 64, 1, 1); - - } - - this.fontRenderer.drawString("" + (pageNumber * 2 + 1), xPos + xSize / 4 - 3, yPos + ySize - 20, 0); - this.fontRenderer.drawString("" + (pageNumber * 2 + 2), xPos + 3 * xSize / 4 - 5, yPos + ySize - 20, 0); - - super.drawScreen(mouseX, mouseY, par3); - - int lineNumber = 0; - - if(pageNumber == 1){ - for(Section s : sections){ - s.drawContents(); - } - }else{ - for(Section s : sections){ - s.hideButton(); - } - } - - for(String paragraph : text.get(pageNumber * 2)){ - - this.fontRenderer.drawSplitString(paragraph, xPos + 17, - yPos + 14 + lineNumber * this.fontRenderer.FONT_HEIGHT, PAGE_WIDTH, BLACK); - - List list = new ArrayList( - this.fontRenderer.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH)); - - lineNumber += list.size(); - } - - lineNumber = 0; - - // Prevents crash when the last page is blank (and hence is not in the list of pages) - if(text.size() > pageNumber * 2 + 1){ - for(String paragraph : text.get(pageNumber * 2 + 1)){ - - // First page is centred - if(pageNumber == 0){ - int startX = this.width / 2 + 7 + PAGE_WIDTH / 2 - - this.fontRenderer.getStringWidth(paragraph) / 2; - this.fontRenderer.drawSplitString(paragraph, startX, - yPos + 14 + lineNumber * this.fontRenderer.FONT_HEIGHT, PAGE_WIDTH, BLACK); - }else{ - this.fontRenderer.drawSplitString(paragraph, this.width / 2 + 7, - yPos + 14 + lineNumber * this.fontRenderer.FONT_HEIGHT, PAGE_WIDTH, BLACK); - } - - List list = new ArrayList( - this.fontRenderer.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH)); - - lineNumber += list.size(); - } - } - - // Which page of the recipes this is - int recipePage = pageNumber - (sections.get(sections.size() - 1).pageNumber - 1) / 2; - - if(recipePage >= 0 && recipePage < 4){ - // 4 recipes per page, hence the recipePage*4 - this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, RECIPES.get(recipePage*4).getRight(), RECIPES.get(recipePage*4).getLeft()); - this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, RECIPES.get(recipePage*4+1).getRight(), RECIPES.get(recipePage*4+1).getLeft()); - this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, RECIPES.get(recipePage*4+2).getRight(), RECIPES.get(recipePage*4+2).getLeft()); - this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, RECIPES.get(recipePage*4+3).getRight(), RECIPES.get(recipePage*4+3).getLeft()); - - // Tooltips are rendered after recipes to prevent tooltips on the left appearing behind items on the right. - this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, RECIPES.get(recipePage*4).getRight(), RECIPES.get(recipePage*4).getLeft()); - this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, RECIPES.get(recipePage*4+1).getRight(), RECIPES.get(recipePage*4+1).getLeft()); - this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, RECIPES.get(recipePage*4+2).getRight(), RECIPES.get(recipePage*4+2).getLeft()); - this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, RECIPES.get(recipePage*4+3).getRight(), RECIPES.get(recipePage*4+3).getLeft()); - } - - } - - // TODO: In 1.12, this all needs redoing nicely. With the crafting system halfway through changing in 1.11.2, this - // isn't worth doing until then. - - private void renderCraftingRecipe(int xPos, int yPos, int mouseX, int mouseY, NonNullList> craftingGrid, - ItemStack craftingResult){ - - GlStateManager.pushMatrix(); - RenderHelper.enableGUIStandardItemLighting(); - GlStateManager.disableLighting(); - GlStateManager.enableRescaleNormal(); - GlStateManager.enableColorMaterial(); - GlStateManager.enableLighting(); - itemRender.zLevel = 100.0F; - - for(int i = 0; i < craftingGrid.size(); i++){ - for(int j = 0; j < craftingGrid.get(i).size(); j++){ - ItemStack stack = craftingGrid.get(i).get(j); - if(!stack.isEmpty()){ - itemRender.renderItemAndEffectIntoGUI(stack, xPos + 18 * i, yPos + 18 * j); - itemRender.renderItemOverlays(this.fontRenderer, stack, xPos + 18 * i, - yPos + 18 * j); - } - } - } - - if(!craftingResult.isEmpty()){ - itemRender.renderItemAndEffectIntoGUI(craftingResult, xPos + 86, yPos + 18); - itemRender.renderItemOverlays(this.fontRenderer, craftingResult, xPos + 86, yPos + 18); - } - - GlStateManager.popMatrix(); - GlStateManager.enableLighting(); - GlStateManager.enableDepth(); - RenderHelper.enableStandardItemLighting(); - - } - - private void renderCraftingTooltips(int xPos, int yPos, int mouseX, int mouseY, NonNullList> craftingGrid, - ItemStack craftingResult){ - - int guiLeft = this.width / 2 - xSize / 2; - int guiTop = this.height / 2 - this.ySize / 2; - - GlStateManager.pushMatrix(); - RenderHelper.enableGUIStandardItemLighting(); - GlStateManager.disableLighting(); - GlStateManager.enableRescaleNormal(); - GlStateManager.enableColorMaterial(); - itemRender.zLevel = 0.0F; - GlStateManager.disableLighting(); - - for(int i = 0; i < craftingGrid.size(); i++){ - for(int j = 0; j < craftingGrid.get(i).size(); j++){ - ItemStack stack = craftingGrid.get(i).get(j); - if(!stack.isEmpty() - && isPointInRegion(xPos + 18 * i, yPos + 18 * j, 16, 16, mouseX + guiLeft, mouseY + guiTop)){ - this.renderToolTip(stack, mouseX, mouseY); - } - } - } - - if(!craftingResult.isEmpty() && isPointInRegion(xPos + 86, yPos + 18, 16, 16, mouseX + guiLeft, mouseY + guiTop)){ - this.renderToolTip(craftingResult, mouseX, mouseY); - } - - GlStateManager.popMatrix(); - GlStateManager.enableLighting(); - GlStateManager.enableDepth(); - RenderHelper.enableStandardItemLighting(); - - } - - @Override - public void initGui(){ - - super.initGui(); - Keyboard.enableRepeatEvents(true); - - int nextButtonId = 0; - - this.buttonList.clear(); - this.buttonList.add(new GuiButtonTurnPage(nextButtonId++, this.width / 2 + this.xSize / 2 - 22 - 23, - this.height / 2 + this.ySize / 2 - 10 - 13, true)); - this.buttonList.add(new GuiButtonTurnPage(nextButtonId++, this.width / 2 - this.xSize / 2 + 21, - this.height / 2 + this.ySize / 2 - 10 - 13, false)); - - text = new ArrayList>(1); - sections = new ArrayList
(1); - - BufferedReader bufferedreader = null; - - String textFilepath = Wizardry.MODID + ":texts/handbook_" - + Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".txt"; - - try{ - - bufferedreader = new BufferedReader(new InputStreamReader( - this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), - StandardCharsets.UTF_8)); - - }catch (IOException e){ - - Wizardry.logger.info( - "Wizard handbook text file missing for the current language. Using default (English - US) instead."); - - textFilepath = Wizardry.MODID + ":texts/handbook_en_us.txt"; - - try { - - bufferedreader = new BufferedReader(new InputStreamReader( - this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), - StandardCharsets.UTF_8)); - - } catch (IOException x){ - Wizardry.logger.error("Couldn't find file: " + Wizardry.MODID + "/assets/texts/handbook_en_us.txt. The file may be" - + "missing; please try re-downloading and reinstalling Wizardry.", x); - } - } - - if(bufferedreader != null){ - - try{ - - String paragraph = bufferedreader.readLine(); - ArrayList page = new ArrayList(1); - - int linesPerPage = 16; - - int lineNumber = 0; - - while(paragraph != null){ - - // System.out.println(paragraph); - - if(paragraph.contains("PAGEBREAK") || lineNumber >= linesPerPage){ - - text.add(page); - - page = new ArrayList(1); - - lineNumber = 0; - - if(paragraph.contains("PAGEBREAK")) paragraph = bufferedreader.readLine(); - - }else if(paragraph.contains("LINEBREAK")){ - - lineNumber++; - - page.add(""); - - paragraph = bufferedreader.readLine(); - - }else if(paragraph.contains("SECTION")){ - - sections.add( - new Section(paragraph.replace("SECTION ", ""), text.size() + 1, this.width / 2 + 7, - this.height / 2 - this.ySize / 2 + 14 - + (sections.size() + 2) * this.fontRenderer.FONT_HEIGHT, - nextButtonId++)); - paragraph = bufferedreader.readLine(); - - }else if(paragraph.contains("IMAGE")){ - - if(paragraph.contains("WORKBENCH")){ - this.guiPage = text.size() + 1; - }else if(paragraph.contains("CRYSTAL")){ - this.imagePage = text.size() + 1; - } - - paragraph = bufferedreader.readLine(); - - }else{ - - paragraph = paragraph.replaceAll("NEXT_SPELL_KEY", ClientProxy.NEXT_SPELL.getDisplayName()); - paragraph = paragraph.replaceAll("PREVIOUS_SPELL_KEY", ClientProxy.PREVIOUS_SPELL.getDisplayName()); - paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL_MINUS_30", "" + (Constants.MANA_PER_CRYSTAL - 30)); - paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL", "" + Constants.MANA_PER_CRYSTAL); - paragraph = paragraph.replaceAll("BASIC_MAX_CHARGE", "" + Tier.BASIC.maxCharge); - paragraph = paragraph.replaceAll("APPRENTICE_MAX_CHARGE", "" + Tier.APPRENTICE.maxCharge); - paragraph = paragraph.replaceAll("ADVANCED_MAX_CHARGE", "" + Tier.ADVANCED.maxCharge); - paragraph = paragraph.replaceAll("MASTER_MAX_CHARGE", "" + Tier.MASTER.maxCharge); - paragraph = paragraph.replaceAll("BASIC_COLOUR", "\u00A77"); - paragraph = paragraph.replaceAll("APPRENTICE_COLOUR", Tier.APPRENTICE.getFormattingCode()); - paragraph = paragraph.replaceAll("ADVANCED_COLOUR", Tier.ADVANCED.getFormattingCode()); - paragraph = paragraph.replaceAll("MASTER_COLOUR", Tier.MASTER.getFormattingCode()); - paragraph = paragraph.replaceAll("FIRE_COLOUR", Element.FIRE.getFormattingCode()); - paragraph = paragraph.replaceAll("ICE_COLOUR", Element.ICE.getFormattingCode()); - paragraph = paragraph.replaceAll("LIGHTNING_COLOUR", Element.LIGHTNING.getFormattingCode()); - paragraph = paragraph.replaceAll("NECROMANCY_COLOUR", Element.NECROMANCY.getFormattingCode()); - paragraph = paragraph.replaceAll("EARTH_COLOUR", Element.EARTH.getFormattingCode()); - paragraph = paragraph.replaceAll("SORCERY_COLOUR", Element.SORCERY.getFormattingCode()); - paragraph = paragraph.replaceAll("HEALING_COLOUR", Element.HEALING.getFormattingCode()); - paragraph = paragraph.replaceAll("RESET_COLOUR", "\u00A70"); - paragraph = paragraph.replaceAll("MCVERSION", "1.12.2"); - paragraph = paragraph.replaceAll("VERSION", Wizardry.VERSION); - - int linesInParagraph = this.fontRenderer - .listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH).size(); - - // Ignores empty lines at the top of a page. - if(paragraph.isEmpty() && lineNumber == 0){ - - paragraph = bufferedreader.readLine(); - - // Normal paragraph, all on one page - }else if(lineNumber + linesInParagraph <= linesPerPage){ - - page.add(paragraph); - - lineNumber += linesInParagraph; - - paragraph = bufferedreader.readLine(); - - // Paragraphs split across two pages (or more?) - }else{ - - int linesInFirstPart = linesPerPage - lineNumber; - - String paragraphFirstPart = ""; - String paragraphLastPart = ""; - - int i = 0; - - List strings = this.fontRenderer.listFormattedStringToWidth(paragraph, - GuiWizardHandbook.PAGE_WIDTH); - - for(Object s : strings){ - if(i < linesInFirstPart){ - paragraphFirstPart = paragraphFirstPart.concat((String)s + " "); - }else{ - paragraphLastPart = paragraphLastPart.concat((String)s + " "); - } - i++; - } - - // System.out.println("Paragraph crosses page boundary; string split into: \"" + - // paragraphFirstPart + "\" and \"" + paragraphLastPart + "\""); - - page.add(paragraphFirstPart); - - lineNumber += linesInFirstPart; - - paragraph = paragraphLastPart; - } - } - } - - text.add(page); - - }catch (IOException e){ - Wizardry.logger.error("Something went wrong reading file: " + textFilepath - + ". The file may be damaged; please try re-downloading and reinstalling wizardry.", e); - } - } - } - - private class Section { - - /** The integer text colour used for the section when it is moused over. Currently orange. */ - private static final int HIGHLIGHT_COLOUR = 0xdd4c1d; - - String name; - int pageNumber; - int x, y; - int buttonId; - - Section(String name, int pageNumber, int x, int y, int id){ - this.name = name; - this.pageNumber = pageNumber; - this.x = x; - this.y = y; - this.buttonId = id; - GuiWizardHandbook.this.buttonList.add(new GuiButtonInvisible(id, x, y, GuiWizardHandbook.PAGE_WIDTH, - GuiWizardHandbook.this.fontRenderer.FONT_HEIGHT)); - } - - void hideButton(){ - GuiWizardHandbook.this.buttonList.get(buttonId).visible = false; - } - - void drawContents(){ - - GuiWizardHandbook.this.buttonList.get(buttonId).visible = true; - - GuiWizardHandbook.this.fontRenderer.drawString(name, x, y, - GuiWizardHandbook.this.buttonList.get(buttonId).isMouseOver() ? HIGHLIGHT_COLOUR : BLACK); - - int nameWidth = GuiWizardHandbook.this.fontRenderer.getStringWidth(name); - - String dotsAndNumber = " " + this.pageNumber; - - while(GuiWizardHandbook.this.fontRenderer.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - - nameWidth - 2){ - dotsAndNumber = "." + dotsAndNumber; - } - - GuiWizardHandbook.this.fontRenderer.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - - GuiWizardHandbook.this.fontRenderer.getStringWidth(dotsAndNumber), y, BLACK); - } - } - - @Override - public void onGuiClosed(){ - super.onGuiClosed(); - Keyboard.enableRepeatEvents(false); - } - - /** - * Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e). - */ - @Override - protected void actionPerformed(GuiButton par1GuiButton){ - - if(par1GuiButton.enabled){ - if(par1GuiButton.id == 0){ - if(pageNumber < (text.size() - 1) / 2) pageNumber++; - }else if(par1GuiButton.id == 1){ - if(pageNumber > 0) pageNumber--; - }else{ - if(pageNumber == 1) pageNumber = (sections.get(par1GuiButton.id - 2).pageNumber - 1) / 2; - } - } - } - - /** - * Args: left, top, width, height, pointX, pointY. Note: left, top are local to Gui, pointX, pointY are local to - * screen - */ - protected boolean isPointInRegion(int par1, int par2, int par3, int par4, int par5, int par6){ - int k1 = this.width / 2 - xSize / 2; - int l1 = this.height / 2 - this.ySize / 2; - par5 -= k1; - par6 -= l1; - return par5 >= par1 - 1 && par5 < par1 + par3 + 1 && par6 >= par2 - 1 && par6 < par2 + par4 + 1; - } - - /** - * Draws a textured rectangle, stretching the section of the image to fit the size given. - * - * @param x The x position of the rectangle - * @param y The y position of the rectangle - * @param u The x position of the top left corner of the section of the image wanted, expressed as a fraction of the - * image width - * @param v The y position of the top left corner of the section of the image wanted, expressed as a fraction of the - * image width - * @param finalWidth The width as rendered - * @param finalHeight The height as rendered - * @param width The width of the section, expressed as a fraction of the image width - * @param height The height of the section, expressed as a fraction of the image width - */ - public static void drawTexturedStretchedRect(int x, int y, int u, int v, int finalWidth, int finalHeight, int width, - int height){ - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - buffer.pos((x), y + finalHeight, 0).tex(u, v + height).endVertex(); - buffer.pos(x + finalWidth, y + finalHeight, 0).tex(u + width, v + height).endVertex(); - buffer.pos(x + finalWidth, (y), 0).tex(u + width, v).endVertex(); - buffer.pos((x), (y), 0).tex(u, v).endVertex(); - tessellator.draw(); - } - - private static NonNullList> createGrid(){ - NonNullList> grid = NonNullList.withSize(3, NonNullList.create()); - for(int i=0; i<3; i++){ - grid.set(i, NonNullList.withSize(3, ItemStack.EMPTY)); - } - return grid; - } - - /** Called from init() in the main mod class to initialise the recipes for display in the handbook. */ - public static void initDisplayRecipes(){ - - NonNullList> craftingGrid; - ItemStack craftingResult; - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(Items.GOLD_NUGGET)); - craftingGrid.get(1).set(0, new ItemStack(Blocks.CARPET, 1, 10)); - craftingGrid.get(2).set(0, new ItemStack(Items.GOLD_NUGGET)); - craftingGrid.get(0).set(1, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(1).set(1, new ItemStack(Blocks.LAPIS_BLOCK)); - craftingGrid.get(2).set(1, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(0).set(2, new ItemStack(Blocks.STONE)); - craftingGrid.get(1).set(2, new ItemStack(Blocks.STONE)); - craftingGrid.get(2).set(2, new ItemStack(Blocks.STONE)); - craftingResult = new ItemStack(WizardryBlocks.arcane_workbench); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(2).set(0, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(1).set(1, new ItemStack(Items.STICK)); - craftingGrid.get(0).set(2, new ItemStack(Items.GOLD_NUGGET)); - craftingResult = new ItemStack(WizardryItems.magic_wand); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(1).set(0, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(0).set(1, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(1).set(1, new ItemStack(Items.BOOK)); - craftingGrid.get(1).set(2, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(2).set(1, new ItemStack(WizardryItems.magic_crystal)); - craftingResult = new ItemStack(WizardryItems.spell_book, 1, 1); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(Items.BOOK)); - craftingGrid.get(1).set(0, new ItemStack(WizardryItems.magic_crystal)); - craftingResult = new ItemStack(WizardryItems.wizard_handbook); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(WizardryBlocks.crystal_flower)); - craftingResult = new ItemStack(WizardryItems.magic_crystal, 2); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(1).set(0, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(2).set(0, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(0).set(1, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(1).set(1, new ItemStack(Items.GLASS_BOTTLE)); - craftingGrid.get(2).set(1, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(0).set(2, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(1).set(2, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(2).set(2, new ItemStack(WizardryItems.magic_crystal)); - craftingResult = new ItemStack(WizardryItems.mana_flask); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(1).set(0, new ItemStack(Blocks.STONE)); - craftingGrid.get(0).set(1, new ItemStack(Blocks.STONE)); - craftingGrid.get(1).set(1, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(1).set(2, new ItemStack(Blocks.STONE)); - craftingGrid.get(2).set(1, new ItemStack(Blocks.STONE)); - craftingResult = new ItemStack(WizardryBlocks.transportation_stone, 2); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(1).set(0, new ItemStack(Items.STRING)); - craftingGrid.get(0).set(1, new ItemStack(Items.STRING)); - craftingGrid.get(1).set(1, new ItemStack(WizardryItems.magic_crystal)); - craftingGrid.get(1).set(2, new ItemStack(Items.STRING)); - craftingGrid.get(2).set(1, new ItemStack(Items.STRING)); - craftingResult = new ItemStack(WizardryItems.magic_silk, 2); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(1).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(0).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingResult = new ItemStack(WizardryItems.wizard_hat); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(0).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(1).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(0).set(2, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(1).set(2, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(2, new ItemStack(WizardryItems.magic_silk)); - craftingResult = new ItemStack(WizardryItems.wizard_robe); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(1).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(0).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(0).set(2, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(2, new ItemStack(WizardryItems.magic_silk)); - craftingResult = new ItemStack(WizardryItems.wizard_leggings); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(0, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(0).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingGrid.get(2).set(1, new ItemStack(WizardryItems.magic_silk)); - craftingResult = new ItemStack(WizardryItems.wizard_boots); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(Items.PAPER)); - craftingGrid.get(1).set(0, new ItemStack(Items.STRING)); - craftingResult = new ItemStack(WizardryItems.blank_scroll); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(Items.BLAZE_POWDER)); - craftingGrid.get(1).set(0, new ItemStack(Items.BLAZE_POWDER)); - craftingGrid.get(0).set(1, new ItemStack(Items.GLASS_BOTTLE)); - craftingGrid.get(1).set(1, new ItemStack(Items.GUNPOWDER)); - craftingResult = new ItemStack(WizardryItems.firebomb, 3); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(Items.SPIDER_EYE)); - craftingGrid.get(1).set(0, new ItemStack(Items.SPIDER_EYE)); - craftingGrid.get(0).set(1, new ItemStack(Items.GLASS_BOTTLE)); - craftingGrid.get(1).set(1, new ItemStack(Items.GUNPOWDER)); - craftingResult = new ItemStack(WizardryItems.poison_bomb, 3); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - - craftingGrid = createGrid(); - craftingGrid.get(0).set(0, new ItemStack(Items.COAL)); - craftingGrid.get(1).set(0, new ItemStack(Items.COAL)); - craftingGrid.get(0).set(1, new ItemStack(Items.GLASS_BOTTLE)); - craftingGrid.get(1).set(1, new ItemStack(Items.GUNPOWDER)); - craftingResult = new ItemStack(WizardryItems.smoke_bomb, 3); - RECIPES.add(ImmutablePair.of(craftingResult, craftingGrid)); - } - -} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/Contents.java b/src/main/java/electroblob/wizardry/client/gui/handbook/Contents.java new file mode 100644 index 00000000..2ef67821 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/Contents.java @@ -0,0 +1,181 @@ +package electroblob.wizardry.client.gui.handbook; + +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.client.DrawingUtils; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.JsonUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Instances of this class represent tables of contents in the wizard's handbook. Each {@link Section} can have a + * single table of contents, which can reference any other sections in the handbook (though it is normal to list + * top-level sections in a main contents and have subsections listed in their respective parent sections' contents). + * + * This class handles JSON parsing, formatting and drawing of the contents itself, working on a line-by-line basis + * (as opposed to sections, which work on a page-by-page basis). It also stores its own list of buttons. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +class Contents { + + // Final fields are mandatory, the rest are optional + final String id; + private boolean hyperlinks = true; + private boolean pageNumbers = true; + private String separator = "."; + // Derived fields, not specifically defined in JSON + private int startPage; + private int startLine; + private final List> buttons; + + private final List
entries; + + private Contents(String id){ + this.id = id; + this.entries = new ArrayList<>(); + this.buttons = new ArrayList<>(); + } + + /** Returns an unmodifiable, flattened collection of all the buttons in this contents. */ + Collection getButtons(){ + return WizardryUtilities.flatten(buttons); + } + + void addEntry(Section section){ + entries.add(section); + } + + /** + * Draws this contents for the given double-page spread and shows/hides buttons accordingly. Will draw nothing + * if the given page is outside of this contents. + * + * @param font The font renderer object. + * @param doublePage The index of the double-page to be drawn. + * @param left The x coordinate of the left side of the GUI. + * @param top The y coordinate of the top of the GUI. + */ + void draw(FontRenderer font, int doublePage, int left, int top){ + + // Show/hide buttons + + int i = 0; + + for(List list : buttons){ + final int i1 = i++; + list.forEach(b -> b.visible = GuiWizardHandbook.singleToDoublePage(startPage + i1) == doublePage); + } + + if(!pageNumbers) return; // No page numbers means only the buttons are drawn + + // FONT_HEIGHT may change between fonts, so this is calculated here. With the default font it's 14. + final int maxLineNumber = GuiWizardHandbook.PAGE_HEIGHT / font.FONT_HEIGHT; + + int leftIndex = GuiWizardHandbook.doubleToSinglePage(doublePage, false); + // Relative indices of the pages to be rendered - often these will be outside the section entirely + int[] visiblePages = {leftIndex - startPage, leftIndex - startPage + 1}; + + for(int page : visiblePages){ + + if(page >= 0 && page < entries.size() / maxLineNumber + 1){ + + int x = left + (GuiWizardHandbook.isRightPage(startPage + page) ? GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : GuiWizardHandbook.TEXT_INSET_X); + int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT; + + for(Section entry : this.entries){ + + int nameWidth = font.getStringWidth(entry.title); + + String dotsAndNumber = " " + entry.startPage; + + while(font.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - nameWidth - 2){ + dotsAndNumber = separator + dotsAndNumber; + } + + font.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - font.getStringWidth(dotsAndNumber), y, DrawingUtils.BLACK, false); + + if(!hyperlinks) font.drawString(entry.title, x, y, DrawingUtils.BLACK, false); + + y += font.FONT_HEIGHT; + } + } + } + } + + /** + * Called on GUI load to format the section and all subsections, contents tables and other elements. Does not + * perform any actual drawing. + * + * @param font The font renderer object, for measurement purposes. + * @param startPage The index of the first page (single side, not double-page) of this section. + * @param startLine The index of the first line of this contents. + * @param left The x coordinate of the left side of the GUI. + * @param top The y coordinate of the top of the GUI. + * @return The number of lines this contents takes up. + * @throws JsonSyntaxException if at any point the formatting is found to be invalid. + */ + int format(FontRenderer font, int startPage, int startLine, int left, int top){ + + this.buttons.clear(); + + if(hyperlinks){ + + // FONT_HEIGHT may change between fonts, so this is calculated here. With the default font it's 14. + final int maxLineNumber = GuiWizardHandbook.PAGE_HEIGHT / font.FONT_HEIGHT; + + this.startPage = startPage; + this.startLine = startLine; + + List list = new ArrayList<>(maxLineNumber); + + for(Section entry : this.entries){ + + int x = GuiWizardHandbook.isRightPage(startPage) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X; + int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT; + + list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, "")); + + startLine++; + + if(startLine == maxLineNumber){ + startLine = 0; + startPage++; + buttons.add(list); + list = new ArrayList<>(maxLineNumber); // If there are no more entries this will be discarded anyway + } + } + + buttons.add(list); + } + + // Returning this is kind of trivial at the moment but if we ever wanted to add a header or something, + // it would be more useful. + return entries.size(); + } + + /** + * Parses the given JSON object and constructs a new {@code Contents} from it, setting all the relevant fields + * and references. + * + * @param json A JSON object representing the contents to be constructed. This must contain at least an "id" + * string. + * @return The resulting {@code Contents} object. + * @throws JsonSyntaxException if at any point the JSON object is found to be invalid. + */ + static Contents fromJson(JsonObject json){ + + Contents contents = new Contents(JsonUtils.getString(json, "id")); + + contents.hyperlinks = JsonUtils.getBoolean(json, "hyperlinks", true); + contents.pageNumbers = JsonUtils.getBoolean(json, "page_numbers", true); + contents.separator = JsonUtils.getString(json, "separator", "."); + + return contents; + } +} diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/CraftingRecipe.java b/src/main/java/electroblob/wizardry/client/gui/handbook/CraftingRecipe.java new file mode 100644 index 00000000..ecaf5105 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/CraftingRecipe.java @@ -0,0 +1,225 @@ +package electroblob.wizardry.client.gui.handbook; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.client.DrawingUtils; +import electroblob.wizardry.spell.Mine; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.recipebook.GuiRecipeBook; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.RenderItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.stats.RecipeBook; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +class CraftingRecipe { + + static final int WIDTH = 111, HEIGHT = 56; + + // Final fields are mandatory, the rest are optional + private final ResourceLocation location; + // Derived fields, not specifically defined in JSON + private IRecipe recipe; + private final Set instances = new HashSet<>(); + + private CraftingRecipe(ResourceLocation location){ + this.location = location; + } + + /** + * Adds an instance of this recipe to the list. + * + * @param page The index of the single page this image is on. + * @param x The x-coordinate of the top-left corner of the image, relative to the top-left corner of the GUI. + * @param y The y-coordinate of the top-left corner of the image, relative to the top-left corner of the GUI. + */ + void addInstance(int page, int x, int y){ + instances.add(new int[]{page, x, y}); + } + + /** Removes all instances of this recipe from the list. */ + void clearInstances(){ + instances.clear(); + } + + /** Called on GUI open to load the actual recipe object from the registry. This cannot be done on JSON load since + * the recipes aren't necessarily loaded at that point. */ + void load(){ + + this.recipe = CraftingManager.getRecipe(location); + + if(recipe == null) throw new JsonSyntaxException("No such recipe: " + location); + } + + /** + * Draws all instances of this recipe that are located on the given double-page spread. + * + * @param font The font renderer object. + * @param itemRenderer The item renderer object. + * @param doublePage The double-page index of the page to be drawn. + * @param left The x coordinate of the left side of the GUI. + * @param top The y coordinate of the top of the GUI. + */ + void draw(FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top){ + for(int[] instance : instances){ + if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){ + renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], this.recipe); + } + } + } + + /** + * Draws the tooltips for all instances of this recipe that are located on the given double-page spread. This has to + * be done separately so that the tooltips are on top of everything else. + * + * @param itemRenderer The item renderer object. + * @param doublePage The double-page index of the page to be drawn. + * @param left The x coordinate of the left side of the GUI. + * @param top The y coordinate of the top of the GUI. + */ + void drawTooltips(GuiWizardHandbook gui, FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top, int mouseX, int mouseY){ + for(int[] instance : instances){ + if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){ + renderCraftingTooltips(gui, itemRenderer, left + instance[1], top + instance[2], mouseX, mouseY, this.recipe); + } + } + } + + /** + * Parses the given JSON object and constructs a new {@code Image} from it, setting all the relevant fields + * and references. + * + * @param json A JSON object representing the image to be constructed. This must contain at least a "location" + * string. + * @return The resulting {@code Image} object. + * @throws JsonSyntaxException if at any point the JSON object is found to be invalid. + */ + static CraftingRecipe fromJson(JsonObject json){ + + ResourceLocation location = new ResourceLocation(JsonUtils.getString(json, "location")); + return new CraftingRecipe(location); + } + + static void populate(Map map, JsonObject json){ + + JsonObject sectionsObject = JsonUtils.getJsonObject(json, "recipes"); + + // Need to iterate over these since we don't know what they're called or how many there are + for(Map.Entry entry : sectionsObject.entrySet()){ + + String key = entry.getKey(); // Find out what each element is called, this will be the sections map key + + CraftingRecipe recipe = fromJson(entry.getValue().getAsJsonObject()); + map.put(key, recipe); + } + } + + private static void renderCraftingRecipe(FontRenderer font, RenderItem itemRenderer, int x, int y, IRecipe recipe){ + + ItemStack result = recipe.getRecipeOutput(); + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture); + + DrawingUtils.drawTexturedRect(x - 2, y - 2, 60, 190, WIDTH, HEIGHT, 512, 256); + + GlStateManager.pushMatrix(); + RenderHelper.enableGUIStandardItemLighting(); + GlStateManager.disableLighting(); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableColorMaterial(); + GlStateManager.enableLighting(); + itemRenderer.zLevel = 100.0F; + + // TODO: There may be a better way of doing this + int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000; + + int i = 0; + + for(Ingredient ingredient : recipe.getIngredients()){ + + if(ingredient != Ingredient.EMPTY){ + ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length]; + if(!stack.isEmpty()){ + itemRenderer.renderItemAndEffectIntoGUI(stack, x + 18 * (i%3), y + 18 * (i/3)); + itemRenderer.renderItemOverlays(font, stack, x + 18 * (i%3), y + 18 * (i/3)); + } + } + + i++; + } + + if(!result.isEmpty()){ + itemRenderer.renderItemAndEffectIntoGUI(result, x + 86, y + 18); + itemRenderer.renderItemOverlays(font, result, x + 86, y + 18); + } + + GlStateManager.popMatrix(); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + GlStateManager.disableColorMaterial(); + itemRenderer.zLevel = 0.0F; + //RenderHelper.enableStandardItemLighting(); + + } + + private static void renderCraftingTooltips(GuiWizardHandbook gui, RenderItem itemRenderer, int x, int y, int mouseX, int mouseY, IRecipe recipe){ + + ItemStack result = recipe.getRecipeOutput(); + + GlStateManager.pushMatrix(); + RenderHelper.enableGUIStandardItemLighting(); + GlStateManager.disableLighting(); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableColorMaterial(); + itemRenderer.zLevel = 0.0F; + GlStateManager.disableLighting(); + + // TODO: There may be a better way of doing this + int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000; + + int i = 0; + + for(Ingredient ingredient : recipe.getIngredients()){ + + if(ingredient != Ingredient.EMPTY){ + ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length]; + if(!stack.isEmpty() && isPointInRegion(x + 18 * (i%3), y + 18 * (i/3), 16, 16, mouseX, mouseY)){ + gui.renderToolTip(stack, mouseX, mouseY); + } + } + + i++; + } + + if(!result.isEmpty() && isPointInRegion(x + 86, y + 18, 16, 16, mouseX, mouseY)){ + gui.renderToolTip(result, mouseX, mouseY); + } + + GlStateManager.popMatrix(); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + GlStateManager.disableColorMaterial(); + RenderHelper.enableStandardItemLighting(); + + } + + private static boolean isPointInRegion(int left, int top, int width, int height, int mouseX, int mouseY){ + return mouseX >= left - 1 && mouseX < left + width + 1 && mouseY >= top - 1 && mouseY < top + height + 1; + } + +} diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonHyperlink.java b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonHyperlink.java new file mode 100644 index 00000000..7aaa5bf4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonHyperlink.java @@ -0,0 +1,179 @@ +package electroblob.wizardry.client.gui.handbook; + +import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.registry.WizardrySounds; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.audio.SoundHandler; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.event.ClickEvent; + +import java.util.ArrayList; +import java.util.List; + +public abstract class GuiButtonHyperlink extends GuiButton { + + public static final String URL_REGEX = "^((https?|ftp)://|(www|ftp)\\.)?[a-z0-9-]+(\\.[a-z0-9-]+)+([/?].*)?$"; + + final int indent; + final List lines; + + GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix){ + + super(id, x, y, font.getStringWidth(text), font.FONT_HEIGHT, text); + + // Sometimes a link has punctuation or something after it that causes it to wrap onto a new line + String linkWithSuffix = text + suffix; + + // If the string won't fit any words at the end of the current line, treat it as if we started a new line + if(font.getStringWidth(linkWithSuffix.split("\\s")[0]) > GuiWizardHandbook.PAGE_WIDTH - indent){ + indent = 0; + this.y += font.FONT_HEIGHT; + } + + this.indent = indent; // Assigned here in case it was corrected above + + String line1 = font.listFormattedStringToWidth(linkWithSuffix, GuiWizardHandbook.PAGE_WIDTH - indent).get(0); + // Without trim(), there will be at least 1 leading space due to the custom wrapping + String remainder = linkWithSuffix.substring(line1.length()).trim(); + + // ... then wrap the rest to the normal width. + lines = new ArrayList<>(); + lines.add(line1); + // Some links are only one line, if this wasn't checked they would cause a StackOverflowError + if(!remainder.isEmpty()) lines.addAll(font.listFormattedStringToWidth(remainder, GuiWizardHandbook.PAGE_WIDTH)); + + // Removes the suffix if it exists (ugly as heck, but it works) + if(!suffix.isEmpty()){ + for(int i=lines.size()-1; i>=0; i--){ + String line = lines.get(i); + if(suffix.endsWith(line)){ + lines.remove(i); + }else if(line.endsWith(suffix)){ + lines.set(i, line.substring(0, line.length() - suffix.length())); + break; + } + } + } + } + + public boolean isHovered(net.minecraft.client.gui.FontRenderer font, int mouseX, int mouseY){ + + int i = 0; + + for(String line : lines){ + + int l = x; + if(i == 0) l += indent; + + int t = y + font.FONT_HEIGHT * i; + + if(mouseX >= l && mouseY >= t && mouseX < l + font.getStringWidth(line) && mouseY < t + font.FONT_HEIGHT){ + return true; + } + + i++; + } + + return false; + } + + @Override + public boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY){ + return this.enabled && this.visible && isHovered(minecraft.fontRenderer, mouseX, mouseY); + } + + @Override + public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){ + + if(this.visible){ + + this.hovered = isHovered(minecraft.fontRenderer, mouseX, mouseY); + int colour = hovered ? GuiWizardHandbook.colours.get("highlight") : GuiWizardHandbook.colours.get("hyperlink"); + + int i = 0; + + for(String line : lines){ + + int l = x; + if(i == 0) l += indent; + + int t = y + minecraft.fontRenderer.FONT_HEIGHT * i; + + minecraft.fontRenderer.drawString(line, l, t, colour); + + i++; + } + } + } + + /** + * Creates a new hyperlink button from the given arguments, automatically differentiating between URLs and sections. + * @param x The x position of the button + * @param y The y position of the button + * @param font A reference to the FontRenderer object + * @param upToLink The paragraph (as a list of lines) up to the link, used to determine positioning and word wrap + * @param arguments The link arguments - that is, everything between the two @ signs, split by spaces + * @param suffix The text directly after the link, up to the first whitespace; used for word wrap. Usually this is + * either empty or contains a single punctuation mark. + * @return The resulting button + * @throws IllegalArgumentException if the given argument array is empty or contains more than 2 arguments + * @throws JsonSyntaxException if the specified link target is not a URL or a valid section ID + */ + public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List upToLink, String[] arguments, String suffix){ + + if(arguments.length == 0 || arguments.length > 2) throw new IllegalArgumentException("Incorrect array length!"); + + GuiButtonHyperlink button; + + if(arguments[0].matches(URL_REGEX)){ + + button = new GuiButtonHyperlink.External(0, x, y, font, arguments[arguments.length - 1], arguments[0], + font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix); + + }else{ + + Section target = GuiWizardHandbook.sections.get(arguments[0]); + + if(target == null) throw new JsonSyntaxException("Hyperlink points to nonexistent section id " + arguments[0]); + + button = new GuiButtonHyperlink.Internal(0, x, y, font, arguments[arguments.length - 1], + target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix); + } + + return button; + } + + static class Internal extends GuiButtonHyperlink { + + final Section target; + + Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix){ + super(id, x, y, font, text, indent, suffix); + this.target = target; + } + + @Override + public void playPressSound(SoundHandler soundHandler){ + soundHandler.playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_PAGE_TURN, 1)); + } + + } + + static class External extends GuiButtonHyperlink { + + final ITextComponent link; + + External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix){ + super(id, x, y, font, text, indent, suffix); + this.link = new TextComponentString(text); + link.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); + } + + } + +} diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonTurnPage.java b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonTurnPage.java new file mode 100644 index 00000000..a05ed041 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonTurnPage.java @@ -0,0 +1,63 @@ +package electroblob.wizardry.client.gui.handbook; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.DrawingUtils; +import electroblob.wizardry.registry.WizardrySounds; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.audio.SoundHandler; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +class GuiButtonTurnPage extends GuiButton { + + static final int WIDTH = 20; + static final int HEIGHT = 12; + + enum Type { + + NEXT_PAGE(0, 196), + PREVIOUS_PAGE(0, 208), + NEXT_SECTION(0, 220), + PREVIOUS_SECTION(0, 232), + CONTENTS(0, 244); + + private final int u, v; + + Type(int u, int v){ + this.u = u; + this.v = v; + } + } + + public final Type type; + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png"); + + public GuiButtonTurnPage(int id, int x, int y, Type type){ + super(id, x, y, WIDTH, HEIGHT, ""); + this.type = type; + } + + @Override + public void playPressSound(SoundHandler soundHandler){ + soundHandler.playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_PAGE_TURN, 1)); + } + + @Override + public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){ + + if(this.visible){ + + boolean flag = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + minecraft.getTextureManager().bindTexture(texture); + + DrawingUtils.drawTexturedRect(this.x, this.y, flag ? type.u + width : type.u, type.v, width, height, 512, 256); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java new file mode 100644 index 00000000..2c21a59f --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java @@ -0,0 +1,566 @@ +package electroblob.wizardry.client.gui.handbook; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.ClientProxy; +import electroblob.wizardry.client.DrawingUtils; +import electroblob.wizardry.client.gui.GuiButtonInvisible; +import electroblob.wizardry.client.gui.handbook.GuiButtonTurnPage.Type; +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardrySounds; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.audio.SoundHandler; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.multiplayer.ClientAdvancementManager; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.IResource; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.item.ItemStack; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.entity.player.AdvancementEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.input.Keyboard; + +import java.awt.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.util.*; +import java.util.List; + +/** + * GUI class for the wizard's handbook. Like any GUI class, this is instantiated each time the book is opened. As of + * Wizardry 4.2, the handbook text is defined as a JSON file rather than a plain text file, and is loaded only on + * resource pack reload, rather than every time the book is opened. This means all the data structures (sections, images, + * etc.) are built before the GUI instance exists at all. However, since some things depend on positioning, these have to + * be initialised on GUI creation. (Previously, everything was done on GUI load) + * + * @author Electroblob + * @since Wizardry 1.0 + * @see Section + * @see Contents + * @see Image + * @see CraftingRecipe + */ +@Mod.EventBusSubscriber +public class GuiWizardHandbook extends GuiScreen { + + private static final ResourceLocation DEFAULT = new ResourceLocation(Wizardry.MODID, "texts/handbook_en_us.json"); + + static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png"); + + /** Global Gson instance for the handbook. */ + private static final Gson gson = new Gson(); + + // Formatting markup + + static final char FORMAT_MARKER = '#'; + static final char HYPERLINK_MARKER = '@'; + + static final String IMAGE_TAG = "image"; + static final String RECIPE_TAG = "recipe"; + + static final Map FORMAT_TAGS = new HashMap<>(); + + // Dimension constants + // Private constants are not relevant to book elements, package-protected ones are + + /** The dimensions of the rendered GUI area. */ + static final int GUI_WIDTH = 288, GUI_HEIGHT = 180; + /** The dimensions of the area of a single page in which text can be drawn. */ + static final int PAGE_WIDTH = 120, PAGE_HEIGHT = 140; + /** The distance of the text from the top outside corner of each page. */ + static final int TEXT_INSET_X = 17, TEXT_INSET_Y = 16; + /** The distance of the buttons from the bottom outside corners of the GUI. */ + private static final int BUTTON_INSET_X = 22, BUTTON_INSET_Y = 13; + /** The distance between adjacent buttons. */ + private static final int BUTTON_SPACING = 20; + /** The distance of the page numbers from the bottom of the GUI. */ + private static final int PAGE_NUMBER_INSET = 22; + + // IDEA: Constant dimensions could be converted to JSON like the spell HUD ones + + // Global variables + + /** + * The double-page currently being viewed. Each double-page spread counts as a single page, with the inside + * of the front cover being page 0. + */ + private int currentPage = 0; + /** + * The number of single pages currently in the book. This is calculated on GUI load based on visible sections. + */ + private int pageCount = 1; // Starts at 1 because the first single-page is the inside of the cover + /** + * The double-page number where the bookmark is currently set, relative to the section stored in + * {@link GuiWizardHandbook#bookmarkSection}. Static because it persists when the book is closed. + */ + private static int bookmarkPage = 1; + /** + * A reference to the section in which the bookmark is currently set. Static because it persists when the book is + * closed. Storing a section means the bookmark doesn't change location when new sections are unlocked. + */ + private static Section bookmarkSection; + + // Buttons + private GuiButton bookmark, next, previous, nextSection, previousSection, menu; + + // Handbook content + + // As a general rule, I prefer to make static final fields lowercase if they're collections that change, because even + // though the collection itself is constant, the stuff in it is not, so being lowercase highlights this difference. + + /** + * A map which stores all loaded section objects, including subsections. This gets wiped on resource pack reload and + * repopulated with mappings as specified by the handbook JSON file for the current language. The keys in the map + * correspond to the keys in the sections object in that file, and are sorted in that order. + */ + static final Map sections = new LinkedHashMap<>(); + + /** + * A list which stores all loaded section objects, including subsections. This is an unmodifiable list view of the + * values in {@link GuiWizardHandbook#sections}, sorted in the same (page number) order. This exists only to allow + * sections to be accessed by ordinal index for the various navigation buttons, hence why it is private. + */ + private static List
sectionList; + + /** + * A map which stores all loaded contents objects. This gets wiped on resource pack reload and repopulated with + * mappings as specified by the handbook JSON file for the current language. The keys in the map correspond to the + * id strings for the contents objects in that file. This map is not sorted. + */ + static final Map contentsList = new HashMap<>(); + + /** + * A map which stores all loaded hex colour values. This gets wiped on resource pack reload and repopulated with + * mappings as specified by the handbook JSON file for the current language. The keys in the map correspond to the + * keys in the colours object in that file. This map is not sorted. + */ + static final Map colours = new HashMap<>(); + + /** + * A map which stores all loaded image objects. This gets wiped on resource pack reload and repopulated with + * mappings as specified by the handbook JSON file for the current language. The keys in the map correspond to the + * keys in the images object in that file. This map is not sorted. + */ + static final Map images = new HashMap<>(); + + /** + * A map which stores all loaded crafting recipe objects. This gets wiped on resource pack reload and repopulated + * with mappings as specified by the handbook JSON file for the current language. The keys in the map correspond to + * the keys in the recipes object in that file. This map is not sorted. + */ + static final Map recipes = new HashMap<>(); + + static String rulerText = "--------------------"; // Assigned here as a fallback + + private static final List>>> RECIPES = new ArrayList<>(); + + // Reflection + + static final Field ADVANCEMENT_TO_PROGRESS; + + static { + // TODO: Obf field name + ADVANCEMENT_TO_PROGRESS = ReflectionHelper.findField(ClientAdvancementManager.class, "advancementToProgress"); + } + + /** + * Adds a format tag to the handbook. All occurrences of the given tag string preceded by a # will be replaced with + * the result of the given value string on GUI load. The value string, therefore, can be anything that should be + * input dynamically, as long as it does not change while the GUI is open. Examples include wizardry's version, + * the various element colours and the keys assigned to wizardry's controls. + * @param tag The tag string, as defined in the handbook JSON file, excluding the # character. Cannot include spaces. + * @param value The string to replace occurrences of the given format tag with. Can include spaces but not the # character. + */ + public static void addFormatTag(String tag, String value){ + FORMAT_TAGS.put(tag, value); + } + + private static void initFormatTags(){ + + addFormatTag("next_spell_key", ClientProxy.NEXT_SPELL.getDisplayName()); + addFormatTag("previous_spell_key", ClientProxy.PREVIOUS_SPELL.getDisplayName()); + addFormatTag("mana_per_crystal_minus_30", "" + (Constants.MANA_PER_CRYSTAL - 30)); + addFormatTag("mana_per_crystal", "" + Constants.MANA_PER_CRYSTAL); + addFormatTag("novice_max_charge", "" + Tier.BASIC.maxCharge); + addFormatTag("apprentice_max_charge", "" + Tier.APPRENTICE.maxCharge); + addFormatTag("advanced_max_charge", "" + Tier.ADVANCED.maxCharge); + addFormatTag("master_max_charge", "" + Tier.MASTER.maxCharge); + addFormatTag("version", Wizardry.VERSION); + addFormatTag("mcversion", Minecraft.getMinecraft().getVersion()); + + addFormatTag("colour_novice", "\u00A77"); + addFormatTag("colour_apprentice", Tier.APPRENTICE.getFormattingCode()); + addFormatTag("colour_advanced", Tier.ADVANCED.getFormattingCode()); + addFormatTag("colour_master", Tier.MASTER.getFormattingCode()); + + addFormatTag("colour_fire", Element.FIRE.getFormattingCode()); + addFormatTag("colour_ice", Element.ICE.getFormattingCode()); + addFormatTag("colour_lightning", Element.LIGHTNING.getFormattingCode()); + addFormatTag("colour_necromancy", Element.NECROMANCY.getFormattingCode()); + addFormatTag("colour_earth", Element.EARTH.getFormattingCode()); + addFormatTag("colour_sorcery", Element.SORCERY.getFormattingCode()); + addFormatTag("colour_healing", Element.HEALING.getFormattingCode()); + + addFormatTag("colour_reset", "\u00A70"); + } + + // Helper methods + + /** + * Converts the given single page index to a double-page index. Inverse of + * {@link GuiWizardHandbook#doubleToSinglePage(int, boolean)}. + * + * @param singlePageIndex The single-page index, which is the same as the page numbers actually displayed. + * @return The corresponding double-page index. + */ + static int singleToDoublePage(int singlePageIndex){ + // Yes, this is trivial, but if I ever change the numbering it'll be useful. It's also more descriptive. + return singlePageIndex / 2; + } + + /** + * Converts the given double-page index to a single-page index. Inverse of + * {@link GuiWizardHandbook#singleToDoublePage(int)}. + * + * @param doublePageIndex The double-page index, as stored in {@link GuiWizardHandbook#currentPage}. + * @param rightHandPage True to return the page on the right (1 greater), false for the left-hand page. + * @return The corresponding single-page index. + */ + static int doubleToSinglePage(int doublePageIndex, boolean rightHandPage){ + return rightHandPage ? doublePageIndex * 2 + 1 : doublePageIndex * 2; + } + + /** + * Returns whether the given page index refers to a right-hand page or a left-hand page. + * + * @param page The single-page index, which is the same as the page number actually displayed. + * @return True if the given page index refers to a right-hand page, false if it is a left-hand page. + */ + static boolean isRightPage(int page){ + return page % 2 == 1; + } + + // Drawing + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks){ + + int left = this.width / 2 - GUI_WIDTH / 2; + int top = this.height / 2 - GUI_HEIGHT / 2; + + Minecraft.getMinecraft().renderEngine.bindTexture(texture); + + // Main background + DrawingUtils.drawTexturedRect(left, top, 0, 0, GUI_WIDTH, GUI_HEIGHT, 512, 256); + + // First page background + if(currentPage == 0){ + DrawingUtils.drawTexturedRect(left, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, 512, 256); + previous.visible = false; + previousSection.visible = false; // Not worth testing if we're in the first section every frame + menu.visible = false; + }else{ + previous.visible = true; + previousSection.visible = true; + menu.visible = true; + } + + // Last page background + if(currentPage == singleToDoublePage(pageCount)){ + DrawingUtils.drawTexturedFlippedRect(left + GUI_WIDTH / 2, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, 512, 256, true, false); + next.visible = false; + nextSection.visible = false; + }else{ + next.visible = true; + nextSection.visible = true; + } + + // Page numbers + if(currentPage > 0){ + String pageNumber = "" + doubleToSinglePage(currentPage, false); + this.fontRenderer.drawString(pageNumber, left + TEXT_INSET_X + PAGE_WIDTH / 2 + - fontRenderer.getStringWidth(pageNumber)/2, top + GUI_HEIGHT - PAGE_NUMBER_INSET, DrawingUtils.BLACK); + } + if(currentPage < singleToDoublePage(pageCount)){ + String pageNumber = "" + doubleToSinglePage(currentPage, true); + this.fontRenderer.drawString(pageNumber, left + GUI_WIDTH - TEXT_INSET_X - PAGE_WIDTH / 2 + - fontRenderer.getStringWidth(pageNumber)/2, top + GUI_HEIGHT - PAGE_NUMBER_INSET, DrawingUtils.BLACK); + } + + // Main content + images.values().forEach(i -> i.draw(fontRenderer, currentPage, left, top)); + contentsList.values().forEach(c -> c.draw(fontRenderer, currentPage, left, top)); + sections.values().forEach(s -> s.draw(fontRenderer, currentPage, left, top)); + recipes.values().forEach(r -> r.draw(fontRenderer, itemRender, currentPage, left, top)); + + // Buttons + super.drawScreen(mouseX, mouseY, partialTicks); + + // Bookmark + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().renderEngine.bindTexture(texture); + + if(currentPage == singleToDoublePage(bookmarkSection.startPage) + bookmarkPage){ + bookmark.visible = false; + DrawingUtils.drawTexturedRect(left + 138, top, 299, 0, 11, 191, 512, 256); + }else{ + bookmark.visible = true; + bookmark.x = left + (currentPage > singleToDoublePage(bookmarkSection.startPage) + bookmarkPage ? 130 : 147); + DrawingUtils.drawTexturedRect(bookmark.x, top, + bookmark.isMouseOver() ? 310 : 288, 0, 11, 191, 512, 256); + } + + // Recipe tooltips + recipes.values().forEach(r -> r.drawTooltips(this, fontRenderer, itemRender, currentPage, left, top, mouseX, mouseY)); + + } + + // GUI Initialisation / Close + + @Override + public void onResize(Minecraft minecraft, int width, int height){ + initGui(); + } + + @Override + public void onGuiClosed(){ + super.onGuiClosed(); + Keyboard.enableRepeatEvents(false); + } + + @Override + public void initGui(){ + + super.initGui(); + Keyboard.enableRepeatEvents(true); + + initFormatTags(); + + final int left = this.width / 2 - GUI_WIDTH / 2; + final int top = this.height / 2 - GUI_HEIGHT / 2; + + recipes.values().forEach(CraftingRecipe::load); + + int nextButtonId = 0; + + this.buttonList.clear(); + + this.buttonList.add(next = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH - BUTTON_INSET_X - GuiButtonTurnPage.WIDTH, + top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_PAGE)); + + this.buttonList.add(previous = new GuiButtonTurnPage(nextButtonId++, left + BUTTON_INSET_X, + top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_PAGE)); + + this.buttonList.add(nextSection = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH - BUTTON_INSET_X - GuiButtonTurnPage.WIDTH - BUTTON_SPACING, + top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_SECTION)); + + this.buttonList.add(previousSection = new GuiButtonTurnPage(nextButtonId++, left + BUTTON_INSET_X + BUTTON_SPACING, + top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_SECTION)); + + this.buttonList.add(menu = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH/2 - 28, + top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.CONTENTS)); + + this.buttonList.add(bookmark = new GuiButtonInvisible(nextButtonId++, left + 130, top + 172, 11, 19) { + @Override + public void playPressSound(SoundHandler soundHandler){ + soundHandler.playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_PAGE_TURN, 1)); + } + }); + + pageCount = 1; + + // Clears instances of all images and recipes + images.values().forEach(Image::clearInstances); + recipes.values().forEach(CraftingRecipe::clearInstances); + + // Formats all the unlocked sections in order + for(Section section : sections.values()){ + if(section.isUnlocked()){ + pageCount = section.format(this.fontRenderer, pageCount, left, top); + buttonList.addAll(section.getButtons()); + } + } + + contentsList.values().forEach(c -> buttonList.addAll(c.getButtons())); + + this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1)); + } + + // JSON Parsing / Data Construction + + /** + * Called from preInit in the main mod class (via the proxies) to initialise the handbook (parses the JSON file + * and constructs the relevant data structures), and again on each resource reload (changing the language triggers + * a resource reload). + */ + public static void loadHandbookFile(IResourceManager manager){ + + IResource handbookFile = getHandbookResource(manager); + + if(handbookFile != null){ + + // Wipes all the maps before repopulating them + images.clear(); + sections.clear(); + contentsList.clear(); + colours.clear(); + + bookmarkSection = null; // Also need to wipe the reference to the old bookmarked section + + BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream())); + + JsonElement je = gson.fromJson(reader, JsonElement.class); + JsonObject json = je.getAsJsonObject(); + + rulerText = JsonUtils.getString(json, "ruler_text"); + + JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(), + Color.decode(e.getValue().getAsString()).getRGB())); + + // Repopulates the remaining maps + Image.populate(images, json); + CraftingRecipe.populate(recipes, json); + Section.populate(sections, json); + + sectionList = Collections.unmodifiableList(new ArrayList<>(sections.values())); + + if(sections.isEmpty()){ + Wizardry.logger.warn("Handbook has no sections! Aborting loading..."); + return; + } + + // Attempts to find a suitable place to put the bookmark to start with + bookmarkSection = sections.get("introduction"); + if(bookmarkSection == null) bookmarkSection = sectionList.get(0); + } + } + + /** + * Retrieves the handbook JSON file for the current language and returns its IResource object. If a handbook file + * cannot be found for the current language, a message is printed to the console and the method attempts to retrieve + * the default file instead (English-US). If this file cannot be found, the resulting error is printed to the + * console and the method returns null. + * + * @param manager The resource manager instance to use. + * @return The handbook JSON file, as an IResource, or null if it was not found. + */ + private static IResource getHandbookResource(IResourceManager manager){ + + IResource handbookFile = null; + + try{ + handbookFile = manager.getResource(new ResourceLocation(Wizardry.MODID, "texts/handbook_" + + Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".json")); + }catch(IOException e){ + + Wizardry.logger.info("Wizard handbook JSON file missing for the current language (" + Minecraft.getMinecraft() + .getLanguageManager().getCurrentLanguage() + "). Using default (English-US) instead."); + + try{ + handbookFile = manager.getResource(DEFAULT); + }catch(IOException x){ + Wizardry.logger.error("Couldn't find file: " + DEFAULT + ". The file may be missing; please try re-downloading and reinstalling Wizardry.", x); + } + } + + return handbookFile; + } + + // Controls + + @Override + protected void actionPerformed(GuiButton button){ + + if(button.enabled){ + + if(button == next){ + if(currentPage < singleToDoublePage(pageCount)) currentPage++; + + }else if(button == previous){ + if(currentPage > 0) currentPage--; + + }else if(button == nextSection || button == previousSection){ + + Section currentSection = null; + + for(Section section : sections.values()){ + // We always want this button to do something, and taking the right-hand page means it always does + if(section.containsPage(doubleToSinglePage(currentPage, true))){ + currentSection = section; + break; + } + } + + if(currentSection != null){ + + int index = sectionList.indexOf(currentSection); + + if(button == nextSection && index + 1 < sections.size()){ + currentPage = singleToDoublePage(sectionList.get(index + 1).startPage); + }else if(index > 0){ + currentPage = singleToDoublePage(sectionList.get(index - 1).startPage); + } + } + + }else if(button == menu){ + currentPage = singleToDoublePage(sections.get("main_contents").startPage); + + }else if(button == bookmark && bookmarkSection != null){ + currentPage = singleToDoublePage(bookmarkSection.startPage) + bookmarkPage; + + }else{ + if(button instanceof GuiButtonHyperlink.Internal){ + currentPage = singleToDoublePage(((GuiButtonHyperlink.Internal)button).target.startPage); + }else if(button instanceof GuiButtonHyperlink.External){ + this.handleComponentClick(((GuiButtonHyperlink.External)button).link); + } + } + } + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException{ + if(mouseButton == 1){ + // Right-clicking of bookmark + if(bookmark.mousePressed(this.mc, mouseX, mouseY)){ + + this.selectedButton = bookmark; + + for(Section section : sections.values()){ + // The bookmark is assumed to bookmark the left-hand page + if(section.containsPage(doubleToSinglePage(bookmarkPage, false))) bookmarkSection = section; + } + + bookmarkPage = currentPage - singleToDoublePage(bookmarkSection.startPage); + } + }else{ + super.mouseClicked(mouseX, mouseY, mouseButton); + } + } + + // Overridden to make it public + @Override + public void renderToolTip(ItemStack stack, int x, int y){ + super.renderToolTip(stack, x, y); + } + + @SubscribeEvent + public static void onAdvancementEvent(AdvancementEvent event){ + sections.values().forEach(s -> s.onAdvancement(event.getEntityPlayer(), event.getAdvancement())); + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/Image.java b/src/main/java/electroblob/wizardry/client/gui/handbook/Image.java new file mode 100644 index 00000000..cb0d391e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/Image.java @@ -0,0 +1,119 @@ +package electroblob.wizardry.client.gui.handbook; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.client.DrawingUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.ResourceLocation; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +class Image { + + // Final fields are mandatory, the rest are optional + private final ResourceLocation location; + private final int width, height; + private int textureWidth, textureHeight; + private int u = 0, v = 0; + private String caption = ""; + // Derived fields, not specifically defined in JSON + private final Set instances = new HashSet<>(); + + private static final int CAPTION_OFFSET = 4; + + private Image(ResourceLocation location, int width, int height){ + this.location = location; + this.width = width; + this.height = height; + } + + /** Returns the width of the image. */ + int getWidth(){ + return width; + } + + /** Returns the total height of the image, including caption if it has one. */ + int getHeight(FontRenderer font){ + return caption.isEmpty() ? height : height + CAPTION_OFFSET + font.FONT_HEIGHT; + } + + /** + * Adds an instance of this image to the list. + * + * @param page The index of the single page this image is on. + * @param x The x-coordinate of the top-left corner of the image, relative to the top-left corner of the GUI. + * @param y The y-coordinate of the top-left corner of the image, relative to the top-left corner of the GUI. + */ + void addInstance(int page, int x, int y){ + instances.add(new int[]{page, x, y}); + } + + /** Removes all instances of this image from the list. */ + void clearInstances(){ + instances.clear(); + } + + /** + * Draws all instances of this image that are located on the given double-page spread. + * + * @param font The font renderer object. + * @param doublePage The double-page index of the page to be drawn. + * @param left The x coordinate of the left side of the GUI. + * @param top The y coordinate of the top of the GUI. + */ + void draw(FontRenderer font, int doublePage, int left, int top){ + for(int[] instance : instances){ + if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){ + Minecraft.getMinecraft().renderEngine.bindTexture(location); + GlStateManager.color(1, 1, 1, 1); + DrawingUtils.drawTexturedRect(left + instance[1], top + instance[2], u, v, width, height, textureWidth, textureHeight); + font.drawString("\u00A7o" + caption, left + instance[1] + width/ 2 - font.getStringWidth(caption)/2, + top + instance[2] + height + CAPTION_OFFSET, GuiWizardHandbook.colours.get("caption")); + } + } + } + + /** + * Parses the given JSON object and constructs a new {@code Image} from it, setting all the relevant fields + * and references. + * + * @param json A JSON object representing the image to be constructed. This must contain at least a "location" + * string. + * @return The resulting {@code Image} object. + * @throws JsonSyntaxException if at any point the JSON object is found to be invalid. + */ + static Image fromJson(JsonObject json){ + + Image image = new Image(new ResourceLocation(JsonUtils.getString(json, "location")), + JsonUtils.getInt(json, "width"), JsonUtils.getInt(json, "height")); + + image.u = JsonUtils.getInt(json, "u", 0); + image.v = JsonUtils.getInt(json, "v", 0); + image.textureWidth = JsonUtils.getInt(json, "texture_width", image.width); + image.textureHeight = JsonUtils.getInt(json, "texture_height", image.height); + image.caption = JsonUtils.getString(json, "caption", ""); + + + return image; + } + + static void populate(Map map, JsonObject json){ + + JsonObject sectionsObject = JsonUtils.getJsonObject(json, "images"); + + // Need to iterate over these since we don't know what they're called or how many there are + for(Map.Entry entry : sectionsObject.entrySet()){ + + String key = entry.getKey(); // Find out what each element is called, this will be the sections map key + + Image image = fromJson(entry.getValue().getAsJsonObject()); + map.put(key, image); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/Section.java b/src/main/java/electroblob/wizardry/client/gui/handbook/Section.java new file mode 100644 index 00000000..29f5fc0e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/Section.java @@ -0,0 +1,429 @@ +package electroblob.wizardry.client.gui.handbook; + +import com.google.common.collect.Streams; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.DrawingUtils; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementProgress; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.JsonUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; + +/** + * Instances of this class represent sections in the wizard's handbook. As of wizardry 4.2, this class handles + * everything within the section itself, including JSON parsing, unlock triggers and drawing the actual rawText. + * Sections may now also be nested and have other elements within them, such as images and a table of contents, a + * behaviour which is also handled within this class. + *

+ * The formatting of the book is now done 'dynamically' - that is, the exact positions and page numbers of + * sections, images and so on are determined on GUI load and depend on which of the previous sections have been + * unlocked, amongst other factors. This means that all of the unlocked sections must be formatted in order on GUI + * load, so that each section knows the previous section's length and therefore where to start. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +// Because these are now generated on resource pack reload (not on handbook open, as before), this class must now +// be static +class Section { + + // Final fields are mandatory (none here though), the rest are optional + String title; + private String[] rawText; + private Contents contents; + private Advancement[] triggers; + private Map subsections; + private boolean centreX, centreY; + + // Derived fields, not explicitly defined in JSON + /** The single-page index of the first page of this section. */ + int startPage; + private final List> buttons; + /** + * A list of single pages, which are themselves lists of paragraphs (each paragraph is a single + * string which may include line breaks and other escape characters). + */ + private final List> pages; + + private Section(){ + this.buttons = new ArrayList<>(); + this.pages = new ArrayList<>(); + this.subsections = new LinkedHashMap<>(); + } + + Collection getButtons(){ + return WizardryUtilities.flatten(buttons); + } + + /** + * Returns true if the given page is within this section, false if not. + */ + boolean containsPage(int page){ + return startPage <= page && startPage + pages.size() > page; + } + + /** + * Returns true if this section is unlocked for the client player, false if not. Always returns true if + * handbook progression is disabled in the config. + */ + boolean isUnlocked(){ + + if(!Wizardry.settings.handbookProgression) return true; // Always unlocked if handbook progression is off + + // A section is automatically unlocked if one of its subsections is unlocked + for(Section subsection : subsections.values()){ + if(subsection.isUnlocked()) return true; + } + + if(triggers == null) return true; // If no triggers were defined, the section is unlocked from the start + + for(Advancement trigger : triggers){ + + try{ + + // TESTME: Is this properly synced or do we need to do that as well? + Map advancements = (Map)GuiWizardHandbook.ADVANCEMENT_TO_PROGRESS.get(Minecraft.getMinecraft().player.connection.getAdvancementManager()); + + if(advancements.get(trigger).isDone()){ + return true; + } + + }catch(IllegalAccessException e){ + e.printStackTrace(); + } + } + + return false; + } + + /** + * Actually draws the contents of the given section for the given double-page spread. Will do nothing if the + * given page is outside of this section. + * + * @param font The font renderer object. + * @param doublePage The index of the double-page to be drawn. + * @param left The x coordinate of the left side of the GUI. + * @param top The y coordinate of the top of the GUI. + */ + // This method is supposed to be 'idiot-proof' in the sense that the code calling it need not check whether the + // section actually needs drawing, so it can just dumbly call draw(...) for all the sections in order. + void draw(FontRenderer font, int doublePage, int left, int top){ + + // Show/hide buttons + + int i = 0; + + for(List list : buttons){ + final int i1 = i++; + list.forEach(b -> b.visible = GuiWizardHandbook.singleToDoublePage(startPage + i1) == doublePage); + } + + int leftIndex = GuiWizardHandbook.doubleToSinglePage(doublePage, false); + // Relative indices of the pages to be rendered - often these will be outside the section entirely + int[] visiblePages = {leftIndex - startPage, leftIndex - startPage + 1}; + + for(int page : visiblePages){ + + if(page >= 0 && page < pages.size()){ + + List lines = pages.get(page); + + int x = left + (GuiWizardHandbook.isRightPage(startPage + page) ? GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : GuiWizardHandbook.TEXT_INSET_X); + int y = top + GuiWizardHandbook.TEXT_INSET_Y; + if(centreY) y += GuiWizardHandbook.PAGE_HEIGHT / 2 - lines.size() / 2 * font.FONT_HEIGHT; + + for(String line : lines){ + + int lx = centreX ? x + GuiWizardHandbook.PAGE_WIDTH / 2 - font.getStringWidth(line) / 2 : x; + + font.drawString(line, lx, y, DrawingUtils.BLACK, false); + + y += font.FONT_HEIGHT; + } + } + } + } + + /** + * Called on GUI load to format the section, contents tables and other elements, excluding subsections. + * Does not perform any actual drawing. + * + * @param font The font renderer object, for measurement purposes. + * @param startPage The index of the first page (single side, not double-page) of this section. + * @param left The x coordinate of the left side of the GUI. + * @param top The y coordinate of the top of the GUI. + * @return The single-page index of the next blank page after the end of this section. + * @throws JsonSyntaxException if at any point the formatting is found to be invalid. + */ + int format(FontRenderer font, int startPage, int left, int top){ + + this.buttons.clear(); + this.pages.clear(); + + // FONT_HEIGHT may change between fonts, so this is calculated here. With the default font it's 14. + final int maxLineNumber = GuiWizardHandbook.PAGE_HEIGHT / font.FONT_HEIGHT; + + this.startPage = startPage; + + // First everything is added to a single list of lines, then it is split into pages. + List lines = new ArrayList<>(); + + // Adds the header if present + if(!this.title.isEmpty()){ + lines.add(this.title); + lines.add(GuiWizardHandbook.rulerText); + } + + // Adds space for the contents if it exists + if(this.contents != null){ + lines.addAll(Collections.nCopies(this.contents.format(font, startPage, lines.size(), left, top), "")); + // Line break between contents and first paragraph + if((lines.size() % maxLineNumber) != 0) lines.add(""); + } + + if(this.rawText != null){ + // Paragraphs are defined as a JSON list because it makes it easier to arrange them properly across pages + // - using multiple line breaks would mean having to find and remove them when at the top of a page. + for(String paragraph : this.rawText){ + + // (lines.size() % maxLineNumber) gives the number of lines on the current page + // (lines.size() / maxLineNumber) gives the index of the current page minus the value of startPage + + // Formats the paragraph + + String raw = paragraph; // For error messages + + // Images (images must be separate paragraphs) + + if(paragraph.startsWith(GuiWizardHandbook.FORMAT_MARKER + GuiWizardHandbook.IMAGE_TAG)){ + + String[] arguments = paragraph.split("\\s", 2); + + if(arguments.length < 2) throw new JsonSyntaxException("Missing image name in string " + + StringUtils.abbreviate(raw, 50)); + + Image image = GuiWizardHandbook.images.get(arguments[1]); + if(image == null) throw new JsonSyntaxException("Image with id " + arguments[1] + "is undefined"); + + // Starts a new page if the image will not fit on the current one + if((lines.size() % maxLineNumber) * font.FONT_HEIGHT + image.getHeight(font) > GuiWizardHandbook.PAGE_HEIGHT){ + // Remaining number of lines on the page + lines.addAll(Collections.nCopies(maxLineNumber - (lines.size() % maxLineNumber), "")); + } + + if(image.getWidth() > GuiWizardHandbook.PAGE_WIDTH) Wizardry.logger.warn("Image with id " + arguments[1] + + "has a width (" + image.getWidth() + ") greater than the maximum page width (" + GuiWizardHandbook.PAGE_WIDTH + + "), it will extend beyond the page area."); + + if(image.getHeight(font) > GuiWizardHandbook.PAGE_HEIGHT) Wizardry.logger.warn("Image with id " + arguments[1] + + "has a height (" + image.getHeight(font) + ") greater than the maximum page height (" + GuiWizardHandbook.PAGE_HEIGHT + + "), it will extend beyond the page area."); + + int page = startPage + (lines.size() / maxLineNumber); + + image.addInstance(page, GuiWizardHandbook.PAGE_WIDTH / 2 - image.getWidth() / 2 + + (GuiWizardHandbook.isRightPage(page) ? GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : GuiWizardHandbook.TEXT_INSET_X), + GuiWizardHandbook.TEXT_INSET_Y + (lines.size() % maxLineNumber) * font.FONT_HEIGHT); + + // Height of the image in lines, rounded up + // Uses a single space instead of an empty string so that the page trimming doesn't remove them + lines.addAll(Collections.nCopies(image.getHeight(font) / font.FONT_HEIGHT, " ")); + lines.add(""); // The last one is removable though, since it's actually extra space + + // Recipes (recipes must be separate paragraphs) + }else if(paragraph.startsWith(GuiWizardHandbook.FORMAT_MARKER + GuiWizardHandbook.RECIPE_TAG)){ + + String[] arguments = paragraph.split("\\s", 2); + + if(arguments.length < 2) throw new JsonSyntaxException("Missing recipe name in string " + + StringUtils.abbreviate(raw, 50)); + + CraftingRecipe recipe = GuiWizardHandbook.recipes.get(arguments[1]); + if(recipe == null) throw new JsonSyntaxException("Recipe with id " + arguments[1] + "is undefined"); + + // Starts a new page if the recipe will not fit on the current one + if((lines.size() % maxLineNumber) * font.FONT_HEIGHT + CraftingRecipe.HEIGHT > GuiWizardHandbook.PAGE_HEIGHT){ + // Remaining number of lines on the page + lines.addAll(Collections.nCopies(maxLineNumber - (lines.size() % maxLineNumber), "")); + } + + int page = startPage + (lines.size() / maxLineNumber); + + recipe.addInstance(page, GuiWizardHandbook.PAGE_WIDTH / 2 - CraftingRecipe.WIDTH / 2 + + (GuiWizardHandbook.isRightPage(page) ? GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : GuiWizardHandbook.TEXT_INSET_X), + GuiWizardHandbook.TEXT_INSET_Y + (lines.size() % maxLineNumber) * font.FONT_HEIGHT); + + // Height of the recipe in lines, rounded up + // Uses a single space instead of an empty string so that the page trimming doesn't remove them + lines.addAll(Collections.nCopies(CraftingRecipe.HEIGHT / font.FONT_HEIGHT, " ")); + // This time we're not adding an extra space because it's not really needed + + }else{ // All other paragraphs + + // Hyperlinks + + int linkStart; + + while((linkStart = paragraph.indexOf(GuiWizardHandbook.HYPERLINK_MARKER)) > -1){ // Ooh an assignment and a comparison in one... + + int linkEnd = paragraph.indexOf(GuiWizardHandbook.HYPERLINK_MARKER, linkStart + 1); + + if(linkEnd < 0) throw new JsonSyntaxException("Un-closed hyperlink marker in string " + + StringUtils.abbreviate(raw, 50)); + + List upToLink = font.listFormattedStringToWidth(paragraph.substring(0, linkStart), GuiWizardHandbook.PAGE_WIDTH); + + String linkRaw = paragraph.substring(linkStart, linkEnd + 1); + String[] arguments = paragraph.substring(linkStart + 1, linkEnd).split("\\s", 2); + String suffix = paragraph.substring(linkEnd).split("\\s", 2)[0]; + + // The index of the single page currently being formatted, relative to the section + int pageRelative = (lines.size() + upToLink.size() - 1) / maxLineNumber; + // The overall index of the single page currently being formatted + int page = startPage + pageRelative; + + int x = GuiWizardHandbook.isRightPage(page) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X; + int y = top + GuiWizardHandbook.TEXT_INSET_Y + (((lines.size() + upToLink.size() - 1) % maxLineNumber)) * font.FONT_HEIGHT; + + // Adds any missing sub-lists + while(this.buttons.size() <= pageRelative){ + this.buttons.add(new ArrayList<>()); + } + + // The button id only does what you use it for, so we're just not using it at all. + this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix)); + + // The link button should exactly overlay the display rawText in the main string + // If the link has no display rawText specified, it displays the unformatted target string + paragraph = paragraph.replace(linkRaw, arguments[arguments.length - 1]); + } + + // Formatting + for(Map.Entry entry : GuiWizardHandbook.FORMAT_TAGS.entrySet()){ + paragraph = paragraph.replace(GuiWizardHandbook.FORMAT_MARKER + entry.getKey(), entry.getValue()); + } + + lines.addAll(font.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH)); + } + + // Line break between paragraphs (the last one will just be deleted later) + if((lines.size() % maxLineNumber) != 0) lines.add(""); + } + } + + // Splits lines into pages + + List page = new ArrayList<>(); + pages.add(page); + + while(!lines.isEmpty()){ + + if(page.size() == maxLineNumber){ + // Removes blank lines at the end of the page + while(page.get(page.size() - 1).isEmpty()) page.remove(page.size() - 1); + // Adds a new page + pages.add(page = new ArrayList<>()); + } + + String line = lines.remove(0); + + // Prevents blank lines at the start of the page + if(!page.isEmpty() || !line.isEmpty()) page.add(line); + } + + return startPage + pages.size(); + } + + /** + * Parses the given JSON object and constructs a new {@code Section} from it, setting all the relevant fields + * and references. This method converts the JSON object to a {@code Section} object and retrieves any resources; + * the section is not formatted in any way until GUI load, in {@link Section#format(FontRenderer, int, int, int)}. + * + * @param json A JSON object representing the section to be constructed. This must contain at least a "title" + * string. + * @return The resulting {@code Section} object. + * @throws JsonSyntaxException if at any point the JSON object is found to be invalid. + */ + static Section fromJson(JsonObject json){ + + Section section = new Section(); + + section.title = JsonUtils.getString(json, "title", ""); + + if(JsonUtils.hasField(json, "include_in_contents")){ + + String id = JsonUtils.getString(json, "include_in_contents"); + + Contents belongsTo = GuiWizardHandbook.contentsList.get(id); + + if(belongsTo == null){ + throw new JsonSyntaxException("Expected include_in_contents to be the id of a previously defined contents, but no contents with the id " + id + " exists yet."); + }else{ + belongsTo.addEntry(section); + } + } + + if(JsonUtils.hasField(json, "contents")){ + section.contents = Contents.fromJson(JsonUtils.getJsonObject(json, "contents")); + GuiWizardHandbook.contentsList.put(section.contents.id, section.contents); + } + + if(JsonUtils.hasField(json, "text")){ + // TESTME: Does this always preserve order? + section.rawText = Streams.stream(JsonUtils.getJsonArray(json, "text")) + .map(e -> JsonUtils.getString(e, "element of array rawText")) + .toArray(String[]::new); + } + + // TODO: Triggers + + if(JsonUtils.hasField(json, "centre")){ + JsonObject centre = JsonUtils.getJsonObject(json,"centre"); + section.centreX = JsonUtils.getBoolean(centre, "x", false); + section.centreY = JsonUtils.getBoolean(centre, "y", false); + } + + // The only benefit of having subsections (other than logical grouping) is that the parent section can + // automatically be unlocked if one of the subsections is. + if(JsonUtils.hasField(json, "sections")){ + populate(section.subsections, json); + } + + return section; + } + + static void populate(Map map, JsonObject json){ + + JsonObject sectionsObject = JsonUtils.getJsonObject(json, "sections"); + + // Need to iterate over these since we don't know what they're called or how many there are + for(Map.Entry entry : sectionsObject.entrySet()){ + + String key = entry.getKey(); // Find out what each element is called, this will be the sections map key + + Section section = fromJson(entry.getValue().getAsJsonObject()); + map.put(key, section); + map.putAll(section.subsections); + } + } + + public void onAdvancement(EntityPlayer player, Advancement advancement){ + Minecraft minecraft = Minecraft.getMinecraft(); + //System.out.println(title); + if(triggers != null && Arrays.asList(triggers).contains(advancement) && player == minecraft.player){ + //minecraft.getToastGui().drawToast(IToast); + + // Debug + //System.out.println(title); + } + } +} diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json b/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json new file mode 100644 index 00000000..8eddb4be --- /dev/null +++ b/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json @@ -0,0 +1,528 @@ +{ + "ruler_text": "--------------------", + + "colours": { + "text": "#000000", + "caption": "#666666", + "hyperlink": "#601ba0", + "highlight": "#dd4c1d" + }, + + "images": { + "workbench": { + "location": "ebwizardry:textures/gui/arcane_workbench_picture.png", + "caption": "The Arcane Workbench", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "crystal_ore": { + "location": "ebwizardry:textures/gui/ore_picture.png", + "caption": "Crystal Ore", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + }, + "magic_crystal": { + "location": "ebwizardry:textures/items/crystal_magic.png", + "caption": "A Magic Crystal", + "u": 6, + "v": 6, + "width": 36, + "height": 33, + "texture_width": 48, + "texture_height": 48 + }, + "magic_wand": { + "location": "ebwizardry:textures/items/wand_basic.png", + "caption": "A Magic Wand", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + }, + "crystal_flower": { + "location": "ebwizardry:textures/gui/flower_picture.png", + "caption": "A Crystal Flower", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + } + }, + + "recipes": { + "arcane_workbench": { + "location": "ebwizardry:arcane_workbench" + }, + "magic_wand": { + "location": "ebwizardry:magic_wand" + }, + "magic_missile_spell_book": { + "location": "ebwizardry:magic_missile_spell_book" + }, + "wizard_handbook": { + "location": "ebwizardry:wizard_handbook" + }, + "crystal_flower_to_crystals": { + "location": "ebwizardry:crystal_flower_to_crystals" + }, + "mana_flask": { + "location": "ebwizardry:mana_flask" + }, + "transportation_stone": { + "location": "ebwizardry:transportation_stone" + }, + "magic_silk": { + "location": "ebwizardry:magic_silk" + }, + "wizard_hat": { + "location": "ebwizardry:wizard_hat" + }, + "wizard_robe": { + "location": "ebwizardry:wizard_robe" + }, + "wizard_leggings": { + "location": "ebwizardry:wizard_leggings" + }, + "wizard_boots": { + "location": "ebwizardry:wizard_boots" + }, + "blank_scroll": { + "location": "ebwizardry:blank_scroll" + }, + "firebomb": { + "location": "ebwizardry:firebomb" + }, + "poison_bomb": { + "location": "ebwizardry:poison_bomb" + }, + "smoke_bomb": { + "location": "ebwizardry:smoke_bomb" + } + }, + + "sections": { + + "inside_cover": { + "centre": { + "x": true, + "y": true + }, + "text": [ + + "The Wizard's Handbook", + + "By Electroblob" + ] + }, + + "introduction": { + "title": "Introduction", + "text": [ + + "Greetings, wizard! This book explains the many ways of the arcane and how to use them. This is no ordinary book, though - its pages will materialise before you as you discover more about the magical world.", + + "Use the arrow buttons to turn between pages, and the double-arrow buttons to quickly flip between sections. Use the central menu button to return to the main contents page.", + + "Click on any purple link text to jump straight to the relevant page. Right-click the bookmark to move it to the current page, and left-click to return to the bookmarked page." + ] + }, + + "main_contents": { + "title": "Contents", + "contents": { + "id": "main_contents", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + } + }, + + "setting_up": { + "title": "Setting Up", + "include_in_contents": "main_contents", + "text": [ + + "To get started with wizardry, you will need a few things:", + + "- A magic wand, crafted with a gold nugget, a stick, and a magic crystal.", + + "- An @arcane_workbench arcane workbench@, crafted with 3 stone, 1 lapis lazuli block, 2 magic crystals, 2 gold nuggets and 1 purple carpet.", + + "- A @spells spell@ book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, with a book and 4 magic crystals.", + + "You will also need a bunch more magic crystals to supply your wand with @mana@." + ] + }, + + "mana": { + "title": "Mana", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:crystal" + ], + "text": [ + + "Mana is the arcane energy that gives wizards their powers. It is not a physical substance in its own right; rather, it is an everpresent aura which permeates everything in the world. In particular, it manifests itself in naturally occurring crystals, which can be found embedded in rocks underground. @wands Wands@ can store mana within them, and this mana is channelled into the @spells@ that you cast. Different spells require different amounts of mana, depending on how powerful they are and how long they last.", + + "#image crystal_ore", + + "#image magic_crystal", + + "It is widely accepted that mana cannot be created or destroyed, and that when a spell is cast, the mana it channels is simply dissipated into the surroundings. Indeed, this is how the vast majority of mana exists - spread thinly throughout the world. However, to be of any use, it must be concentrated, either naturally over thousands of years, as is the case with crystals underground, or artificially - an advanced subject covered later in this book. There also exist various ways of making spells more mana-efficient and recovering some of the mana dissipated during spellcasting." + ] + }, + + "wands": { + "title": "Wands", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], + "text": [ + + "The wand is the implement of choice for a wizard. With it, you can cast any @spells spell@ provided the wand can contain its power (see @tiers Tiers@). Wands come in many different varieties but you will almost certainly start with a basic magic wand.", + + "#image magic_wand", + + "Most wands begin their life as a simple arrangement of a magic crystal of some sort attached to a wooden stick, with a gold nugget affixed to the other end. The crystal is, of course, the source of the wand's power, as it provides the focus necessary to channel @spells@. The rest of the wand is important too though, as it provides not only a means with which to hold the wand, but also a path through which @mana@ can be channelled and directed.", + + "As more spells are cast with a wand, it grows more effective at channelling @spells@, and can therefore cast spells of greater power. This effect can be discerned from subtle changes that occur in the shape and appearance of the wand itself: as a wand grows more powerful, its crystal will become more vibrant, it may change in colour depending on its element, and after a while, the wood from which it is made will start to grow and twist into more complex shapes.", + + "When holding a wand, a small heads-up display will show in the corner of the screen. This indicates the spell that is currently selected along with a pictorial representation of it, and, if the spell has been cast, a cooldown bar indicating the time until that spell can be cast again. It also shows the names of the next and previous spells bound to the wand. To switch between spells, use the #next_spell_key and #previous_spell_key keys (these can be changed in options -> controls). You can also switch spells by scrolling the mouse wheel while sneaking.", + + "When viewing an inventory, hovering over a wand will display how much @mana@ is stored in it, along with its currently selected @spells spell@ and any specific abilities it may have. More in-depth information about a wand can be viewed by placing it in an @arcane_workbench arcane workbench@." + ] + }, + + "spells": { + "title": "Spells", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/spells" + ], + "text": [ + + "A @wands wand@ is useless without spells to cast with it. Spells are recorded in two forms: in books, which are permanent, and in scrolls, which are temporary.", + + "Spell books are of little use on their own; instead they are used to bind the spell they contain to @wands@. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more detailed information about the spell.", + + "Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself by crafting a blank scroll from a piece of paper and some string. You can then bind a spell to the scroll using the @arcane_workbench arcane workbench@, but only if you have knowledge of that spell (see @enchanting_scrolls Enchanting Scrolls@). Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your @wands wand@. It should be noted, however, that scrolls are at best an inefficient method of casting spells.", + + "To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right-clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification in the process." + ] + }, + + "arcane_workbench": { + "title": "Arcane Workbench", + "include_in_contents": "main_contents", + "contents": { + "id": "arcane_workbench_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind @spells@ to your @wands wand@. Simply place it anywhere and right click, and you will see something like this:", + + "#image workbench" + ], + "sections": { + "binding_spells": { + "title": "Binding Spells", + "include_in_contents": "arcane_workbench_subsections", + "text": [ + + "To bind a spell to your wand, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press apply. You will notice that the spell book is left untouched during this process - this is because the act of spell binding does not 'take' the spell from the spell book; rather, it attunes the wand to the spell. As such, you may change the spells bound to your wand as much as you wish by simply repeating the spell binding process. You can bind up to five spells to a wand at one time, though this number may be increased with attunement upgrades." + ] + }, + "charging_wands": { + "title": "Charging Wands", + "include_in_contents": "arcane_workbench_subsections", + "text": [ + + "To charge your wand, place the wand in the central slot of the arcane workbench and place some magic crystals in the upper of the two slots on the left, and then press apply. Each crystal is worth #mana_per_crystal mana, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals so if the wand needs, for example, 30 more mana, #mana_per_crystal_minus_30 mana will be lost when charging it." + ] + }, + "upgrading_wands": { + "title": "Upgrading Wands", + "include_in_contents": "arcane_workbench_subsections", + "text": [ + + "To upgrade your wand, you will need a tome of arcana of the appropriate tier (see @tiers Tiers@) or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the lower of the two slots on the left, then press apply.", + + "Special wand upgrades improve a particular aspect of a wand. Each type of upgrade can stack up to three times, and the total number of upgrades that a wand can take depends on its tier. Upgrades cannot be removed." + ] + }, + "enchanting_scrolls": { + "title": "Enchanting Scrolls", + "include_in_contents": "arcane_workbench_subsections", + "text": [ + + "The arcane workbench can also be used to enchant spell scrolls. To do so, you will require a blank scroll, crafted from a piece of paper and some string, a spell book for your chosen spell, and enough magic crystals to provide mana to cast it. Place the crystals in the upper left-hand slot, the blank scroll in the central slot, and the spell book in the single slot that appears above it, then press apply to enchant the scroll." + ] + } + } + }, + + "wizard_armour": { + "title": "Wizard Armour", + "include_in_contents": "main_contents", + "text": [ + + "As a wizard, you will need something to protect you from the creatures you fight. No ordinary armour will do though. To make the most of your spells, you will need wizard armour: hat, robes, leggings and boots. Unlike ordinary armour, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much mana. Charge them as you would a wand in the arcane workbench or with a mana flask, but be careful - if they run out of mana, you will find yourself defenceless.", + + "You can obtain wizard armour by crafting it from magical silk, obtained by crafting string with a magic crystal.", + + "Those wizards who devote themselves to the practice of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find.", + + "Legend speaks of an arcane seal used by the most powerful wizards to greatly improve their armour." + ] + }, + + "magical_world": { + "title": "Magic in the World", + "include_in_contents": "main_contents", + "contents": { + "id": "magical_world_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "text": [ + + "One cannot master the arcane just by staying at home - there is a world full of magic out there to explore! Ancient ruins, relics and mysterious beings good and bad await discovery - if you know where to look. The greatest wizards are also the most curious, and gain much of their knowledge and power through exploration of the environment around them, and experimenting with what they find.", + + "Whilst much of a wizard's time is inevitably spent alone, the sharing of knowledge is also vital to learning the arcane arts. Seek out fellow practicioners of magic, and learn as much as you can from them: communication is arguably the greatest power of all." + ], + "sections": { + "crystal_flowers": { + "title": "Crystal Flowers", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/crystal_flowers" + ], + "text": [ + + "During your travels, you will probably come across curious glowing flowers growing in the wild from time to time. These distinctive blooms are known as crystal flowers, and they are strangely effective at concentrating mana - to this day, nobody is quite sure why. We do know, however, that they can be harvested and crafted to extract the mana as crystals, making them a rather useful above-ground source of mana. The amount of mana obtainable this way is limited, though, by the small size of the flowers and due to them only growing in small patches.", + + "#image crystal_flower" + ] + }, + "wizard_towers": { + "title": "Wizard Towers", + "include_in_contents": "magical_world_subsections", + "text": [ + + "Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter a tall tower or two with a distinctive pointed roof. This is the residence of a fellow wizard. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder. If, however, it is a master spell you seek, you will need to speak to a specialist.", + + "Unfortunately, there are a few wizards out there who do not welcome visitors. These wizards are typically outcasts, and are hostile to anyone crossing their path. Approach these individuals with caution, and be prepared to defend yourself against powerful magic. Defeat them however, and their knowledge is yours for the taking.", + + "It should also be noted that no wizard will take kindly to being attacked or stolen from - and will readily take the law into their own hands." + ] + }, + "obelisks": { + "title": "Obelisks", + "include_in_contents": "magical_world_subsections", + "text": [ + + "Vestiges of ancient magic are scattered throughout the world, the most notable of which are carved stone structures which bear a great many symbols and runes. These ruins are all that remain of what appears to have been some kind of ancient civilisation. Whoever, or whatever, built them, they clearly had a considerable knowledge of magic, and used it to place protective enchantments over such locations that still persist to this day.", + + "These stuctures fit broadly into two types. The first, and more common, of these are obelisks: tall spikes of carved stone, known as runestone, with an open structure at the bottom that usually contains minor arcane relics from the forgotten past. These structures are typically protected by an enchantment that summons hostile magical creatures should any human stray too close. Fend off these creatures and destroy their source, and the relics are yours." + ] + }, + "shrines": { + "title": "Shrines", + "include_in_contents": "magical_world_subsections", + "text": [ + + "The second, and rarer, kind of structure is known as a shrine. These structures consist of a circle of runestone pillars surrounding a central platform, upon which sits a chest filled with ancient artefacts. This chest is typically protected by an arcane lock enchantment, preventing anyone except the owner from opening it. The entire structure is also protected by a containment field, which prevents anything that strays too close from escaping.", + + "Due to their great arcane power and significance, not to mention the riches within, these structures are particularly attractive to any aspiring wizard - but be cautious. There are numerous reports of wizards becoming trapped within containment fields and slowly being driven insane, perhaps by claustrophobia. A growing number, however, believe such occurences to be a deliberate part of the shrine's protective magic, and that the wizards trapped within are in fact being controlled to protect the structure. A chilling prospect, surely, for anyone who dares to venture near..." + ] + }, + "creatures": { + "title": "Magical Creatures", + "include_in_contents": "magical_world_subsections", + "text": [ + + "Besides wizards, a multitude of other creatures also use magic. Many of these creatures are arcane in origin, and most can be summoned using certain magical spells. One may encounter these creatures guarding an obelisk, or perhaps a powerful summoner. Lesser arcane beings are even found occasionally in the wilderness." + ] + }, + "artefacts": { + "title": "Artefacts", + "include_in_contents": "magical_world_subsections", + "text": [ + + "When exploring a shrine, you may be lucky enough to uncover some kind of ancient magical artefact - an object capable of granting its wearer unique and powerful buffs and special powers. Three types are known to have been found: rings, which grant bonuses and effects to spells, amulets, which improve defensive abilities, and trinkets, which give utility effects. These artefacts appear to function only when worn appropriately; simply having them on one's person is insufficient." + ] + } + } + }, + + "tiers": { + "title": "Tiers", + "include_in_contents": "main_contents", + "text":[ + + "Wands and spells come in four tiers: #colour_novicenovice#colour_reset, #colour_apprenticeapprentice#colour_reset, #colour_advancedadvanced #colour_resetand #colour_mastermaster#colour_reset. Each tier is more powerful than the last.", + + "#colour_noviceNovice #colour_resetwands are the ones that can be crafted. They hold up to #novice_max_charge mana, and can only cast novice spells. Novice spells are simple enough to be cast by anyone and they do not usually cost much mana. This does not necessarily mean that they are useless at higher tiers however; their low cost makes some novice spells useful even when you have access to master spells.", + + "#colour_apprenticeApprentice #colour_resetwands are the next tier up from novice wands. They hold up to #apprentice_max_charge mana and can cast novice and apprentice spells. Apprentice spells are a little more impressive than novice spells but usually cost more.", + + "#colour_advancedAdvanced #colour_resetwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold #advanced_max_charge mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on enemies.", + + "#colour_masterMaster #colour_resetwands are the most powerful wands in existence. They hold up to #master_max_charge mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution." + ] + }, + + "elements": { + "title": "Elements", + "include_in_contents": "main_contents", + "text": [ + + "Spells belong to different elements, which describe the nature of the spell and also have perks when used with certain wands.", + + "#colour_fireFire#colour_reset \nPerhaps the most destructive element, fire concerns burning, lava, and explosions. A powerful pyromancer will unleash hell upon their enemies and probably set the world alight in the process. Most fire attack spells set fire to their target, causing ongoing damage over time. However, be wary that fire spells may have no effect on nether mobs.", + + "#colour_iceIce#colour_reset \nThe element of ice is made of all that is cold. Frost spells often slow enemies down or freeze them completely, and are especially effective on creatures of fire. Frost magic can prove equally useful outside of combat, such as freezing water to cross a river.", + + "#colour_lightningLightning#colour_reset \nThis element concerns lightning, storms, and the weather. A powerful storm mage is a force to be reckoned with, and some posess the ability to call down lightning at will. Lightning spells often damage multiple enemies at once and usually seek their target, making them an effective attack against any mob... but beware of creepers.", + + "#colour_necromancyNecromancy#colour_reset \nNecromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon creatures to fight for you or even bend the will of your enemies.", + + "#colour_earthEarth#colour_reset \nThe element of earth is focused on the natural world: animals, plants, the wind, and such like. Earth magic is diverse and takes a wide variety of forms, from poisoning enemies to unleashing the fury of the weather. Earth spells are a mixture of attack, defence and utility.", + + "#colour_sorcerySorcery#colour_reset \nSorcery is the element of force and change. Sorcerers manipulate light, gravity and even reality itself to fit their needs. Sorcery spells can be used, among other things, to grant their caster magical powers or move objects to their will.", + + "#colour_healingHealing#colour_reset \nThe element of healing is concerned with defence and regeneration. Healers seek to protect themselves and their allies as much as possible and as such can be very difficult opponents. Though generally not used as an attack, the purifying light of some healing spells will do considerable damage to the undead. Healing spells are indispensable when in combat.", + + "The boundaries between the different elements are not always distinct, and some spells bear traits of elements other than their own.", + + "If you are lucky, you may happen upon an elemental wand. These wands will allow you to cast spells of the right element for more potency than usual." + ] + }, + + "growing_crystals": { + "title": "Growing Crystals", + "include_in_contents": "main_contents", + "text": [ + + "Magic crystals normally form naturally underground over thousands of years, by gradually drawing latent mana from the surrounding rock as they grow. Crystalline structures are very good at absorbing and holding mana, hence the mana is naturally drawn towards them. Given the right conditions, however, it is possible to greatly speed up this process. This has given rise to the advanced technique of crystal growing, which requires both great patience and attention to detail.", + + "In order to encourage crystal growth, one must begin with a crystal seed. The most effective seeds have proven to be crystal shards, obtained by simply shattering a magic crystal into pieces. A crystal seed must then be planted into some kind of substrate, usually rock, although other materials are also viable. Left alone, this would produce a sizeable crystal in hundreds of years, depending on the conditions.", + + "To reduce this length of time, several things can be done. Immersing the seed and substrate in mineral-rich water helps with crystal growth, but not with concentrating mana. To concentrate mana more quickly, two techniques can be employed: firstly, surrounding the growth site with lesser mana-gathering objects allows the crystal to draw from them, meaning the surrounding environment is constantly replenished with mana. Too many, however, and they begin to draw mana away from the growing crystal. Secondly, mana can be drawn through some materials better than others: air is very poor at this, whereas dense materials tend to be much better. Some wizards have taken to experimentation with exotic, magical, or even otherworldy materials to try and improve crystal growth. Some even claim to have altered the type of crystal that is formed in this way.", + + "If conditions are exactly right, it is even possible for crystals to grow far beyond their natural size. Such crystals are known as grand magic crystals, and besides containing a great quantity of mana, they have a few specific uses." + ] + }, + + "miscellaneous": { + "title": "Miscellaneous", + "include_in_contents": "main_contents", + "contents": { + "id": "miscellaneous_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "sections": { + "mana_flasks": { + "title": "Mana Flasks", + "include_in_contents": "miscellaneous_subsections", + "text": [ + + "Arkendur's Arcane Supplies Co. - magical items for your every need!", + + "Need to recharge your wand on the go? No problem! Mana can now be bottled.** Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge.*", + + "NEW! Introducing the brand-new large*** and small mana flasks - now you can choose a size of mana flask to meet your needs!", + + "* This process will consume the bottle.", + "** Some mana is lost during bottling.", + "*** Large mana flask requires grand magic crystals." + ] + }, + "throwable_items": { + "title": "Throwable Items", + "include_in_contents": "miscellaneous_subsections", + "text": [ + + "Various spells conjure physical items, some of which can also be crafted directly. Firebombs, poison bombs, spark bombs and smoke bombs can all be crafted." + ] + }, + "automated_casting": { + "title": "Automated Casting", + "include_in_contents": "miscellaneous_subsections", + "text": [ + + "Recent experimentation has revealed that it is possible to automate spell casting, to a degree, using nothing more than a simple dispenser. Nobody is quite sure why, but it would appear that the strange properties of redstone even extend to triggering the activation of spell scrolls. Placing a few into a dispenser and powering it ought to do the trick..." + ] + } + } + }, + + "crafting_recipes": { + "title": "Crafting Recipes", + "include_in_contents": "main_contents", + "text": [ + + "#recipe arcane_workbench", + "#recipe magic_wand", + "#recipe magic_missile_spell_book", + "#recipe wizard_handbook", + "#recipe crystal_flower_to_crystals", + "#recipe mana_flask", + "#recipe transportation_stone", + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + "#recipe blank_scroll", + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb" + ] + }, + + "credits": { + "title": "Credits", + "include_in_contents": "main_contents", + "text": [ + + "Electroblob's Wizardry \nVersion #version \nFor Minecraft #mcversion", + + "For more information, check out the @https://github.com/Electroblob77/Wizardry/wiki wiki@.", + + "Designed, coded and textured by Electroblob", + + "Thanks to Minecraft Forge and MCP, without which this mod would not have been possible.", + + "Thanks also to the Minecraft modding community, which always has an answer to my modding problems!", + + "In addition, I'd like to thank the following individuals for their contributions to the mod:", + + "Code:", + + "- Corail31 \n- 12foo \n- Shadows-of-Fire", + + "Translations:", + + "- Russian: VilagVil \n- Spanish and Mexican Spanish: MadWrist \n- Chinese: ZHENGLOC", + + "Lightning ray sound effect from OhhWowProductions" + ] + } + + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json b/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json new file mode 100644 index 00000000..4c40250d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json @@ -0,0 +1,528 @@ +{ + "ruler_text": "--------------------", + + "colours": { + "text": "#000000", + "caption": "#666666", + "hyperlink": "#601ba0", + "highlight": "#dd4c1d" + }, + + "images": { + "workbench": { + "location": "ebwizardry:textures/gui/arcane_workbench_picture.png", + "caption": "The Arcane Workbench", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "crystal_ore": { + "location": "ebwizardry:textures/gui/ore_picture.png", + "caption": "Crystal Ore", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + }, + "magic_crystal": { + "location": "ebwizardry:textures/items/crystal_magic.png", + "caption": "A Magic Crystal", + "u": 6, + "v": 6, + "width": 36, + "height": 33, + "texture_width": 48, + "texture_height": 48 + }, + "magic_wand": { + "location": "ebwizardry:textures/items/wand_basic.png", + "caption": "A Magic Wand", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + }, + "crystal_flower": { + "location": "ebwizardry:textures/gui/flower_picture.png", + "caption": "A Crystal Flower", + "u": 0, + "v": 0, + "width": 64, + "height": 64 + } + }, + + "recipes": { + "arcane_workbench": { + "location": "ebwizardry:arcane_workbench" + }, + "magic_wand": { + "location": "ebwizardry:magic_wand" + }, + "magic_missile_spell_book": { + "location": "ebwizardry:magic_missile_spell_book" + }, + "wizard_handbook": { + "location": "ebwizardry:wizard_handbook" + }, + "crystal_flower_to_crystals": { + "location": "ebwizardry:crystal_flower_to_crystals" + }, + "mana_flask": { + "location": "ebwizardry:mana_flask" + }, + "transportation_stone": { + "location": "ebwizardry:transportation_stone" + }, + "magic_silk": { + "location": "ebwizardry:magic_silk" + }, + "wizard_hat": { + "location": "ebwizardry:wizard_hat" + }, + "wizard_robe": { + "location": "ebwizardry:wizard_robe" + }, + "wizard_leggings": { + "location": "ebwizardry:wizard_leggings" + }, + "wizard_boots": { + "location": "ebwizardry:wizard_boots" + }, + "blank_scroll": { + "location": "ebwizardry:blank_scroll" + }, + "firebomb": { + "location": "ebwizardry:firebomb" + }, + "poison_bomb": { + "location": "ebwizardry:poison_bomb" + }, + "smoke_bomb": { + "location": "ebwizardry:smoke_bomb" + } + }, + + "sections": { + + "inside_cover": { + "centre": { + "x": true, + "y": true + }, + "text": [ + + "The Wizard's Handbook", + + "By Electroblob" + ] + }, + + "introduction": { + "title": "Introduction", + "text": [ + + "Greetings, wizard! This book explains the many ways of the arcane and how to use them. This is no ordinary book, though - its pages will materialize before you as you discover more about the magical world.", + + "Use the arrow buttons to turn between pages, and the double-arrow buttons to quickly flip between sections. Use the central menu button to return to the main contents page.", + + "Click on any purple link text to jump straight to the relevant page. Right-click the bookmark to move it to the current page, and left-click to return to the bookmarked page." + ] + }, + + "main_contents": { + "title": "Contents", + "contents": { + "id": "main_contents", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + } + }, + + "setting_up": { + "title": "Setting Up", + "include_in_contents": "main_contents", + "text": [ + + "To get started with wizardry, you will need a few things:", + + "- A magic wand, crafted with a gold nugget, a stick, and a magic crystal.", + + "- An @arcane_workbench arcane workbench@, crafted with 3 stone, 1 lapis lazuli block, 2 magic crystals, 2 gold nuggets and 1 purple carpet.", + + "- A @spells spell@ book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, with a book and 4 magic crystals.", + + "You will also need a bunch more magic crystals to supply your wand with @mana@." + ] + }, + + "mana": { + "title": "Mana", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:crystal" + ], + "text": [ + + "Mana is the arcane energy that gives wizards their powers. It is not a physical substance in its own right; rather, it is an everpresent aura which permeates everything in the world. In particular, it manifests itself in naturally occurring crystals, which can be found embedded in rocks underground. @wands Wands@ can store mana within them, and this mana is channeled into the @spells@ that you cast. Different spells require different amounts of mana, depending on how powerful they are and how long they last.", + + "#image crystal_ore", + + "#image magic_crystal", + + "It is widely accepted that mana cannot be created or destroyed, and that when a spell is cast, the mana it channels is simply dissipated into the surroundings. Indeed, this is how the vast majority of mana exists - spread thinly throughout the world. However, to be of any use, it must be concentrated, either naturally over thousands of years, as is the case with crystals underground, or artificially - an advanced subject covered later in this book. There also exist various ways of making spells more mana-efficient and recovering some of the mana dissipated during spellcasting." + ] + }, + + "wands": { + "title": "Wands", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], + "text": [ + + "The wand is the implement of choice for a wizard. With it, you can cast any @spells spell@ provided the wand can contain its power (see @tiers Tiers@). Wands come in many different varieties but you will almost certainly start with a basic magic wand.", + + "#image magic_wand", + + "Most wands begin their life as a simple arrangement of a magic crystal of some sort attached to a wooden stick, with a gold nugget affixed to the other end. The crystal is, of course, the source of the wand's power, as it provides the focus necessary to channel @spells@. The rest of the wand is important too though, as it provides not only a means with which to hold the wand, but also a path through which @mana@ can be channeled and directed.", + + "As more spells are cast with a wand, it grows more effective at channeling @spells@, and can therefore cast spells of greater power. This effect can be discerned from subtle changes that occur in the shape and appearance of the wand itself: as a wand grows more powerful, its crystal will become more vibrant, it may change in color depending on its element, and after a while, the wood from which it is made will start to grow and twist into more complex shapes.", + + "When holding a wand, a small heads-up display will show in the corner of the screen. This indicates the spell that is currently selected along with a pictorial representation of it, and, if the spell has been cast, a cooldown bar indicating the time until that spell can be cast again. It also shows the names of the next and previous spells bound to the wand. To switch between spells, use the #next_spell_key and #previous_spell_key keys (these can be changed in options -> controls). You can also switch spells by scrolling the mouse wheel while sneaking.", + + "When viewing an inventory, hovering over a wand will display how much @mana@ is stored in it, along with its currently selected @spells spell@ and any specific abilities it may have. More in-depth information about a wand can be viewed by placing it in an @arcane_workbench arcane workbench@." + ] + }, + + "spells": { + "title": "Spells", + "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/spells" + ], + "text": [ + + "A @wands wand@ is useless without spells to cast with it. Spells are recorded in two forms: in books, which are permanent, and in scrolls, which are temporary.", + + "Spell books are of little use on their own; instead they are used to bind the spell they contain to @wands@. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more detailed information about the spell.", + + "Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself by crafting a blank scroll from a piece of paper and some string. You can then bind a spell to the scroll using the @arcane_workbench arcane workbench@, but only if you have knowledge of that spell (see @enchanting_scrolls Enchanting Scrolls@). Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your @wands wand@. It should be noted, however, that scrolls are at best an inefficient method of casting spells.", + + "To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right-clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification in the process." + ] + }, + + "arcane_workbench": { + "title": "Arcane Workbench", + "include_in_contents": "main_contents", + "contents": { + "id": "arcane_workbench_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], + "text": [ + + "The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind @spells@ to your @wands wand@. Simply place it anywhere and right click, and you will see something like this:", + + "#image workbench" + ], + "sections": { + "binding_spells": { + "title": "Binding Spells", + "include_in_contents": "arcane_workbench_subsections", + "text": [ + + "To bind a spell to your wand, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press apply. You will notice that the spell book is left untouched during this process - this is because the act of spell binding does not 'take' the spell from the spell book; rather, it attunes the wand to the spell. As such, you may change the spells bound to your wand as much as you wish by simply repeating the spell binding process. You can bind up to five spells to a wand at one time, though this number may be increased with attunement upgrades." + ] + }, + "charging_wands": { + "title": "Charging Wands", + "include_in_contents": "arcane_workbench_subsections", + "text": [ + + "To charge your wand, place the wand in the central slot of the arcane workbench and place some magic crystals in the upper of the two slots on the left, and then press apply. Each crystal is worth #mana_per_crystal mana, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals so if the wand needs, for example, 30 more mana, #mana_per_crystal_minus_30 mana will be lost when charging it." + ] + }, + "upgrading_wands": { + "title": "Upgrading Wands", + "include_in_contents": "arcane_workbench_subsections", + "text": [ + + "To upgrade your wand, you will need a tome of arcana of the appropriate tier (see @tiers Tiers@) or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the lower of the two slots on the left, then press apply.", + + "Special wand upgrades improve a particular aspect of a wand. Each type of upgrade can stack up to three times, and the total number of upgrades that a wand can take depends on its tier. Upgrades cannot be removed." + ] + }, + "enchanting_scrolls": { + "title": "Enchanting Scrolls", + "include_in_contents": "arcane_workbench_subsections", + "text": [ + + "The arcane workbench can also be used to enchant spell scrolls. To do so, you will require a blank scroll, crafted from a piece of paper and some string, a spell book for your chosen spell, and enough magic crystals to provide mana to cast it. Place the crystals in the upper left-hand slot, the blank scroll in the central slot, and the spell book in the single slot that appears above it, then press apply to enchant the scroll." + ] + } + } + }, + + "wizard_armour": { + "title": "Wizard Armor", + "include_in_contents": "main_contents", + "text": [ + + "As a wizard, you will need something to protect you from the creatures you fight. No ordinary armor will do though. To make the most of your spells, you will need wizard armor: hat, robes, leggings and boots. Unlike ordinary armor, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much mana. Charge them as you would a wand in the arcane workbench or with a mana flask, but be careful - if they run out of mana, you will find yourself defenseless.", + + "You can obtain wizard armor by crafting it from magical silk, obtained by crafting string with a magic crystal.", + + "Those wizards who devote themselves to the practise of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find.", + + "Legend speaks of an arcane seal used by the most powerful wizards to greatly improve their armor." + ] + }, + + "magical_world": { + "title": "Magic in the World", + "include_in_contents": "main_contents", + "contents": { + "id": "magical_world_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "text": [ + + "One cannot master the arcane just by staying at home - there is a world full of magic out there to explore! Ancient ruins, relics and mysterious beings good and bad await discovery - if you know where to look. The greatest wizards are also the most curious, and gain much of their knowledge and power through exploration of the environment around them, and experimenting with what they find.", + + "Whilst much of a wizard's time is inevitably spent alone, the sharing of knowledge is also vital to learning the arcane arts. Seek out fellow practicioners of magic, and learn as much as you can from them: communication is arguably the greatest power of all." + ], + "sections": { + "crystal_flowers": { + "title": "Crystal Flowers", + "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/crystal_flowers" + ], + "text": [ + + "During your travels, you will probably come across curious glowing flowers growing in the wild from time to time. These distinctive blooms are known as crystal flowers, and they are strangely effective at concentrating mana - to this day, nobody is quite sure why. We do know, however, that they can be harvested and crafted to extract the mana as crystals, making them a rather useful above-ground source of mana. The amount of mana obtainable this way is limited, though, by the small size of the flowers and due to them only growing in small patches.", + + "#image crystal_flower" + ] + }, + "wizard_towers": { + "title": "Wizard Towers", + "include_in_contents": "magical_world_subsections", + "text": [ + + "Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter a tall tower or two with a distinctive pointed roof. This is the residence of a fellow wizard. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder. If, however, it is a master spell you seek, you will need to speak to a specialist.", + + "Unfortunately, there are a few wizards out there who do not welcome visitors. These wizards are typically outcasts, and are hostile to anyone crossing their path. Approach these individuals with caution, and be prepared to defend yourself against powerful magic. Defeat them however, and their knowledge is yours for the taking.", + + "It should also be noted that no wizard will take kindly to being attacked or stolen from - and will readily take the law into their own hands." + ] + }, + "obelisks": { + "title": "Obelisks", + "include_in_contents": "magical_world_subsections", + "text": [ + + "Vestiges of ancient magic are scattered throughout the world, the most notable of which are carved stone structures which bear a great many symbols and runes. These ruins are all that remain of what appears to have been some kind of ancient civilisation. Whoever, or whatever, built them, they clearly had a considerable knowledge of magic, and used it to place protective enchantments over such locations that still persist to this day.", + + "These stuctures fit broadly into two types. The first, and more common, of these are obelisks: tall spikes of carved stone, known as runestone, with an open structure at the bottom that usually contains minor arcane relics from the forgotten past. These structures are typically protected by an enchantment that summons hostile magical creatures should any human stray too close. Fend off these creatures and destroy their source, and the relics are yours." + ] + }, + "shrines": { + "title": "Shrines", + "include_in_contents": "magical_world_subsections", + "text": [ + + "The second, and rarer, kind of structure is known as a shrine. These structures consist of a circle of runestone pillars surrounding a central platform, upon which sits a chest filled with ancient artifacts. This chest is typically protected by an arcane lock enchantment, preventing anyone except the owner from opening it. The entire structure is also protected by a containment field, which prevents anything that strays too close from escaping.", + + "Due to their great arcane power and significance, not to mention the riches within, these structures are particularly attractive to any aspiring wizard - but be cautious. There are numerous reports of wizards becoming trapped within containment fields and slowly being driven insane, perhaps by claustrophobia. A growing number, however, believe such occurences to be a deliberate part of the shrine's protective magic, and that the wizards trapped within are in fact being controlled to protect the structure. A chilling prospect, surely, for anyone who dares to venture near..." + ] + }, + "creatures": { + "title": "Magical Creatures", + "include_in_contents": "magical_world_subsections", + "text": [ + + "Besides wizards, a multitude of other creatures also use magic. Many of these creatures are arcane in origin, and most can be summoned using certain magical spells. One may encounter these creatures guarding an obelisk, or perhaps a powerful summoner. Lesser arcane beings are even found occasionally in the wilderness." + ] + }, + "artefacts": { + "title": "Artifacts", + "include_in_contents": "magical_world_subsections", + "text": [ + + "When exploring a shrine, you may be lucky enough to uncover some kind of ancient magical artifact - an object capable of granting its wearer unique and powerful buffs and special powers. Three types are known to have been found: rings, which grant bonuses and effects to spells, amulets, which improve defensive abilities, and trinkets, which give utility effects. These artifacts appear to function only when worn appropriately; simply having them on one's person is insufficient." + ] + } + } + }, + + "tiers": { + "title": "Tiers", + "include_in_contents": "main_contents", + "text":[ + + "Wands and spells come in four tiers: #colour_novicenovice#colour_reset, #colour_apprenticeapprentice#colour_reset, #colour_advancedadvanced #colour_resetand #colour_mastermaster#colour_reset. Each tier is more powerful than the last.", + + "#colour_noviceNovice #colour_resetwands are the ones that can be crafted. They hold up to #novice_max_charge mana, and can only cast novice spells. Novice spells are simple enough to be cast by anyone and they do not usually cost much mana. This does not necessarily mean that they are useless at higher tiers however; their low cost makes some novice spells useful even when you have access to master spells.", + + "#colour_apprenticeApprentice #colour_resetwands are the next tier up from novice wands. They hold up to #apprentice_max_charge mana and can cast novice and apprentice spells. Apprentice spells are a little more impressive than novice spells but usually cost more.", + + "#colour_advancedAdvanced #colour_resetwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold #advanced_max_charge mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on enemies.", + + "#colour_masterMaster #colour_resetwands are the most powerful wands in existence. They hold up to #master_max_charge mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution." + ] + }, + + "elements": { + "title": "Elements", + "include_in_contents": "main_contents", + "text": [ + + "Spells belong to different elements, which describe the nature of the spell and also have perks when used with certain wands.", + + "#colour_fireFire#colour_reset \nPerhaps the most destructive element, fire concerns burning, lava, and explosions. A powerful pyromancer will unleash hell upon their enemies and probably set the world alight in the process. Most fire attack spells set fire to their target, causing ongoing damage over time. However, be wary that fire spells may have no effect on nether mobs.", + + "#colour_iceIce#colour_reset \nThe element of ice is made of all that is cold. Frost spells often slow enemies down or freeze them completely, and are especially effective on creatures of fire. Frost magic can prove equally useful outside of combat, such as freezing water to cross a river.", + + "#colour_lightningLightning#colour_reset \nThis element concerns lightning, storms, and the weather. A powerful storm mage is a force to be reckoned with, and some posess the ability to call down lightning at will. Lightning spells often damage multiple enemies at once and usually seek their target, making them an effective attack against any mob... but beware of creepers.", + + "#colour_necromancyNecromancy#colour_reset \nNecromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon creatures to fight for you or even bend the will of your enemies.", + + "#colour_earthEarth#colour_reset \nThe element of earth is focused on the natural world: animals, plants, the wind, and such like. Earth magic is diverse and takes a wide variety of forms, from poisoning enemies to unleashing the fury of the weather. Earth spells are a mixture of attack, defense and utility.", + + "#colour_sorcerySorcery#colour_reset \nSorcery is the element of force and change. Sorcerers manipulate light, gravity and even reality itself to fit their needs. Sorcery spells can be used, among other things, to grant their caster magical powers or move objects to their will.", + + "#colour_healingHealing#colour_reset \nThe element of healing is concerned with defense and regeneration. Healers seek to protect themselves and their allies as much as possible and as such can be very difficult opponents. Though generally not used as an attack, the purifying light of some healing spells will do considerable damage to the undead. Healing spells are indispensable when in combat.", + + "The boundaries between the different elements are not always distinct, and some spells bear traits of elements other than their own.", + + "If you are lucky, you may happen upon an elemental wand. These wands will allow you to cast spells of the right element for more potency than usual." + ] + }, + + "growing_crystals": { + "title": "Growing Crystals", + "include_in_contents": "main_contents", + "text": [ + + "Magic crystals normally form naturally underground over thousands of years, by gradually drawing latent mana from the surrounding rock as they grow. Crystalline structures are very good at absorbing and holding mana, hence the mana is naturally drawn towards them. Given the right conditions, however, it is possible to greatly speed up this process. This has given rise to the advanced technique of crystal growing, which requires both great patience and attention to detail.", + + "In order to encourage crystal growth, one must begin with a crystal seed. The most effective seeds have proven to be crystal shards, obtained by simply shattering a magic crystal into pieces. A crystal seed must then be planted into some kind of substrate, usually rock, although other materials are also viable. Left alone, this would produce a sizeable crystal in hundreds of years, depending on the conditions.", + + "To reduce this length of time, several things can be done. Immersing the seed and substrate in mineral-rich water helps with crystal growth, but not with concentrating mana. To concentrate mana more quickly, two techniques can be employed: firstly, surrounding the growth site with lesser mana-gathering objects allows the crystal to draw from them, meaning the surrounding environment is constantly replenished with mana. Too many, however, and they begin to draw mana away from the growing crystal. Secondly, mana can be drawn through some materials better than others: air is very poor at this, whereas dense materials tend to be much better. Some wizards have taken to experimentation with exotic, magical, or even otherworldy materials to try and improve crystal growth. Some even claim to have altered the type of crystal that is formed in this way.", + + "If conditions are exactly right, it is even possible for crystals to grow far beyond their natural size. Such crystals are known as grand magic crystals, and besides containing a great quantity of mana, they have a few specific uses." + ] + }, + + "miscellaneous": { + "title": "Miscellaneous", + "include_in_contents": "main_contents", + "contents": { + "id": "miscellaneous_subsections", + "hyperlinks": true, + "page_numbers": true, + "separator": "." + }, + "sections": { + "mana_flasks": { + "title": "Mana Flasks", + "include_in_contents": "miscellaneous_subsections", + "text": [ + + "Arkendur's Arcane Supplies Co. - magical items for your every need!", + + "Need to recharge your wand on the go? No problem! Mana can now be bottled.** Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge.*", + + "NEW! Introducing the brand-new large*** and small mana flasks - now you can choose a size of mana flask to meet your needs!", + + "* This process will consume the bottle.", + "** Some mana is lost during bottling.", + "*** Large mana flask requires grand magic crystals." + ] + }, + "throwable_items": { + "title": "Throwable Items", + "include_in_contents": "miscellaneous_subsections", + "text": [ + + "Various spells conjure physical items, some of which can also be crafted directly. Firebombs, poison bombs, spark bombs and smoke bombs can all be crafted." + ] + }, + "automated_casting": { + "title": "Automated Casting", + "include_in_contents": "miscellaneous_subsections", + "text": [ + + "Recent experimentation has revealed that it is possible to automate spell casting, to a degree, using nothing more than a simple dispenser. Nobody is quite sure why, but it would appear that the strange properties of redstone even extend to triggering the activation of spell scrolls. Placing a few into a dispenser and powering it ought to do the trick..." + ] + } + } + }, + + "crafting_recipes": { + "title": "Crafting Recipes", + "include_in_contents": "main_contents", + "text": [ + + "#recipe arcane_workbench", + "#recipe magic_wand", + "#recipe magic_missile_spell_book", + "#recipe wizard_handbook", + "#recipe crystal_flower_to_crystals", + "#recipe mana_flask", + "#recipe transportation_stone", + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + "#recipe blank_scroll", + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb" + ] + }, + + "credits": { + "title": "Credits", + "include_in_contents": "main_contents", + "text": [ + + "Electroblob's Wizardry \nVersion #version \nFor Minecraft #mcversion", + + "For more information, check out the @https://github.com/Electroblob77/Wizardry/wiki wiki@.", + + "Designed, coded and textured by Electroblob", + + "Thanks to Minecraft Forge and MCP, without which this mod would not have been possible.", + + "Thanks also to the Minecraft modding community, which always has an answer to my modding problems!", + + "In addition, I'd like to thank the following individuals for their contributions to the mod:", + + "Code:", + + "- Corail31 \n- 12foo \n- Shadows-of-Fire", + + "Translations:", + + "- Russian: VilagVil \n- Spanish and Mexican Spanish: MadWrist \n- Chinese: ZHENGLOC", + + "Lightning ray sound effect from OhhWowProductions" + ] + } + + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/arcane_workbench_picture.png b/src/main/resources/assets/ebwizardry/textures/gui/arcane_workbench_picture.png new file mode 100644 index 0000000000000000000000000000000000000000..7587aba0fedbe91dd8553f928d65a5d49193297b GIT binary patch literal 15386 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/flower_picture.png b/src/main/resources/assets/ebwizardry/textures/gui/flower_picture.png new file mode 100644 index 0000000000000000000000000000000000000000..d00b9a498e0ffd20644fd1bad376e0f4097ab356 GIT binary patch literal 86005 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

  • L3 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/handbook_recipes.png b/src/main/resources/assets/ebwizardry/textures/gui/handbook_recipes.png deleted file mode 100644 index 6aab80dcc20a1dde179b209f7f56dafe0d7a3c6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26539 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 S4{re7nd9l|=d#Wzp$P!d0Xl~O From f8cfc5941527557c10e41e7a96c7d9f960d789b2 Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 22:48:38 +0000 Subject: [PATCH 53/68] Missed in b374f71 --- .../java/electroblob/wizardry/block/BlockSpectral.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/electroblob/wizardry/block/BlockSpectral.java b/src/main/java/electroblob/wizardry/block/BlockSpectral.java index 07023985..be7e266c 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSpectral.java +++ b/src/main/java/electroblob/wizardry/block/BlockSpectral.java @@ -60,14 +60,6 @@ public class BlockSpectral extends BlockContainer { @Override public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){ - // Middle of block - ParticleBuilder.create(Type.DUST) - .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble(), pos.getZ() + random.nextDouble()) - .lifetime((int)(16.0D / (Math.random() * 0.8D + 0.2D))) - .colour(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f) - .shaded(true).spawn(world); - - // Top surface for(int i=0; i<2; i++){ ParticleBuilder.create(Type.DUST) .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble(), pos.getZ() + random.nextDouble()) From eb2abdfbe90decbd93db0e3ab3b751558f951a5a Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 22:52:45 +0000 Subject: [PATCH 54/68] Move wand and armour map retrieval methods to WizardryItems, encapsulating the underlying maps --- .../wizardry/registry/WizardryItems.java | 44 ++++++++++++++++++- .../wizardry/util/WizardryUtilities.java | 39 ---------------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/main/java/electroblob/wizardry/registry/WizardryItems.java b/src/main/java/electroblob/wizardry/registry/WizardryItems.java index a6549f63..c3ffb79f 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryItems.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryItems.java @@ -188,8 +188,8 @@ public final class WizardryItems { public static final Item identification_scroll = new ItemIdentificationScroll(); - public static final Map, Item> WAND_MAP = new HashMap<>(); - public static final Map, Item> ARMOUR_MAP = new HashMap<>(); + private static final Map, Item> WAND_MAP = new HashMap<>(); + private static final Map, Item> ARMOUR_MAP = new HashMap<>(); static { @@ -260,6 +260,46 @@ public final class WizardryItems { ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.HEALING), wizard_boots_healing); } + // TODO: These methods need a rethink. What are we trying to achieve with them? Should each use case look in the + // same pool of items? For example, might we (or someone else) want to have a wand which can generate in chests, but + // is not used by wizards? + + // I reckon this should be strictly for cases where we only ever want the standard wand set, i.e. wizards' gear, + // etc. + + /** + * Helper method to return the appropriate wand based on tier and element. As of Wizardry 2.1, this uses the + * immutable map stored in {@link WizardryItems#WAND_MAP}. Currently used for upgrading wands, for chest generation + * and to iterate through wands for charging recipes. + * + * @param tier The tier of the wand required. + * @param element The element of the wand required. Null will be converted to {@link Element#MAGIC}. + * @return The wand item which corresponds to the given element and slot, or null if no such item exists. + * @throws NullPointerException if the given tier is null. + */ + public static Item getWand(Tier tier, Element element){ + if(tier == null) throw new NullPointerException("The given tier cannot be null."); + if(element == null) element = Element.MAGIC; + return WAND_MAP.get(ImmutablePair.of(tier, element)); + } + + /** + * Helper method to return the appropriate armour item based on element and slot. As of Wizardry 2.1, this uses the + * immutable map stored in {@link WizardryItems#ARMOUR_MAP}. Currently used to iterate through armour for + * registering charging recipes and for chest generation. + * + * @param element The EnumElement of the armour required. Null will be converted to {@link Element#MAGIC}. + * @param slot EntityEquipmentSlot of the armour piece required + * @return The armour item which corresponds to the given element and slot, or null if no such item exists. + * @throws IllegalArgumentException if the given slot is not an armour slot. + */ + public static Item getArmour(Element element, EntityEquipmentSlot slot){ + if(slot == null || slot.getSlotType() != Type.ARMOR) + throw new IllegalArgumentException("Must be a valid armour slot"); + if(element == null) element = Element.MAGIC; + return ARMOUR_MAP.get(ImmutablePair.of(slot, element)); + } + /** * Sets both the registry and unlocalised names of the given item, then registers it with the given registry. Use * this instead of {@link Item#setRegistryName(String)} and {@link Item#setUnlocalizedName(String)} during diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index bcd9872c..592a3bc3 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -1056,43 +1056,4 @@ public final class WizardryUtilities { return spells.get(random.nextInt(spells.size())).id(); } - // TODO: These methods need a rethink. What are we trying to achieve with them? Should each use case look in the - // same pool of items? For example, might we (or someone else) want to have a wand which can generate in chests, but - // is not used by wizards? - - // I reckon this should be strictly for cases where we only ever want the standard wand set, i.e. wizards' gear, - // etc. - - /** - * Helper method to return the appropriate armour item based on element and slot. As of Wizardry 2.1, this uses the - * immutable map stored in {@link WizardryItems#ARMOUR_MAP}. Currently used to iterate through armour for - * registering charging recipes and for chest generation. - * - * @param element The EnumElement of the armour required. Null will be converted to {@link Element#MAGIC}. - * @param slot EntityEquipmentSlot of the armour piece required - * @return The armour item which corresponds to the given element and slot, or null if no such item exists. - * @throws IllegalArgumentException if the given slot is not an armour slot. - */ - public static Item getArmour(Element element, EntityEquipmentSlot slot){ - if(slot == null || slot.getSlotType() != Type.ARMOR) - throw new IllegalArgumentException("Must be a valid armour slot"); - if(element == null) element = Element.MAGIC; - return WizardryItems.ARMOUR_MAP.get(ImmutablePair.of(slot, element)); - } - - /** - * Helper method to return the appropriate wand based on tier and element.As of Wizardry 2.1, this uses the - * immutable map stored in {@link WizardryItems#WAND_MAP}. Currently used in the packet handler for upgrading wands, - * for chest generation and to iterate through wands for charging recipes. - * - * @param tier The tier of the wand required. - * @param element The element of the wand required. Null will be converted to {@link Element#MAGIC}. - * @return The wand item which corresponds to the given element and slot, or null if no such item exists. - * @throws NullPointerException if the given tier is null. - */ - public static Item getWand(Tier tier, Element element){ - if(tier == null) throw new NullPointerException("The given tier cannot be null."); - if(element == null) element = Element.MAGIC; - return WizardryItems.WAND_MAP.get(ImmutablePair.of(tier, element)); - } } From 212fbe51df76e0ec85fc4883306bd54d91106b1d Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 22:59:45 +0000 Subject: [PATCH 55/68] Move block, item, potion and enchantment registries over to the @ObjectHolder system and reorganise the potion classes a bit --- .../wizardry/potion/PotionDecay.java | 22 +- .../wizardry/potion/PotionFrost.java | 28 +- .../wizardry/potion/PotionMagicEffect.java | 30 +- .../potion/PotionMagicEffectParticles.java | 9 +- .../wizardry/registry/WizardryBlocks.java | 72 ++- .../registry/WizardryEnchantments.java | 19 +- .../wizardry/registry/WizardryItems.java | 523 ++++++++++-------- .../wizardry/registry/WizardryPotions.java | 191 ++++--- 8 files changed, 474 insertions(+), 420 deletions(-) diff --git a/src/main/java/electroblob/wizardry/potion/PotionDecay.java b/src/main/java/electroblob/wizardry/potion/PotionDecay.java index 91a6c854..025c9e16 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionDecay.java +++ b/src/main/java/electroblob/wizardry/potion/PotionDecay.java @@ -3,10 +3,10 @@ package electroblob.wizardry.potion; import java.util.List; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.entity.construct.EntityDecay; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; @@ -21,12 +21,10 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @Mod.EventBusSubscriber -public class PotionDecay extends Potion { - - private static final ResourceLocation ICON = new ResourceLocation(Wizardry.MODID, "textures/gui/decay_icon.png"); +public class PotionDecay extends PotionMagicEffect { public PotionDecay(boolean isBadEffect, int liquidColour){ - super(isBadEffect, liquidColour); + super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_decay.png")); // This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet. this.setPotionName("potion." + Wizardry.MODID + ":decay"); this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED, @@ -46,20 +44,6 @@ public class PotionDecay extends Potion { target.attackEntityFrom(DamageSource.WITHER, 1); } - @Override - @SideOnly(Side.CLIENT) - public void renderInventoryEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc){ - mc.renderEngine.bindTexture(ICON); - WizardryUtilities.drawTexturedRect(x + 6, y + 7, 0, 0, 18, 18, 18, 18); - } - - @Override - @SideOnly(Side.CLIENT) - public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha){ - mc.renderEngine.bindTexture(ICON); - WizardryUtilities.drawTexturedRect(x + 3, y + 3, 0, 0, 18, 18, 18, 18); - } - @SubscribeEvent public static void onLivingUpdateEvent(LivingUpdateEvent event){ diff --git a/src/main/java/electroblob/wizardry/potion/PotionFrost.java b/src/main/java/electroblob/wizardry/potion/PotionFrost.java index 2733ded4..cba91fd6 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionFrost.java +++ b/src/main/java/electroblob/wizardry/potion/PotionFrost.java @@ -1,14 +1,13 @@ package electroblob.wizardry.potion; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; @@ -19,12 +18,10 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @Mod.EventBusSubscriber -public class PotionFrost extends Potion implements ICustomPotionParticles { - - private static final ResourceLocation ICON = new ResourceLocation(Wizardry.MODID, "textures/gui/frost_icon.png"); +public class PotionFrost extends PotionMagicEffect implements ICustomPotionParticles { public PotionFrost(boolean isBadEffect, int liquidColour){ - super(isBadEffect, liquidColour); + super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_frost.png")); // This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet. this.setPotionName("potion." + Wizardry.MODID + ":frost"); // With -0.5 as the 'amount', frost 1 slows the entity down by a half and frost 2 roots it to the spot @@ -33,27 +30,8 @@ public class PotionFrost extends Potion implements ICustomPotionParticles { // More UUIDs: 85602e0b-4801-4a87-94f3-bf617c97014e } - @Override - public void performEffect(EntityLivingBase entitylivingbase, int strength){ - // Nothing here because this potion works on attribute modifiers. - } - @Override public void spawnCustomParticle(World world, double x, double y, double z){ - } - - @Override - @SideOnly(Side.CLIENT) - public void renderInventoryEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc){ - mc.renderEngine.bindTexture(ICON); - WizardryUtilities.drawTexturedRect(x + 6, y + 7, 0, 0, 18, 18, 18, 18); - } - - @Override - @SideOnly(Side.CLIENT) - public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha){ - mc.renderEngine.bindTexture(ICON); - WizardryUtilities.drawTexturedRect(x + 3, y + 3, 0, 0, 18, 18, 18, 18); ParticleBuilder.create(Type.SNOW).pos(x, y, z).time(15 + world.rand.nextInt(5)).spawn(world); } diff --git a/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java b/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java index 02e6bc7a..cf7f5820 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java +++ b/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java @@ -1,7 +1,6 @@ package electroblob.wizardry.potion; -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.client.DrawingUtils; import net.minecraft.entity.EntityLivingBase; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; @@ -9,15 +8,17 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -/** Class for all potions that work on events only. */ +/** + * As of Wizardry 4.2, this class is used by all of wizardry's potions. Potions that work solely on events + * instantiate this class directly, all other potions extend it. + */ public class PotionMagicEffect extends Potion { - private static final ResourceLocation ICONS = new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons.png"); - private final int textureIndex; + private final ResourceLocation texture; - public PotionMagicEffect(boolean isBadEffect, int liquidColour, int textureIndex){ + public PotionMagicEffect(boolean isBadEffect, int liquidColour, ResourceLocation texture){ super(isBadEffect, liquidColour); - this.textureIndex = textureIndex; + this.texture = texture; } @Override @@ -28,17 +29,20 @@ public class PotionMagicEffect extends Potion { @Override @SideOnly(Side.CLIENT) public void renderInventoryEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc){ - mc.renderEngine.bindTexture(ICONS); - WizardryUtilities.drawTexturedRect(x + 6, y + 7, 18 * (textureIndex % 4), 18 * (textureIndex / 4), 18, 18, 72, - 72); + drawIcon(x + 6, y + 7, effect, mc); } @Override @SideOnly(Side.CLIENT) public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha){ - mc.renderEngine.bindTexture(ICONS); - WizardryUtilities.drawTexturedRect(x + 3, y + 3, 18 * (textureIndex % 4), 18 * (textureIndex / 4), 18, 18, 72, - 72); + net.minecraft.client.renderer.GlStateManager.color(1, 1, 1, alpha); + drawIcon(x + 3, y + 3, effect, mc); + } + + @SideOnly(Side.CLIENT) + protected void drawIcon(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc){ + mc.renderEngine.bindTexture(texture); + DrawingUtils.drawTexturedRect(x, y, 0, 0, 18, 18, 18, 18); } } diff --git a/src/main/java/electroblob/wizardry/potion/PotionMagicEffectParticles.java b/src/main/java/electroblob/wizardry/potion/PotionMagicEffectParticles.java index 8112a43b..eea1b759 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionMagicEffectParticles.java +++ b/src/main/java/electroblob/wizardry/potion/PotionMagicEffectParticles.java @@ -1,13 +1,16 @@ package electroblob.wizardry.potion; +import net.minecraft.util.ResourceLocation; + /** * Same as {@link PotionMagicEffect}, but also implements {@link ICustomPotionParticles} to allow anonymous classes to - * extend it and add their own particles. + * extend it and add their own particles. It is advised that all other (named) classes extend and implement the + * underlying class and interface rather than extending this class. */ public abstract class PotionMagicEffectParticles extends PotionMagicEffect implements ICustomPotionParticles { - public PotionMagicEffectParticles(boolean isBadEffect, int liquidColour, int textureIndex){ - super(isBadEffect, liquidColour, textureIndex); + public PotionMagicEffectParticles(boolean isBadEffect, int liquidColour, ResourceLocation texture){ + super(isBadEffect, liquidColour, texture); } } diff --git a/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java b/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java index a88bff23..87920c4e 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java @@ -1,20 +1,13 @@ package electroblob.wizardry.registry; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.block.BlockArcaneWorkbench; -import electroblob.wizardry.block.BlockCrystalFlower; -import electroblob.wizardry.block.BlockCrystalOre; -import electroblob.wizardry.block.BlockMagicLight; -import electroblob.wizardry.block.BlockSnare; -import electroblob.wizardry.block.BlockSpectral; -import electroblob.wizardry.block.BlockStatue; -import electroblob.wizardry.block.BlockTransportationStone; -import electroblob.wizardry.block.BlockVanishingCobweb; +import electroblob.wizardry.block.*; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; import net.minecraftforge.registries.IForgeRegistry; /** @@ -23,6 +16,7 @@ import net.minecraftforge.registries.IForgeRegistry; * @author Electroblob * @since Wizardry 2.1 */ +@ObjectHolder(Wizardry.MODID) @Mod.EventBusSubscriber public final class WizardryBlocks { @@ -33,23 +27,19 @@ public final class WizardryBlocks { // setSoundType should be public, but in this particular version it isn't... which is a bit of a pain. - public static final Block arcane_workbench = new BlockArcaneWorkbench().setHardness(1.0F).setCreativeTab(WizardryTabs.WIZARDRY); - public static final Block crystal_ore = new BlockCrystalOre(Material.ROCK).setHardness(3.0F).setCreativeTab(WizardryTabs.WIZARDRY); - public static final Block petrified_stone = new BlockStatue(Material.ROCK).setHardness(1.5F).setResistance(10.0F); - public static final Block ice_statue = new BlockStatue(Material.ICE).setHardness(0.5F).setLightOpacity(3); - public static final Block magic_light = new BlockMagicLight(Material.CIRCUITS); - public static final Block crystal_flower = new BlockCrystalFlower(Material.PLANTS).setHardness(0.0F).setCreativeTab(WizardryTabs.WIZARDRY); - public static final Block snare = new BlockSnare(Material.PLANTS).setHardness(0.0F); - public static final Block transportation_stone = new BlockTransportationStone(Material.ROCK).setHardness(0.3F).setLightLevel(0.5f).setLightOpacity(0).setCreativeTab(WizardryTabs.WIZARDRY); - public static final Block spectral_block = new BlockSpectral(Material.GLASS).setLightLevel(0.7f).setLightOpacity(0).setBlockUnbreakable().setResistance(6000000.0F); - public static final Block crystal_block = new Block(Material.IRON).setHardness(5.0F).setResistance(10.0F).setCreativeTab(WizardryTabs.WIZARDRY); - public static final Block meteor = new Block(Material.ROCK).setLightLevel(1); - public static final Block vanishing_cobweb = new BlockVanishingCobweb(Material.WEB).setLightOpacity(1).setHardness(4.0F); - - static{ - // This is here because Block#setHarvestLevel isn't chainable. - crystal_block.setHarvestLevel("pickaxe", 2); - } + public static final Block arcane_workbench = null; + public static final Block crystal_ore = null; + public static final Block petrified_stone = null; + public static final Block ice_statue = null; + public static final Block magic_light = null; + public static final Block crystal_flower = null; + public static final Block snare = null; + public static final Block transportation_stone = null; + public static final Block spectral_block = null; + public static final Block crystal_block = null; + public static final Block meteor = null; + public static final Block vanishing_cobweb = null; + public static final Block runestone = null; /** * Sets both the registry and unlocalised names of the given block, then registers it with the given registry. Use @@ -57,11 +47,11 @@ public final class WizardryBlocks { * construction, for convenience and consistency. * * @param registry The registry to register the given block to. - * @param item The block to register. * @param name The name of the block, without the mod ID or the .name stuff. The registry name will be * {@code ebwizardry:[name]}. The unlocalised name will be {@code tile.ebwizardry:[name].name}. + * @param item The block to register. */ - public static void registerBlock(IForgeRegistry registry, Block block, String name){ + public static void registerBlock(IForgeRegistry registry, String name, Block block){ block.setRegistryName(Wizardry.MODID, name); block.setUnlocalizedName(block.getRegistryName().toString()); registry.register(block); @@ -71,18 +61,20 @@ public final class WizardryBlocks { public static void register(RegistryEvent.Register event){ IForgeRegistry registry = event.getRegistry(); + + registerBlock(registry, "arcane_workbench", new BlockArcaneWorkbench().setHardness(1.0F).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "crystal_ore", new BlockCrystalOre(Material.ROCK).setHardness(3.0F).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "petrified_stone", new BlockStatue(Material.ROCK).setHardness(1.5F).setResistance(10.0F)); + registerBlock(registry, "ice_statue", new BlockStatue(Material.ICE).setHardness(0.5F).setLightOpacity(3)); + registerBlock(registry, "magic_light", new BlockMagicLight(Material.CIRCUITS)); + registerBlock(registry, "crystal_flower", new BlockCrystalFlower(Material.PLANTS).setHardness(0.0F).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "snare", new BlockSnare(Material.PLANTS).setHardness(0.0F)); + registerBlock(registry, "transportation_stone", new BlockTransportationStone(Material.ROCK).setHardness(0.3F).setLightLevel(0.5f).setLightOpacity(0).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "spectral_block", new BlockSpectral(Material.GLASS).setLightLevel(0.7f).setLightOpacity(0).setBlockUnbreakable().setResistance(6000000.0F)); + registerBlock(registry, "crystal_block", new BlockCrystal(Material.IRON).setHardness(5.0F).setResistance(10.0F).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "meteor", new Block(Material.ROCK).setLightLevel(1)); + registerBlock(registry, "vanishing_cobweb", new BlockVanishingCobweb(Material.WEB).setLightOpacity(1).setHardness(4.0F)); + registerBlock(registry, "runestone", new BlockRunestone(Material.ROCK)); - registerBlock(registry, arcane_workbench, "arcane_workbench"); - registerBlock(registry, crystal_ore, "crystal_ore"); - registerBlock(registry, petrified_stone, "petrified_stone"); - registerBlock(registry, ice_statue, "ice_statue"); - registerBlock(registry, magic_light, "magic_light"); - registerBlock(registry, crystal_flower, "crystal_flower"); - registerBlock(registry, snare, "snare"); - registerBlock(registry, transportation_stone, "transportation_stone"); - registerBlock(registry, spectral_block, "spectral_block"); - registerBlock(registry, crystal_block, "crystal_block"); - registerBlock(registry, meteor, "meteor"); - registerBlock(registry, vanishing_cobweb, "vanishing_cobweb"); } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java b/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java index 2c3ba970..66c8789c 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java @@ -26,20 +26,17 @@ public final class WizardryEnchantments { // All of these have custom classes, so the unlocalised name (referred to simply as 'name' for enchantments) is // dealt with inside those classes. - public static final Enchantment magic_sword = new EnchantmentMagicSword().setRegistryName(Wizardry.MODID, - "magic_sword"); - public static final Enchantment magic_bow = new EnchantmentTimed().setRegistryName(Wizardry.MODID, "magic_bow"); - public static final Enchantment flaming_weapon = new EnchantmentTimed().setRegistryName(Wizardry.MODID, - "flaming_weapon"); - public static final Enchantment freezing_weapon = new EnchantmentTimed().setRegistryName(Wizardry.MODID, - "freezing_weapon"); + public static final Enchantment magic_sword = null; + public static final Enchantment magic_bow = null; + public static final Enchantment flaming_weapon = null; + public static final Enchantment freezing_weapon = null; @SubscribeEvent public static void register(RegistryEvent.Register event){ - event.getRegistry().register(magic_sword); - event.getRegistry().register(magic_bow); - event.getRegistry().register(flaming_weapon); - event.getRegistry().register(freezing_weapon); + event.getRegistry().register(new EnchantmentMagicSword().setRegistryName(Wizardry.MODID, "magic_sword")); + event.getRegistry().register(new EnchantmentTimed().setRegistryName(Wizardry.MODID, "magic_bow")); + event.getRegistry().register(new EnchantmentTimed().setRegistryName(Wizardry.MODID, "flaming_weapon")); + event.getRegistry().register(new EnchantmentTimed().setRegistryName(Wizardry.MODID, "freezing_weapon")); } } diff --git a/src/main/java/electroblob/wizardry/registry/WizardryItems.java b/src/main/java/electroblob/wizardry/registry/WizardryItems.java index c3ffb79f..c1ae9776 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryItems.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryItems.java @@ -40,6 +40,7 @@ import net.minecraftforge.common.util.EnumHelper; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; import net.minecraftforge.registries.IForgeRegistry; /** @@ -49,144 +50,145 @@ import net.minecraftforge.registries.IForgeRegistry; * @author Electroblob * @since Wizardry 2.1 */ +@ObjectHolder(Wizardry.MODID) @Mod.EventBusSubscriber public final class WizardryItems { - - public static final Item magic_crystal = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - - public static final Item magic_wand = new ItemWand(Tier.BASIC, null); - public static final Item apprentice_wand = new ItemWand(Tier.APPRENTICE, null); - public static final Item advanced_wand = new ItemWand(Tier.ADVANCED, null); - public static final Item master_wand = new ItemWand(Tier.MASTER, null); - - public static final Item arcane_tome = new ItemArcaneTome(); - public static final Item wizard_handbook = new ItemWizardHandbook(); - public static final Item spell_book = new ItemSpellBook(); - - public static final Item basic_fire_wand = new ItemWand(Tier.BASIC, Element.FIRE); - public static final Item basic_ice_wand = new ItemWand(Tier.BASIC, Element.ICE); - public static final Item basic_lightning_wand = new ItemWand(Tier.BASIC, Element.LIGHTNING); - public static final Item basic_necromancy_wand = new ItemWand(Tier.BASIC, Element.NECROMANCY); - public static final Item basic_earth_wand = new ItemWand(Tier.BASIC, Element.EARTH); - public static final Item basic_sorcery_wand = new ItemWand(Tier.BASIC, Element.SORCERY); - public static final Item basic_healing_wand = new ItemWand(Tier.BASIC, Element.HEALING); - - public static final Item apprentice_fire_wand = new ItemWand(Tier.APPRENTICE, Element.FIRE); - public static final Item apprentice_ice_wand = new ItemWand(Tier.APPRENTICE, Element.ICE); - public static final Item apprentice_lightning_wand = new ItemWand(Tier.APPRENTICE, Element.LIGHTNING); - public static final Item apprentice_necromancy_wand = new ItemWand(Tier.APPRENTICE, Element.NECROMANCY); - public static final Item apprentice_earth_wand = new ItemWand(Tier.APPRENTICE, Element.EARTH); - public static final Item apprentice_sorcery_wand = new ItemWand(Tier.APPRENTICE, Element.SORCERY); - public static final Item apprentice_healing_wand = new ItemWand(Tier.APPRENTICE, Element.HEALING); - - public static final Item advanced_fire_wand = new ItemWand(Tier.ADVANCED, Element.FIRE); - public static final Item advanced_ice_wand = new ItemWand(Tier.ADVANCED, Element.ICE); - public static final Item advanced_lightning_wand = new ItemWand(Tier.ADVANCED, Element.LIGHTNING); - public static final Item advanced_necromancy_wand = new ItemWand(Tier.ADVANCED, Element.NECROMANCY); - public static final Item advanced_earth_wand = new ItemWand(Tier.ADVANCED, Element.EARTH); - public static final Item advanced_sorcery_wand = new ItemWand(Tier.ADVANCED, Element.SORCERY); - public static final Item advanced_healing_wand = new ItemWand(Tier.ADVANCED, Element.HEALING); - - public static final Item master_fire_wand = new ItemWand(Tier.MASTER, Element.FIRE); - public static final Item master_ice_wand = new ItemWand(Tier.MASTER, Element.ICE); - public static final Item master_lightning_wand = new ItemWand(Tier.MASTER, Element.LIGHTNING); - public static final Item master_necromancy_wand = new ItemWand(Tier.MASTER, Element.NECROMANCY); - public static final Item master_earth_wand = new ItemWand(Tier.MASTER, Element.EARTH); - public static final Item master_sorcery_wand = new ItemWand(Tier.MASTER, Element.SORCERY); - public static final Item master_healing_wand = new ItemWand(Tier.MASTER, Element.HEALING); - - public static final Item spectral_sword = new ItemSpectralSword(ToolMaterial.IRON); - public static final Item spectral_pickaxe = new ItemSpectralPickaxe(ToolMaterial.IRON); - public static final Item spectral_bow = new ItemSpectralBow(); - - public static final Item mana_flask = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - - public static final Item storage_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - public static final Item siphon_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - public static final Item condenser_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - public static final Item range_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - public static final Item duration_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - public static final Item cooldown_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - public static final Item blast_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - public static final Item attunement_upgrade = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - - public static final Item magic_silk = new Item().setCreativeTab(WizardryTabs.WIZARDRY); - - public static final Item.ToolMaterial MAGICAL = EnumHelper.addToolMaterial("MAGICAL", 3, 1000, 8.0f, 4.0f, 0); - - public static final Item flaming_axe = new ItemFlamingAxe(MAGICAL); - public static final Item frost_axe = new ItemFrostAxe(MAGICAL); - - public static final Item firebomb = new ItemFirebomb(); - public static final Item poison_bomb = new ItemPoisonBomb(); - - public static final Item blank_scroll = new ItemBlankScroll(); - public static final Item scroll = new ItemScroll(); - - // The only way to get these is in dungeon chests (They are legendary, after all. Wizards don't just have them. - // Also if they were sold you could buy four from the same wizard - and that's no fun at all!) - public static final Item armour_upgrade = new ItemArmourUpgrade(); - - public static final ArmorMaterial SILK = EnumHelper.addArmorMaterial("SILK", - "wizardry/textures/armour/wizard_armour", 15, new int[]{0, 0, 0, 0}, 0, - SoundEvents.ITEM_ARMOR_EQUIP_LEATHER, 0.0F); - // Saw a post somewhere that said you have to put these in the init methods rather than defining them as constants. - // I *think* that's because the post was for a newer Minecraft version, where custom armour has its own renderer or - // something, meaning it would be done a lot like the entity rendering registry in ClientProxy. This is all working - // fine it seems, so I'm not going to fiddle with it, but it might be useful to know if I update versions again. - public static final Item wizard_hat = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, null); - public static final Item wizard_robe = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, null); - public static final Item wizard_leggings = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, null); - public static final Item wizard_boots = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, null); + /** Keeping the material fields in here means {@code @ObjectHolder} ignores them. In actual fact, I could have just + * made them private since wizardry only uses them within this class, but in case someone needs them elsewhere I've + * used this trick instead to keep them public. */ + public static final class Materials { - public static final Item wizard_hat_fire = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.FIRE); - public static final Item wizard_robe_fire = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.FIRE); - public static final Item wizard_leggings_fire = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.FIRE); - public static final Item wizard_boots_fire = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.FIRE); - - public static final Item wizard_hat_ice = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.ICE); - public static final Item wizard_robe_ice = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.ICE); - public static final Item wizard_leggings_ice = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.ICE); - public static final Item wizard_boots_ice = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.ICE); - - public static final Item wizard_hat_lightning = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.LIGHTNING); - public static final Item wizard_robe_lightning = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.LIGHTNING); - public static final Item wizard_leggings_lightning = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.LIGHTNING); - public static final Item wizard_boots_lightning = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.LIGHTNING); - - public static final Item wizard_hat_necromancy = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.NECROMANCY); - public static final Item wizard_robe_necromancy = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.NECROMANCY); - public static final Item wizard_leggings_necromancy = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.NECROMANCY); - public static final Item wizard_boots_necromancy = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.NECROMANCY); - - public static final Item wizard_hat_earth = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.EARTH); - public static final Item wizard_robe_earth = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.EARTH); - public static final Item wizard_leggings_earth = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.EARTH); - public static final Item wizard_boots_earth = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.EARTH); - - public static final Item wizard_hat_sorcery = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.SORCERY); - public static final Item wizard_robe_sorcery = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.SORCERY); - public static final Item wizard_leggings_sorcery = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.SORCERY); - public static final Item wizard_boots_sorcery = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.SORCERY); - - public static final Item wizard_hat_healing = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.HEAD, Element.HEALING); - public static final Item wizard_robe_healing = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.CHEST, Element.HEALING); - public static final Item wizard_leggings_healing = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.LEGS, Element.HEALING); - public static final Item wizard_boots_healing = new ItemWizardArmour(SILK, 1, EntityEquipmentSlot.FEET, Element.HEALING); - - public static final Item spectral_helmet = new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.HEAD); - public static final Item spectral_chestplate = new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.CHEST); - public static final Item spectral_leggings = new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.LEGS); - public static final Item spectral_boots = new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.FEET); - - public static final Map SPECTRAL_ARMOUR_MAP = ImmutableMap.of( - EntityEquipmentSlot.HEAD, spectral_helmet, EntityEquipmentSlot.CHEST, spectral_chestplate, - EntityEquipmentSlot.LEGS, spectral_leggings, EntityEquipmentSlot.FEET, spectral_boots); + public static final ToolMaterial MAGICAL = EnumHelper.addToolMaterial("MAGICAL", 3, 1000, 8.0f, 4.0f, 0); + + public static final ArmorMaterial SILK = EnumHelper.addArmorMaterial("SILK", "wizardry/textures/armour/wizard_armour", + 15, new int[]{0, 0, 0, 0}, 0, WizardrySounds.ITEM_ARMOUR_EQUIP_SILK, 0.0F); + + } - public static final Item smoke_bomb = new ItemSmokeBomb(); + // This is the most concise way I can think of to register the items. Really, I'd prefer it if there was only one + // point where all the items were listed, but that's not possible within the current system unless you use an array, + // which means you lose the individual fields... - public static final Item identification_scroll = new ItemIdentificationScroll(); + public static final Item magic_crystal = null; + + public static final Item magic_wand = null; + public static final Item apprentice_wand = null; + public static final Item advanced_wand = null; + public static final Item master_wand = null; + + public static final Item arcane_tome = null; + public static final Item wizard_handbook = null; + public static final Item spell_book = null; + + public static final Item basic_fire_wand = null; + public static final Item basic_ice_wand = null; + public static final Item basic_lightning_wand = null; + public static final Item basic_necromancy_wand = null; + public static final Item basic_earth_wand = null; + public static final Item basic_sorcery_wand = null; + public static final Item basic_healing_wand = null; + + public static final Item apprentice_fire_wand = null; + public static final Item apprentice_ice_wand = null; + public static final Item apprentice_lightning_wand = null; + public static final Item apprentice_necromancy_wand = null; + public static final Item apprentice_earth_wand = null; + public static final Item apprentice_sorcery_wand = null; + public static final Item apprentice_healing_wand = null; + + public static final Item advanced_fire_wand = null; + public static final Item advanced_ice_wand = null; + public static final Item advanced_lightning_wand = null; + public static final Item advanced_necromancy_wand = null; + public static final Item advanced_earth_wand = null; + public static final Item advanced_sorcery_wand = null; + public static final Item advanced_healing_wand = null; + + public static final Item master_fire_wand = null; + public static final Item master_ice_wand = null; + public static final Item master_lightning_wand = null; + public static final Item master_necromancy_wand = null; + public static final Item master_earth_wand = null; + public static final Item master_sorcery_wand = null; + public static final Item master_healing_wand = null; + + public static final Item spectral_sword = null; + public static final Item spectral_pickaxe = null; + public static final Item spectral_bow = null; + + public static final Item medium_mana_flask = null; + + public static final Item storage_upgrade = null; + public static final Item siphon_upgrade = null; + public static final Item condenser_upgrade = null; + public static final Item range_upgrade = null; + public static final Item duration_upgrade = null; + public static final Item cooldown_upgrade = null; + public static final Item blast_upgrade = null; + public static final Item attunement_upgrade = null; + + public static final Item magic_silk = null; + + public static final Item flaming_axe = null; + public static final Item frost_axe = null; + + public static final Item firebomb = null; + public static final Item poison_bomb = null; + + public static final Item blank_scroll = null; + public static final Item scroll = null; + + public static final Item armour_upgrade = null; + + public static final Item wizard_hat = null; + public static final Item wizard_robe = null; + public static final Item wizard_leggings = null; + public static final Item wizard_boots = null; + + public static final Item wizard_hat_fire = null; + public static final Item wizard_robe_fire = null; + public static final Item wizard_leggings_fire = null; + public static final Item wizard_boots_fire = null; + + public static final Item wizard_hat_ice = null; + public static final Item wizard_robe_ice = null; + public static final Item wizard_leggings_ice = null; + public static final Item wizard_boots_ice = null; + + public static final Item wizard_hat_lightning = null; + public static final Item wizard_robe_lightning = null; + public static final Item wizard_leggings_lightning = null; + public static final Item wizard_boots_lightning = null; + + public static final Item wizard_hat_necromancy = null; + public static final Item wizard_robe_necromancy = null; + public static final Item wizard_leggings_necromancy = null; + public static final Item wizard_boots_necromancy = null; + + public static final Item wizard_hat_earth = null; + public static final Item wizard_robe_earth = null; + public static final Item wizard_leggings_earth = null; + public static final Item wizard_boots_earth = null; + + public static final Item wizard_hat_sorcery = null; + public static final Item wizard_robe_sorcery = null; + public static final Item wizard_leggings_sorcery = null; + public static final Item wizard_boots_sorcery = null; + + public static final Item wizard_hat_healing = null; + public static final Item wizard_robe_healing = null; + public static final Item wizard_leggings_healing = null; + public static final Item wizard_boots_healing = null; + + public static final Item spectral_helmet = null; + public static final Item spectral_chestplate = null; + public static final Item spectral_leggings = null; + public static final Item spectral_boots = null; + + public static final Item smoke_bomb = null; + + public static final Item identification_scroll = null; private static final Map, Item> WAND_MAP = new HashMap<>(); private static final Map, Item> ARMOUR_MAP = new HashMap<>(); @@ -303,23 +305,60 @@ public final class WizardryItems { /** * Sets both the registry and unlocalised names of the given item, then registers it with the given registry. Use * this instead of {@link Item#setRegistryName(String)} and {@link Item#setUnlocalizedName(String)} during - * construction, for convenience and consistency. + * construction, for convenience and consistency. As of wizardry 4.2, this also automatically adds it to the order + * list for its creative tab if that tab is a {@link CreativeTabListed}, meaning the order can be defined simply + * by the order in which the items are registered in this class. * * @param registry The registry to register the given item to. - * @param item The item to register. * @param name The name of the item, without the mod ID or the .name stuff. The registry name will be * {@code ebwizardry:[name]}. The unlocalised name will be {@code item.ebwizardry:[name].name}. + * @param item The item to register. */ - public static void registerItem(IForgeRegistry registry, Item item, String name){ + // It now makes sense to have the name first, since it's shorter than an entire item declaration. + public static void registerItem(IForgeRegistry registry, String name, Item item){ + registerItem(registry, name, item, false); + } + + /** + * Sets both the registry and unlocalised names of the given item, then registers it with the given registry. Use + * this instead of {@link Item#setRegistryName(String)} and {@link Item#setUnlocalizedName(String)} during + * construction, for convenience and consistency. As of wizardry 4.2, this also automatically adds it to the order + * list for its creative tab if that tab is a {@link CreativeTabListed}, meaning the order can be defined simply + * by the order in which the items are registered in this class. + * + * @param registry The registry to register the given item to. + * @param name The name of the item, without the mod ID or the .name stuff. The registry name will be + * {@code ebwizardry:[name]}. The unlocalised name will be {@code item.ebwizardry:[name].name}. + * @param item The item to register. + * @param setTabIcon True to set this item as the icon for its creative tab. + */ + // It now makes sense to have the name first, since it's shorter than an entire item declaration. + public static void registerItem(IForgeRegistry registry, String name, Item item, boolean setTabIcon){ item.setRegistryName(Wizardry.MODID, name); item.setUnlocalizedName(item.getRegistryName().toString()); registry.register(item); + + if(setTabIcon && item.getCreativeTab() instanceof CreativeTabSorted){ + ((CreativeTabSorted)item.getCreativeTab()).setIconItem(new ItemStack(item)); + } + + if(item.getCreativeTab() instanceof CreativeTabListed){ + ((CreativeTabListed)item.getCreativeTab()).order.add(item); + } } - /** Registers an ItemBlock afor the given block, with the same registry name as that block. */ + /** Registers an ItemBlock for the given block, with the same registry name as that block. As of wizardry 4.2, this + * also automatically adds it to the order list for its creative tab if that tab is a {@link CreativeTabListed}, + * meaning the order can be defined simply by the order in which the items are registered in this class. */ private static void registerItemBlock(IForgeRegistry registry, Block block){ - // We don't need to keep a reference to the ItemBlock, so this can all be done in one line. - registry.register(new ItemBlock(block).setRegistryName(block.getRegistryName())); + // We don't need to keep a reference to the ItemBlock + Item itemblock = new ItemBlock(block).setRegistryName(block.getRegistryName()); + registry.register(itemblock); + + if(block.getCreativeTabToDisplayOn() instanceof CreativeTabListed){ + ((CreativeTabListed)block.getCreativeTabToDisplayOn()).order.add(itemblock); + } + } } @SubscribeEvent @@ -336,126 +375,134 @@ public final class WizardryItems { registerItemBlock(registry, WizardryBlocks.crystal_block); // Items + + registerItem(registry, "magic_crystal", new ItemCrystal()); - registerItem(registry, magic_crystal, "magic_crystal"); + registerItem(registry, "magic_wand", new ItemWand(Tier.BASIC, null)); + registerItem(registry, "apprentice_wand", new ItemWand(Tier.APPRENTICE, null)); + registerItem(registry, "advanced_wand", new ItemWand(Tier.ADVANCED, null)); + registerItem(registry, "master_wand", new ItemWand(Tier.MASTER, null)); - registerItem(registry, magic_wand, "magic_wand"); - registerItem(registry, apprentice_wand, "apprentice_wand"); - registerItem(registry, advanced_wand, "advanced_wand"); - registerItem(registry, master_wand, "master_wand"); + registerItem(registry, "arcane_tome", new ItemArcaneTome()); + registerItem(registry, "wizard_handbook", new ItemWizardHandbook(), true); + registerItem(registry, "spell_book", new ItemSpellBook(), true); - registerItem(registry, spell_book, "spell_book"); - registerItem(registry, arcane_tome, "arcane_tome"); - registerItem(registry, wizard_handbook, "wizard_handbook"); + registerItem(registry, "basic_fire_wand", new ItemWand(Tier.BASIC, Element.FIRE)); + registerItem(registry, "apprentice_fire_wand", new ItemWand(Tier.APPRENTICE, Element.FIRE)); + registerItem(registry, "advanced_fire_wand", new ItemWand(Tier.ADVANCED, Element.FIRE)); + registerItem(registry, "master_fire_wand", new ItemWand(Tier.MASTER, Element.FIRE)); + + registerItem(registry, "basic_ice_wand", new ItemWand(Tier.BASIC, Element.ICE)); + registerItem(registry, "apprentice_ice_wand", new ItemWand(Tier.APPRENTICE, Element.ICE)); + registerItem(registry, "advanced_ice_wand", new ItemWand(Tier.ADVANCED, Element.ICE)); + registerItem(registry, "master_ice_wand", new ItemWand(Tier.MASTER, Element.ICE)); + + registerItem(registry, "basic_lightning_wand", new ItemWand(Tier.BASIC, Element.LIGHTNING)); + registerItem(registry, "apprentice_lightning_wand", new ItemWand(Tier.APPRENTICE, Element.LIGHTNING)); + registerItem(registry, "advanced_lightning_wand", new ItemWand(Tier.ADVANCED, Element.LIGHTNING)); + registerItem(registry, "master_lightning_wand", new ItemWand(Tier.MASTER, Element.LIGHTNING)); + + registerItem(registry, "basic_necromancy_wand", new ItemWand(Tier.BASIC, Element.NECROMANCY)); + registerItem(registry, "apprentice_necromancy_wand", new ItemWand(Tier.APPRENTICE, Element.NECROMANCY)); + registerItem(registry, "advanced_necromancy_wand", new ItemWand(Tier.ADVANCED, Element.NECROMANCY)); + registerItem(registry, "master_necromancy_wand", new ItemWand(Tier.MASTER, Element.NECROMANCY)); + + registerItem(registry, "basic_earth_wand", new ItemWand(Tier.BASIC, Element.EARTH)); + registerItem(registry, "apprentice_earth_wand", new ItemWand(Tier.APPRENTICE, Element.EARTH)); + registerItem(registry, "advanced_earth_wand", new ItemWand(Tier.ADVANCED, Element.EARTH)); + registerItem(registry, "master_earth_wand", new ItemWand(Tier.MASTER, Element.EARTH)); + + registerItem(registry, "basic_sorcery_wand", new ItemWand(Tier.BASIC, Element.SORCERY)); + registerItem(registry, "apprentice_sorcery_wand", new ItemWand(Tier.APPRENTICE, Element.SORCERY)); + registerItem(registry, "advanced_sorcery_wand", new ItemWand(Tier.ADVANCED, Element.SORCERY)); + registerItem(registry, "master_sorcery_wand", new ItemWand(Tier.MASTER, Element.SORCERY)); + + registerItem(registry, "basic_healing_wand", new ItemWand(Tier.BASIC, Element.HEALING)); + registerItem(registry, "apprentice_healing_wand", new ItemWand(Tier.APPRENTICE, Element.HEALING)); + registerItem(registry, "advanced_healing_wand", new ItemWand(Tier.ADVANCED, Element.HEALING)); + registerItem(registry, "master_healing_wand", new ItemWand(Tier.MASTER, Element.HEALING)); - registerItem(registry, basic_fire_wand, "basic_fire_wand"); - registerItem(registry, basic_ice_wand, "basic_ice_wand"); - registerItem(registry, basic_lightning_wand, "basic_lightning_wand"); - registerItem(registry, basic_necromancy_wand, "basic_necromancy_wand"); - registerItem(registry, basic_earth_wand, "basic_earth_wand"); - registerItem(registry, basic_sorcery_wand, "basic_sorcery_wand"); - registerItem(registry, basic_healing_wand, "basic_healing_wand"); + registerItem(registry, "spectral_sword", new ItemSpectralSword(ToolMaterial.IRON)); + registerItem(registry, "spectral_pickaxe", new ItemSpectralPickaxe(ToolMaterial.IRON)); + registerItem(registry, "spectral_bow", new ItemSpectralBow()); - registerItem(registry, apprentice_fire_wand, "apprentice_fire_wand"); - registerItem(registry, apprentice_ice_wand, "apprentice_ice_wand"); - registerItem(registry, apprentice_lightning_wand, "apprentice_lightning_wand"); - registerItem(registry, apprentice_necromancy_wand, "apprentice_necromancy_wand"); - registerItem(registry, apprentice_earth_wand, "apprentice_earth_wand"); - registerItem(registry, apprentice_sorcery_wand, "apprentice_sorcery_wand"); - registerItem(registry, apprentice_healing_wand, "apprentice_healing_wand"); + registerItem(registry, "medium_mana_flask", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, advanced_fire_wand, "advanced_fire_wand"); - registerItem(registry, advanced_ice_wand, "advanced_ice_wand"); - registerItem(registry, advanced_lightning_wand, "advanced_lightning_wand"); - registerItem(registry, advanced_necromancy_wand, "advanced_necromancy_wand"); - registerItem(registry, advanced_earth_wand, "advanced_earth_wand"); - registerItem(registry, advanced_sorcery_wand, "advanced_sorcery_wand"); - registerItem(registry, advanced_healing_wand, "advanced_healing_wand"); + registerItem(registry, "storage_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "siphon_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "condenser_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "range_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "duration_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "cooldown_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "blast_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "attunement_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, master_fire_wand, "master_fire_wand"); - registerItem(registry, master_ice_wand, "master_ice_wand"); - registerItem(registry, master_lightning_wand, "master_lightning_wand"); - registerItem(registry, master_necromancy_wand, "master_necromancy_wand"); - registerItem(registry, master_earth_wand, "master_earth_wand"); - registerItem(registry, master_sorcery_wand, "master_sorcery_wand"); - registerItem(registry, master_healing_wand, "master_healing_wand"); + registerItem(registry, "magic_silk", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, spectral_sword, "spectral_sword"); - registerItem(registry, spectral_pickaxe, "spectral_pickaxe"); - registerItem(registry, spectral_bow, "spectral_bow"); + registerItem(registry, "flaming_axe", new ItemFlamingAxe(Materials.MAGICAL)); + registerItem(registry, "frost_axe", new ItemFrostAxe(Materials.MAGICAL)); - registerItem(registry, mana_flask, "mana_flask"); + registerItem(registry, "firebomb", new ItemFirebomb()); + registerItem(registry, "poison_bomb", new ItemPoisonBomb()); - registerItem(registry, storage_upgrade, "storage_upgrade"); - registerItem(registry, siphon_upgrade, "siphon_upgrade"); - registerItem(registry, condenser_upgrade, "condenser_upgrade"); - registerItem(registry, range_upgrade, "range_upgrade"); - registerItem(registry, duration_upgrade, "duration_upgrade"); - registerItem(registry, cooldown_upgrade, "cooldown_upgrade"); - registerItem(registry, blast_upgrade, "blast_upgrade"); - registerItem(registry, attunement_upgrade, "attunement_upgrade"); + registerItem(registry, "blank_scroll", new ItemBlankScroll()); + registerItem(registry, "scroll", new ItemScroll()); - registerItem(registry, flaming_axe, "flaming_axe"); - registerItem(registry, frost_axe, "frost_axe"); + // The only way to get these is in dungeon chests (They are legendary, after all. Wizards don't just have them. + // Also if they were sold you could buy four from the same wizard - and that's no fun at all!) + registerItem(registry, "armour_upgrade", new ItemArmourUpgrade()); + + registerItem(registry, "wizard_hat", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, null), true); + registerItem(registry, "wizard_robe", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, null)); + registerItem(registry, "wizard_leggings", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, null)); + registerItem(registry, "wizard_boots", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.FEET, null)); - registerItem(registry, firebomb, "firebomb"); - registerItem(registry, poison_bomb, "poison_bomb"); + registerItem(registry, "wizard_hat_fire", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, Element.FIRE)); + registerItem(registry, "wizard_robe_fire", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, Element.FIRE)); + registerItem(registry, "wizard_leggings_fire", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, Element.FIRE)); + registerItem(registry, "wizard_boots_fire", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.FEET, Element.FIRE)); - registerItem(registry, blank_scroll, "blank_scroll"); - registerItem(registry, scroll, "scroll"); + registerItem(registry, "wizard_hat_ice", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, Element.ICE)); + registerItem(registry, "wizard_robe_ice", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, Element.ICE)); + registerItem(registry, "wizard_leggings_ice", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, Element.ICE)); + registerItem(registry, "wizard_boots_ice", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.FEET, Element.ICE)); - registerItem(registry, armour_upgrade, "armour_upgrade"); + registerItem(registry, "wizard_hat_lightning", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, Element.LIGHTNING)); + registerItem(registry, "wizard_robe_lightning", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, Element.LIGHTNING)); + registerItem(registry, "wizard_leggings_lightning", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, Element.LIGHTNING)); + registerItem(registry, "wizard_boots_lightning", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.FEET, Element.LIGHTNING)); - registerItem(registry, magic_silk, "magic_silk"); + registerItem(registry, "wizard_hat_necromancy", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, Element.NECROMANCY)); + registerItem(registry, "wizard_robe_necromancy", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, Element.NECROMANCY)); + registerItem(registry, "wizard_leggings_necromancy", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, Element.NECROMANCY)); + registerItem(registry, "wizard_boots_necromancy", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.FEET, Element.NECROMANCY)); - registerItem(registry, wizard_hat, "wizard_hat"); - registerItem(registry, wizard_robe, "wizard_robe"); - registerItem(registry, wizard_leggings, "wizard_leggings"); - registerItem(registry, wizard_boots, "wizard_boots"); + registerItem(registry, "wizard_hat_earth", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, Element.EARTH)); + registerItem(registry, "wizard_robe_earth", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, Element.EARTH)); + registerItem(registry, "wizard_leggings_earth", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, Element.EARTH)); + registerItem(registry, "wizard_boots_earth", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.FEET, Element.EARTH)); - registerItem(registry, wizard_hat_fire, "wizard_hat_fire"); - registerItem(registry, wizard_robe_fire, "wizard_robe_fire"); - registerItem(registry, wizard_leggings_fire, "wizard_leggings_fire"); - registerItem(registry, wizard_boots_fire, "wizard_boots_fire"); + registerItem(registry, "wizard_hat_sorcery", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, Element.SORCERY)); + registerItem(registry, "wizard_robe_sorcery", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, Element.SORCERY)); + registerItem(registry, "wizard_leggings_sorcery", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, Element.SORCERY)); + registerItem(registry, "wizard_boots_sorcery", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.FEET, Element.SORCERY)); - registerItem(registry, wizard_hat_ice, "wizard_hat_ice"); - registerItem(registry, wizard_robe_ice, "wizard_robe_ice"); - registerItem(registry, wizard_leggings_ice, "wizard_leggings_ice"); - registerItem(registry, wizard_boots_ice, "wizard_boots_ice"); + registerItem(registry, "wizard_hat_healing", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, Element.HEALING)); + registerItem(registry, "wizard_robe_healing", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, Element.HEALING)); + registerItem(registry, "wizard_leggings_healing", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, Element.HEALING)); + registerItem(registry, "wizard_boots_healing", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.FEET, Element.HEALING)); - registerItem(registry, wizard_hat_lightning, "wizard_hat_lightning"); - registerItem(registry, wizard_robe_lightning, "wizard_robe_lightning"); - registerItem(registry, wizard_leggings_lightning, "wizard_leggings_lightning"); - registerItem(registry, wizard_boots_lightning, "wizard_boots_lightning"); + registerItem(registry, "spectral_helmet", new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.HEAD)); + registerItem(registry, "spectral_chestplate", new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.CHEST)); + registerItem(registry, "spectral_leggings", new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.LEGS)); + registerItem(registry, "spectral_boots", new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.FEET)); + + registerItem(registry, "smoke_bomb", new ItemSmokeBomb()); - registerItem(registry, wizard_hat_necromancy, "wizard_hat_necromancy"); - registerItem(registry, wizard_robe_necromancy, "wizard_robe_necromancy"); - registerItem(registry, wizard_leggings_necromancy, "wizard_leggings_necromancy"); - registerItem(registry, wizard_boots_necromancy, "wizard_boots_necromancy"); - - registerItem(registry, wizard_hat_earth, "wizard_hat_earth"); - registerItem(registry, wizard_robe_earth, "wizard_robe_earth"); - registerItem(registry, wizard_leggings_earth, "wizard_leggings_earth"); - registerItem(registry, wizard_boots_earth, "wizard_boots_earth"); - - registerItem(registry, wizard_hat_sorcery, "wizard_hat_sorcery"); - registerItem(registry, wizard_robe_sorcery, "wizard_robe_sorcery"); - registerItem(registry, wizard_leggings_sorcery, "wizard_leggings_sorcery"); - registerItem(registry, wizard_boots_sorcery, "wizard_boots_sorcery"); - - registerItem(registry, wizard_hat_healing, "wizard_hat_healing"); - registerItem(registry, wizard_robe_healing, "wizard_robe_healing"); - registerItem(registry, wizard_leggings_healing, "wizard_leggings_healing"); - registerItem(registry, wizard_boots_healing, "wizard_boots_healing"); - - registerItem(registry, spectral_helmet, "spectral_helmet"); - registerItem(registry, spectral_chestplate, "spectral_chestplate"); - registerItem(registry, spectral_leggings, "spectral_leggings"); - registerItem(registry, spectral_boots, "spectral_boots"); - - registerItem(registry, smoke_bomb, "smoke_bomb"); - - registerItem(registry, identification_scroll, "identification_scroll"); + registerItem(registry, "identification_scroll", new ItemIdentificationScroll()); + + registerItem(registry, "test_artefact", new ItemArtefact(EnumRarity.UNCOMMON)); + } } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryPotions.java b/src/main/java/electroblob/wizardry/registry/WizardryPotions.java index 60f43f9d..a39a99d7 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryPotions.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryPotions.java @@ -1,19 +1,19 @@ package electroblob.wizardry.registry; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.potion.PotionDecay; -import electroblob.wizardry.potion.PotionFrost; -import electroblob.wizardry.potion.PotionMagicEffect; -import electroblob.wizardry.potion.PotionMagicEffectParticles; +import electroblob.wizardry.potion.*; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.attributes.AbstractAttributeMap; import net.minecraft.potion.Potion; import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; import net.minecraftforge.registries.IForgeRegistry; /** @@ -22,73 +22,39 @@ import net.minecraftforge.registries.IForgeRegistry; * @author Electroblob * @since Wizardry 2.1 */ +@ObjectHolder(Wizardry.MODID) @Mod.EventBusSubscriber public final class WizardryPotions { - /* Interestingly, setting the colour to black stops the particles from rendering. This is great, however, the black - * colour then 'mixes' with other potions that are applied. Whilst this is a bit annoying, for the amount it is - * likely to get noticed it is certainly preferable to always making showParticles false, because now I can give the - * user the option (via commands) of having one of my potion effects without particles, and more importantly the - * potion effect HUD still gets displayed. TODO: Backport to 1.7.10, assuming it also works in that version. This - * means also changing whenever the potion effect is added such that it is NOT ambient. */ - - public static final Potion frost = new PotionFrost(true, 0); // Colour was 0x38ddec (was arbitrary anyway) - - public static final Potion transience = new PotionMagicEffectParticles(false, 0, 0){ - @Override - public void spawnCustomParticle(World world, double x, double y, double z){ - ParticleBuilder.create(Type.DUST).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); - } - }.setBeneficial(); // 0xffe89b - - public static final Potion fireskin = new PotionMagicEffectParticles(false, 0, 1){ - @Override - public void spawnCustomParticle(World world, double x, double y, double z){ - world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0); - } - - @Override - public void performEffect(EntityLivingBase entitylivingbase, int strength){ - entitylivingbase.extinguish(); // Stops melee mobs that are on fire from setting the player on fire, - // without allowing the player to actually stand in fire or swim in lava without taking damage. - }; - }.setBeneficial(); // 0xff2f02 - - public static final Potion ice_shroud = new PotionMagicEffectParticles(false, 0, 2){ - @Override - public void spawnCustomParticle(World world, double x, double y, double z){ - float brightness = 0.5f + (world.rand.nextFloat() / 2); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).colour(brightness, brightness + 0.1f, 1.0f).gravity(true).spawn(world); - ParticleBuilder.create(Type.SNOW).pos(x, y, z).spawn(world); - } - }.setBeneficial(); // 0x52f1ff - - public static final Potion static_aura = new PotionMagicEffectParticles(false, 0, 3){ - @Override - public void spawnCustomParticle(World world, double x, double y, double z){ - ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); - } - }.setBeneficial(); // 0x0070ff - - public static final Potion decay = new PotionDecay(true, 0x3c006c); - public static final Potion sixth_sense = new PotionMagicEffect(false, 0xc6ff01, 4).setBeneficial(); - public static final Potion arcane_jammer = new PotionMagicEffect(false, 0xcf4aa2, 5); - public static final Potion mind_trick = new PotionMagicEffect(true, 0x601683, 6); - public static final Potion mind_control = new PotionMagicEffect(true, 0x320b44, 7); - public static final Potion font_of_mana = new PotionMagicEffect(false, 0xffe5bb, 8).setBeneficial(); - public static final Potion fear = new PotionMagicEffect(true, 0xbd0100, 9); + public static final Potion frost = null; + public static final Potion transience = null; + public static final Potion fireskin = null; + public static final Potion ice_shroud = null; + public static final Potion static_aura = null; + public static final Potion decay = null; + public static final Potion sixth_sense = null; + public static final Potion arcane_jammer = null; + public static final Potion mind_trick = null; + public static final Potion mind_control = null; + public static final Potion font_of_mana = null; + public static final Potion fear = null; + public static final Potion curse_of_soulbinding = null; + public static final Potion paralysis = null; + public static final Potion muffle = null; + public static final Potion ward = null; + public static final Potion slow_time = null; /** * Sets both the registry and unlocalised names of the given potion, then registers it with the given registry. Use - * this instead of {@link Potion#setRegistryName(String)} and {@link Potion#setUnlocalizedName(String)} during + * this instead of {@link Potion#setRegistryName(String)} and {@link Potion#setPotionName(String)} during * construction, for convenience and consistency. * * @param registry The registry to register the given potion to. - * @param potion The potion to register. * @param name The name of the potion, without the mod ID or the .name stuff. The registry name will be * {@code ebwizardry:[name]}. The unlocalised name will be {@code potion.ebwizardry:[name].name}. + * @param potion The potion to register. */ - public static void registerPotion(IForgeRegistry registry, Potion potion, String name){ + public static void registerPotion(IForgeRegistry registry, String name, Potion potion){ potion.setRegistryName(Wizardry.MODID, name); // For some reason, Potion#getName() doesn't prepend "potion." itself, so it has to be done here. potion.setPotionName("potion." + potion.getRegistryName().toString()); @@ -100,18 +66,101 @@ public final class WizardryPotions { IForgeRegistry registry = event.getRegistry(); - registerPotion(registry, frost, "frost"); - registerPotion(registry, transience, "transience"); - registerPotion(registry, fireskin, "fireskin"); - registerPotion(registry, ice_shroud, "ice_shroud"); - registerPotion(registry, static_aura, "static_aura"); - registerPotion(registry, decay, "decay"); - registerPotion(registry, sixth_sense, "sixth_sense"); - registerPotion(registry, arcane_jammer, "arcane_jammer"); - registerPotion(registry, mind_trick, "mind_trick"); - registerPotion(registry, mind_control, "mind_control"); - registerPotion(registry, font_of_mana, "font_of_mana"); - registerPotion(registry, fear, "fear"); + // Interestingly, setting the colour to black stops the particles from rendering. + + registerPotion(registry, "frost", new PotionFrost(true, 0)); // Colour was 0x38ddec (was arbitrary anyway) + + registerPotion(registry, "transience", new PotionMagicEffectParticles(false, 0, + new ResourceLocation(Wizardry.MODID, "potion_icon_transience")){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + ParticleBuilder.create(Type.DUST).pos(x, y, z).clr(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); + } + }.setBeneficial()); // 0xffe89b + + registerPotion(registry, "fireskin", new PotionMagicEffectParticles(false, 0, + new ResourceLocation(Wizardry.MODID, "potion_icon_fireskin")){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0); + } + + @Override + public void performEffect(EntityLivingBase entitylivingbase, int strength){ + entitylivingbase.extinguish(); // Stops melee mobs that are on fire from setting the player on fire, + // without allowing the player to actually stand in fire or swim in lava without taking damage. + }; + }.setBeneficial()); // 0xff2f02 + + registerPotion(registry, "ice_shroud", new PotionMagicEffectParticles(false, 0, + new ResourceLocation(Wizardry.MODID, "potion_icon_ice_shroud")){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + float brightness = 0.5f + (world.rand.nextFloat() / 2); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).clr(brightness, brightness + 0.1f, 1.0f).gravity(true).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).spawn(world); + } + }.setBeneficial()); // 0x52f1ff + + registerPotion(registry, "static_aura", new PotionMagicEffectParticles(false, 0, + new ResourceLocation(Wizardry.MODID, "potion_icon_static_aura")){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); + } + }.setBeneficial()); // 0x0070ff + + registerPotion(registry, "decay", new PotionDecay(true, 0x3c006c)); + + registerPotion(registry, "sixth_sense", new PotionMagicEffect(false, 0xc6ff01, + new ResourceLocation(Wizardry.MODID, "potion_icon_sixth_sense")){ + @Override + public void removeAttributesModifiersFromEntity(EntityLivingBase target, AbstractAttributeMap attributeMapIn, int amplifier){ + // Reset the shader + if(target.world.isRemote && target == net.minecraft.client.Minecraft.getMinecraft().player){ + net.minecraft.client.Minecraft.getMinecraft().entityRenderer.stopUseShader(); + } + } + }.setBeneficial()); + + registerPotion(registry, "arcane_jammer", new PotionMagicEffect(true, 0xcf4aa2, + new ResourceLocation(Wizardry.MODID, "potion_icon_arcane_jammer"))); + + registerPotion(registry, "mind_trick", new PotionMagicEffect(true, 0x601683, + new ResourceLocation(Wizardry.MODID, "potion_icon_mind_trick"))); + + registerPotion(registry, "mind_control", new PotionMagicEffect(true, 0x320b44, + new ResourceLocation(Wizardry.MODID, "potion_icon_mind_control"))); + + registerPotion(registry, "font_of_mana", new PotionMagicEffect(false, 0xffe5bb, + new ResourceLocation(Wizardry.MODID, "potion_icon_font_of_mana")).setBeneficial()); + + registerPotion(registry, "fear", new PotionMagicEffect(true, 0xbd0100, + new ResourceLocation(Wizardry.MODID, "potion_icon_fear"))); + + registerPotion(registry, "curse_of_soulbinding", new Curse(true, 0x0f000f, + new ResourceLocation(Wizardry.MODID, "potion_icon_curse_of_soulbinding")){ + @Override // We're not removing any attributes, but it's called when we want it to be so... + public void removeAttributesModifiersFromEntity(EntityLivingBase entity, net.minecraft.entity.ai.attributes.AbstractAttributeMap attributeMapIn, int amplifier){ + // TODO: Hmmmm... + } + }); + + registerPotion(registry, "paralysis", new PotionMagicEffectParticles(true, 0, + new ResourceLocation(Wizardry.MODID, "potion_icon_paralysis")){ + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); + } + }); + + registerPotion(registry, "muffle", new PotionMagicEffect(false, 0x4464d9, + new ResourceLocation(Wizardry.MODID, "potion_icon_muffle")).setBeneficial()); + + registerPotion(registry, "ward", new PotionMagicEffect(false, 0xc991d0, + new ResourceLocation(Wizardry.MODID, "potion_icon_ward")).setBeneficial()); + + registerPotion(registry, "slow_time", new PotionSlowTime(false, 0x5be3bb).setBeneficial()); } } \ No newline at end of file From 4ca89b2dca00c1be9b97ca482280c1ba7d0d7191 Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 23:00:49 +0000 Subject: [PATCH 56/68] Increase all conjured item durations --- src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java | 2 +- src/main/java/electroblob/wizardry/item/ItemFrostAxe.java | 2 +- src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java | 2 +- src/main/java/electroblob/wizardry/item/ItemSpectralBow.java | 2 +- .../java/electroblob/wizardry/item/ItemSpectralPickaxe.java | 2 +- src/main/java/electroblob/wizardry/item/ItemSpectralSword.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java b/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java index af776bab..23655dd2 100644 --- a/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java +++ b/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java @@ -22,7 +22,7 @@ public class ItemFlamingAxe extends ItemAxe implements IConjuredItem { @Override public int getBaseDuration(){ - return 600; + return 1200; } @Override diff --git a/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java b/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java index 2f57f20b..159d1229 100644 --- a/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java +++ b/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java @@ -24,7 +24,7 @@ public class ItemFrostAxe extends ItemAxe implements IConjuredItem { @Override public int getBaseDuration(){ - return 600; + return 1200; } @Override diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java b/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java index 1250c083..e457e2dd 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java @@ -23,7 +23,7 @@ public class ItemSpectralArmour extends ItemArmor implements IConjuredItem { @Override public int getBaseDuration(){ - return 1200; + return 1800; } @Override diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java b/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java index 2426baec..6ebf1cf0 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java @@ -65,7 +65,7 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem { @Override public int getBaseDuration(){ - return 600; + return 1200; } @Override diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java b/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java index 6e2a71b2..f178d1a3 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java @@ -19,7 +19,7 @@ public class ItemSpectralPickaxe extends ItemPickaxe implements IConjuredItem { @Override public int getBaseDuration(){ - return 600; + return 1200; } @Override diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java b/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java index d8125f9e..6a960b95 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java @@ -19,7 +19,7 @@ public class ItemSpectralSword extends ItemSword implements IConjuredItem { @Override public int getBaseDuration(){ - return 600; + return 1200; } @Override From 03e8682260d6a89a2f74820ce20cd2dbc69fd8be Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 23:04:02 +0000 Subject: [PATCH 57/68] Replace calls to Item#isInCreativeTab(...) with a direct check, fixes metadata items not being displayed correctly in the creative inventory --- src/main/java/electroblob/wizardry/item/ItemArcaneTome.java | 2 +- src/main/java/electroblob/wizardry/item/ItemScroll.java | 2 +- src/main/java/electroblob/wizardry/item/ItemSpellBook.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java b/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java index 07b0406d..bf4b2b25 100644 --- a/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java +++ b/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java @@ -26,7 +26,7 @@ public class ItemArcaneTome extends Item { @Override public void getSubItems(CreativeTabs tab, NonNullList list){ - if (isInCreativeTab(tab)) { + if(tab == WizardryTabs.WIZARDRY){ // Don't use isInCreativeTab here. for(int i = 1; i < Tier.values().length; i++){ list.add(new ItemStack(this, 1, i)); } diff --git a/src/main/java/electroblob/wizardry/item/ItemScroll.java b/src/main/java/electroblob/wizardry/item/ItemScroll.java index cd27e026..6f91757f 100644 --- a/src/main/java/electroblob/wizardry/item/ItemScroll.java +++ b/src/main/java/electroblob/wizardry/item/ItemScroll.java @@ -39,7 +39,7 @@ public class ItemScroll extends Item { @Override public void getSubItems(CreativeTabs tab, NonNullList list){ - if(isInCreativeTab(tab)){ + if(tab == WizardryTabs.SPELLS){ // In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance // is not required, only the id. for(int i = 0; i < Spell.getTotalSpellCount(); i++){ diff --git a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java index b43d5889..359e5eac 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java @@ -36,7 +36,7 @@ public class ItemSpellBook extends Item { @Override public void getSubItems(CreativeTabs tab, NonNullList list){ - if(isInCreativeTab(tab)) { + if(tab == WizardryTabs.SPELLS){ // In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance // is not required, only the id. for(int i = 0; i < Spell.getTotalSpellCount(); i++){ From 740bfb1a8f5ae3f199986bce6f956d25cafdf9e7 Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 23:12:03 +0000 Subject: [PATCH 58/68] Replace old spell book GUI texture with four retextured tiered variants and tweak the layout a tiny bit --- .../wizardry/client/gui/GuiSpellBook.java | 34 +++++++----------- .../textures/gui/spell_book_advanced.png | Bin 0 -> 5292 bytes .../textures/gui/spell_book_apprentice.png | Bin 0 -> 5272 bytes .../textures/gui/spell_book_basic.png | Bin 0 -> 5267 bytes .../textures/gui/spell_book_master.png | Bin 0 -> 5666 bytes 5 files changed, 12 insertions(+), 22 deletions(-) create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_book_advanced.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_book_apprentice.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_book_basic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_book_master.png diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java index fccc7c25..0b2bb487 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java @@ -46,57 +46,47 @@ public class GuiSpellBook extends GuiScreen { // Draws spell illustration on opposite page, underneath the book so it shows through the hole. Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon()); - Minecraft.getMinecraft().renderEngine.bindTexture(texture); DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128); + Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.tier)); DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256); super.drawScreen(par1, par2, par3); if(discovered){ - this.fontRenderer.drawString(spell.getDisplayName(), xPos + 17, yPos + 14, 0); - this.fontRenderer.drawString(spell.type.getDisplayName(), xPos + 17, yPos + 25, 0x777777); + this.fontRenderer.drawString(spell.getDisplayName(), xPos + 17, yPos + 15, 0); + this.fontRenderer.drawString(spell.type.getDisplayName(), xPos + 17, yPos + 26, 0x777777); }else{ this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(spell, player.world), xPos + 17, - yPos + 14, 0); - this.mc.standardGalacticFontRenderer.drawString(spell.type.getDisplayName(), xPos + 17, yPos + 25, + yPos + 15, 0); + this.mc.standardGalacticFontRenderer.drawString(spell.type.getDisplayName(), xPos + 17, yPos + 26, 0x777777); } - this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 34, 0); + this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0); if(spell.tier == Tier.BASIC){ // Basic is usually white but this doesn't show up. - this.fontRenderer.drawString("Tier: \u00A77" + Tier.BASIC.getDisplayName(), xPos + 17, yPos + 44, 0); + this.fontRenderer.drawString("Tier: \u00A77" + Tier.BASIC.getDisplayName(), xPos + 17, yPos + 45, 0); }else{ - this.fontRenderer.drawString("Tier: " + spell.tier.getDisplayNameWithFormatting(), xPos + 17, yPos + 44, - 0); + this.fontRenderer.drawString("Tier: " + spell.tier.getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0); } String element = "Element: " + spell.element.getFormattingCode() + spell.element.getDisplayName(); if(!discovered) element = "Element: ?"; - this.fontRenderer.drawString(element, xPos + 17, yPos + 56, 0); + this.fontRenderer.drawString(element, xPos + 17, yPos + 57, 0); String manaCost = "Mana Cost: " + spell.cost; if(spell.isContinuous) manaCost = "Mana Cost: " + spell.cost + "/second"; if(!discovered) manaCost = "Mana Cost: ?"; - this.fontRenderer.drawString(manaCost, xPos + 17, yPos + 68, 0); + this.fontRenderer.drawString(manaCost, xPos + 17, yPos + 69, 0); if(discovered){ - this.fontRenderer.drawSplitString(spell.getDescription(), xPos + 17, yPos + 82, 118, 0); + this.fontRenderer.drawSplitString(spell.getDescription(), xPos + 17, yPos + 83, 118, 0); }else{ this.mc.standardGalacticFontRenderer.drawSplitString( - SpellGlyphData.getGlyphDescription(spell, player.world), xPos + 17, yPos + 82, 118, 0); + SpellGlyphData.getGlyphDescription(spell, player.world), xPos + 17, yPos + 83, 118, 0); } - - /* // Word wrapping int charNumber = 0; int lineNumber = 0; - * - * while(charNumber < spell.desc.length()){ int lineLength = 0; String line; if(spell.desc.length() - charNumber - * > 22){ for(int i = charNumber; i < charNumber+23; i++){ if(spell.desc.charAt(i) == ' '){ lineLength = i - - * charNumber; } } line = spell.desc.substring(charNumber, charNumber + lineLength); }else{ line = - * spell.desc.substring(charNumber, spell.desc.length()); charNumber = spell.desc.length(); } - * this.fontRendererObj.drawString("\u00A7o" + line, xPos+17, yPos+82+10*lineNumber, 0); - * charNumber+=(lineLength+1); lineNumber++; } */ } public void initGui(){ diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_book_advanced.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_book_advanced.png new file mode 100644 index 0000000000000000000000000000000000000000..47d76cf696d9fe779110bf0fb085caf2682459b8 GIT binary patch literal 5292 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 literal 0 HcmV?d00001 From 5dfa58bf274f0815476d8cd5c9b0ddd34a59ed93 Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 23:12:54 +0000 Subject: [PATCH 59/68] Add more spell HUD skins! --- .../textures/gui/spell_hud/_index.json | 16 +++++++++ .../textures/gui/spell_hud/compass.json | 33 ++++++++++++++++++ .../textures/gui/spell_hud/compass.png | Bin 0 -> 27881 bytes .../textures/gui/spell_hud/dragon.json | 33 ++++++++++++++++++ .../textures/gui/spell_hud/dragon.png | Bin 0 -> 10566 bytes .../textures/gui/spell_hud/futuristic.json | 33 ++++++++++++++++++ .../textures/gui/spell_hud/futuristic.png | Bin 0 -> 4480 bytes .../textures/gui/spell_hud/steampunk.json | 33 ++++++++++++++++++ .../textures/gui/spell_hud/steampunk.png | Bin 0 -> 8183 bytes 9 files changed, 148 insertions(+) create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/compass.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/compass.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/dragon.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/dragon.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/futuristic.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/futuristic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/steampunk.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/steampunk.png diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json index b9cc2d74..37fd0f8c 100644 --- a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json @@ -46,5 +46,21 @@ "skyrim_style": { "texture": "ebwizardry:gui/spell_hud/skyrim_style", "metadata": "ebwizardry:gui/spell_hud/skyrim_style" + }, + "futuristic": { + "texture": "ebwizardry:gui/spell_hud/futuristic", + "metadata": "ebwizardry:gui/spell_hud/futuristic" + }, + "steampunk": { + "texture": "ebwizardry:gui/spell_hud/steampunk", + "metadata": "ebwizardry:gui/spell_hud/steampunk" + }, + "dragon": { + "texture": "ebwizardry:gui/spell_hud/dragon", + "metadata": "ebwizardry:gui/spell_hud/dragon" + }, + "compass": { + "texture": "ebwizardry:gui/spell_hud/compass", + "metadata": "ebwizardry:gui/spell_hud/compass" } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/compass.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/compass.json new file mode 100644 index 00000000..11d17569 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/compass.json @@ -0,0 +1,33 @@ +{ + "name": "Compass", + "description": "A curious artefact that once belonged to a powerful sorcerer. Definitely doesn't point north.", + "width": 128, + "height": 46, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 5, + "y": 5 + }, + "text_inset": { + "x": 49, + "y": 20 + }, + "spell_cascade_offset": { + "x": 1, + "y": 8 + }, + "cooldown_bar": { + "x": 44, + "y": 2, + "length": 77, + "height": 4, + "mirror": { + "x": false, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/compass.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/compass.png new file mode 100644 index 0000000000000000000000000000000000000000..18546a77def5245aa125e634f105406d126ab75d GIT binary patch literal 27881 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/dragon.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/dragon.json new file mode 100644 index 00000000..d014a1de --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/dragon.json @@ -0,0 +1,33 @@ +{ + "name": "Dragonstone", + "description": "A replica of the insignia of Nefazar, the only wizard to have single-handedly slain a fully-grown dragon.", + "width": 128, + "height": 42, + "mirror": { + "x": true, + "y": false + }, + "spell_icon_inset": { + "x": 3, + "y": 4 + }, + "text_inset": { + "x": 42, + "y": 20 + }, + "spell_cascade_offset": { + "x": 1, + "y": 8 + }, + "cooldown_bar": { + "x": 33, + "y": 2, + "length": 93, + "height": 5, + "mirror": { + "x": true, + "y": false + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/dragon.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/dragon.png new file mode 100644 index 0000000000000000000000000000000000000000..751dd6054474341557453364e7097b288a92b69d GIT binary patch literal 10566 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∋W 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

    2QRkq*?Dt8pd90ZO#zDo`}zJXL&*TqODFPGn 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 CcY5~# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/steampunk.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/steampunk.json new file mode 100644 index 00000000..3ac97376 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/steampunk.json @@ -0,0 +1,33 @@ +{ + "name": "Steampunk", + "description": "Magic, powered by steam!", + "width": 128, + "height": 45, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 43, + "y": 19 + }, + "spell_cascade_offset": { + "x": 3, + "y": 8 + }, + "cooldown_bar": { + "x": 57, + "y": 2, + "length": 62, + "height": 2, + "mirror": { + "x": true, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/steampunk.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/steampunk.png new file mode 100644 index 0000000000000000000000000000000000000000..9c433337b025815a793c3e1b3f49638c96909fc4 GIT binary patch literal 8183 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 Hl+XkK Date: Sat, 5 Jan 2019 23:18:30 +0000 Subject: [PATCH 60/68] Retexture all the things! --- .../textures/armour/spectral_armour.png | Bin 2024 -> 1207 bytes .../textures/armour/spectral_armour_legs.png | Bin 990 -> 627 bytes .../blocks/arcane_workbench_bottom.png | Bin 754 -> 741 bytes .../textures/blocks/arcane_workbench_side.png | Bin 694 -> 695 bytes .../textures/blocks/arcane_workbench_top.png | Bin 569 -> 658 bytes .../textures/blocks/crystal_block.png | Bin 794 -> 896 bytes .../textures/blocks/crystal_flower.png | Bin 392 -> 388 bytes .../textures/blocks/crystal_ore.png | Bin 651 -> 898 bytes .../ebwizardry/textures/entity/ice_charge.png | Bin 516 -> 609 bytes .../ebwizardry/textures/entity/spark_bomb.png | Bin 442 -> 573 bytes .../textures/gui/arcane_workbench.png | Bin 4698 -> 28839 bytes .../textures/gui/element_icon_fire.png | Bin 280 -> 305 bytes .../assets/ebwizardry/textures/gui/logo.png | Bin 11755 -> 14687 bytes .../textures/gui/spell_hud/default.png | Bin 20706 -> 11442 bytes .../textures/gui/spell_hud/skyrim_style.png | Bin 20676 -> 21730 bytes .../ebwizardry/textures/items/firebomb.png | Bin 605 -> 662 bytes .../ebwizardry/textures/items/poison_bomb.png | Bin 633 -> 666 bytes .../ebwizardry/textures/items/smoke_bomb.png | Bin 558 -> 632 bytes .../textures/items/spectral_boots.png | Bin 270 -> 369 bytes .../textures/items/spectral_bow_pulling_0.png | Bin 392 -> 438 bytes .../textures/items/spectral_bow_pulling_1.png | Bin 407 -> 442 bytes .../textures/items/spectral_bow_pulling_2.png | Bin 392 -> 422 bytes .../textures/items/spectral_bow_standby.png | Bin 315 -> 403 bytes .../textures/items/spectral_chestplate.png | Bin 373 -> 415 bytes .../textures/items/spectral_helmet.png | Bin 267 -> 327 bytes .../textures/items/spectral_leggings.png | Bin 245 -> 359 bytes .../textures/items/spectral_pickaxe.png | Bin 332 -> 384 bytes .../textures/items/spectral_sword.png | Bin 363 -> 433 bytes .../textures/items/wizard_handbook.png | Bin 451 -> 461 bytes .../textures/spells/chain_lightning.png | Bin 2588 -> 2453 bytes .../textures/spells/clairvoyance.png | Bin 1981 -> 2306 bytes .../textures/spells/conjure_armour.png | Bin 2197 -> 1824 bytes .../textures/spells/conjure_bow.png | Bin 2215 -> 1858 bytes .../textures/spells/conjure_pickaxe.png | Bin 2146 -> 1762 bytes .../textures/spells/conjure_sword.png | Bin 2199 -> 1893 bytes .../ebwizardry/textures/spells/decay.png | Bin 1281 -> 1373 bytes .../ebwizardry/textures/spells/earthquake.png | Bin 2564 -> 2706 bytes .../ebwizardry/textures/spells/entrapment.png | Bin 1910 -> 2394 bytes .../textures/spells/fire_resistance.png | Bin 2419 -> 2381 bytes .../ebwizardry/textures/spells/fire_sigil.png | Bin 2060 -> 2085 bytes .../ebwizardry/textures/spells/firebomb.png | Bin 2002 -> 2035 bytes .../ebwizardry/textures/spells/firestorm.png | Bin 2426 -> 2315 bytes .../ebwizardry/textures/spells/flight.png | Bin 2524 -> 2580 bytes .../textures/spells/frost_sigil.png | Bin 2286 -> 2326 bytes .../ebwizardry/textures/spells/glide.png | Bin 2148 -> 2398 bytes .../ebwizardry/textures/spells/group_heal.png | Bin 2446 -> 2476 bytes .../ebwizardry/textures/spells/ice_charge.png | Bin 2281 -> 2351 bytes .../ebwizardry/textures/spells/ice_spikes.png | Bin 2219 -> 4930 bytes .../textures/spells/invigorating_presence.png | Bin 2308 -> 2323 bytes .../textures/spells/lightning_bolt.png | Bin 1865 -> 2184 bytes .../textures/spells/lightning_disc.png | Bin 2273 -> 2432 bytes .../textures/spells/lightning_hammer.png | Bin 2361 -> 2426 bytes .../textures/spells/lightning_pulse.png | Bin 1965 -> 2275 bytes .../textures/spells/lightning_ray.png | Bin 2072 -> 1964 bytes .../textures/spells/lightning_sigil.png | Bin 2133 -> 2200 bytes .../textures/spells/lightning_web.png | Bin 2880 -> 2483 bytes .../textures/spells/metamorphosis.png | Bin 2010 -> 2194 bytes .../textures/spells/plague_of_darkness.png | Bin 2403 -> 2534 bytes .../textures/spells/poison_bomb.png | Bin 2071 -> 2085 bytes .../ebwizardry/textures/spells/shield.png | Bin 2370 -> 2041 bytes .../ebwizardry/textures/spells/shockwave.png | Bin 2448 -> 2551 bytes .../ebwizardry/textures/spells/smoke_bomb.png | Bin 1715 -> 1778 bytes .../ebwizardry/textures/spells/snowball.png | Bin 1687 -> 1677 bytes .../ebwizardry/textures/spells/spark_bomb.png | Bin 2166 -> 2238 bytes .../textures/spells/static_aura.png | Bin 2177 -> 2195 bytes .../textures/spells/summon_iron_golem.png | Bin 2482 -> 2597 bytes .../spells/summon_lightning_wraith.png | Bin 2127 -> 1975 bytes .../spells/summon_skeleton_legion.png | Bin 2080 -> 2163 bytes .../textures/spells/thunderstorm.png | Bin 2815 -> 2592 bytes .../ebwizardry/textures/spells/tornado.png | Bin 2178 -> 2325 bytes .../textures/spells/wall_of_frost.png | Bin 2521 -> 2547 bytes 71 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/ebwizardry/textures/armour/spectral_armour.png b/src/main/resources/assets/ebwizardry/textures/armour/spectral_armour.png index 748577d3aeafd6b0d2bb85ad3e69fc4b061cde52..739309e1c91521ce836c98b0846b00579052fa21 100644 GIT binary patch delta 1181 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 P3=9mOu6{1-oD!M<3-Zs$ diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/arcane_workbench_bottom.png b/src/main/resources/assets/ebwizardry/textures/blocks/arcane_workbench_bottom.png index 0271489e1ba007b050489d976ba6dd76bb3b8927..cdf19eddce4bd6206847a07378b6f88eab810f28 100644 GIT binary patch delta 40 wcmeyw`jmBo3O`$tx4R3&e}*Lt%q8(RzD{(I<9fuw&8Ny#{SF{6tK02o>g9{>OV delta 79 zcmaFL`iXUdiVI_Lkh>GZx^prw85kJYlDyqr82*Fcg1yTpGcYi47I;J!Gca%qgD@k* ftT_@43=Hfgp1!W^cUjpuESUMLPO@x_?qUJ}$W0as diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/arcane_workbench_side.png b/src/main/resources/assets/ebwizardry/textures/blocks/arcane_workbench_side.png index 49ddaf0a44773ca13e094e3f9a08c745ec3c0a34..15941b3c4acd82b3f3e63c8a3239f7033c43703d 100644 GIT binary patch delta 665 zcmdnSx}9}`R{ej5B@E0Z@i)FQFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#IJo&# zSs&?L?Pg$La`AL=46!)X zt{Fxws`X7vTNRR$vsX3Ty3r}0(WNb_v`CHP*qn){=gqEvbNAetzSgcE_CHP?|GoE- z?GOFJ&u1j>Uzqj&nMU;Ych6rw-aco}oaZMO7yoDZUvc}rOj>0sYlPbCHA;8i-Hn+$ z|M{D*m#-Y(#(W`a$C)=@WU7z7ej~Zw*xJ@T`=Jqo`xOo2<>!p*pNdUY?9Jla7MZnG zLzDY&{vHWU32++Td$ z&noiB(Q3{>Q?<=(1MmgL3rqcUwJuZlr7eY`S4yc>4At-+9+p z@R$e0DSm44Q-4~qo&CV++zS#0U%Dh>x(a2hW*dH4y+W6n_tIBKt*b1vHM#2N2Fn%k zte)^Zu~DQiD{}Khe&Ls)0S{s(Kl7OWtw>a|zlMeLOK{9A$9YOVO-B~x&RwpnZTQagnv02*Rh7eNjb?z>QSRQY3R^$D z*x=;(<$`GQ2dU4Cn@&0xJoqIQsWFG|Mg498QLmJQn-Sj?9K_Bg`Lu0joa*STpe&Gj z<%8N3l}6ziaqS0ED&E&QE^^RdZ}6!S-1lEL*xDh^)#TIg6c zdqSBzqsAJQfTogSk-|5Jc>gC}{F5bZ(ect{#U*KmEglR8``jj!2RwW)s+#j8nc)vh a+ySBQt4*UOr!g=vFnGH9xvX@EJF^@DGL+>=MQ{{wCL_ti(M zKg1^`R^2k+`mEjZ>_6q)cY7;NE5+zw`I=nsw`$SEqbryX5OrkXt!( z=52AwxmGL(9=)EuXLh~M?z@Zb=6%fjXV|?ypQ*shx9IgDp3~veSMX$CiCBAjx_Q2a zCU>)M6?@;Mmun1uKhdi{|4fWwMs3k_zx3WMk;#9uXC8YvA-wr}g}lPN`@5e;Kh}Mu z^XSy!mKC=YUY2F%)h@Z4$9Uo8nvca_B))nbD7*IfV6XR#f&nh7^O|JU6!E$9i zD<)XXapH2{y5{Cd_l_@Y8U=Yh8=Ip`!dIU-cFol}Bgp$nO7i@6A@;xd)C2uKFUzpew}CvtIa#q1K|wPzB`TqTbuCFaL#9hFWo zEGi6d+*u;E{ldaM3H9YyLgp^?E)-a>WKr3^pSSs5{gt~nb-7`W)seV*?W}LQM=$x! zTgvr=DNZ0Q{AuEqum*lXOn_uC&NK@bpLg$!Y9fN~bO)>|x`c!MaWOw%o(}YU_j>q>Ab- z*nWu#|F7mMClY*lhzXg}k`#m4_8^*`}oU|?YIboFyt=akR{0RP}5h5!Hn delta 538 zcmbQlx|3ysR=o>@EJF^O6M_MIhKUPX$nw+jET#}`{h zUC}zRR_fxZ2&snGGwVIeuYFxRb%WXoFWK99PPQvuZ=Bn|G)Y!@ZlwC6*4Rzq90C^) z`Pj`&epT1ytSGt7jpNJLdz)MXcC<|0xJCPmdci%eqecvuCb8VJwMtZfly-N0o$`K7 zhcN!Xo)7fTX#co=#=tD#PwU^_7b>5NWHd}V+QNU>tD2P@dwOQg-KDKJ>tEk^ez5nd zmGFPA)})#3!jErQ@Bgtc(kb%yCa>E!xm|Amo>^CTuC(0c-ig+vnbrO8g=AkW$zL(K zDbOj_UU|l)M>Y3;9q?be^j%5ajNIKGzdH^-%qx55xK)c?MLekC(9_G$Cr(pY-EPp+ wE0q|=uc+%;y8q1OJMQ!JO#?;M_A_1)E`C$=WR;LC0|Nttr>mdKI;Vst0MiTi?f?J) diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block.png b/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block.png index 1a8ece1c30285e8d4f2e38f4a99bea40f484edf4..9e6d71d41b5fabb9a1b04b4decdce6b1f790c890 100644 GIT binary patch delta 865 zcmbQm*1$eNr+x_ob4mP-uM7+foCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&o+K6P`6 z^UpdN7?^oIT^vI!PRC9-ogb1aajgD+`MEjgN;FuvY}fQyAb26Eb(A8Zin zojxfd;}3I8MpDd+b4#m*h0CPG^+cStm6v2L^>G#q(8#S%x0-G|y=VO)Fy|R%N~ofY!G2m zREf^y){a)+rG9E|{hhV%bd?xHp0!%|UVhSlL~8MR`Nd&34uqQ-+n)>Ycpka0t~qP# zsb67S3!4S(gcw_7*X%BL)VS6q8#l-5+@~`(+lwUEO%IcllvA5HL;aHYG0s^x>ez28 z2L>rzY^)PM)RnUHEO+qnowbG2j-C}-KiBr)!SudKoH=bt%x83C7QU;$vU0Z=Z>pe# zY>A41n91wPxLGzQPaU=Jo~os;elM-=8`m_BjnjOKQZmf{GBc-K(oEVID6{>n?efz3 zj9+?>oH*lKy!*Qch*{_ zst`er=^<8~xj#&l?6j0PBo&Kp)-y2{tY5hCQ##{QmLFveE=*1v^8bVeJ+bn0NpB@$OHhn%emdfvXH{izf%a_q|kDej)R_a$rLMgU!b;7B_XfCrs$! zmwR&SlG6SEUzp|RS~)I`NqLynw0_^e8BLkZHyU5N?biR39kJD>eZIZd&M-$wsq?n= zKXruP&tDd#X;`g!ZhCypsjc_(Cd92*TI#l-YL@_Gb~0=DKBETxwD1S?yv~zmo59HmXr8vITPl50={=+17uVX-*tN&kFt= z<=pum?jO$Xv`DJ_Hs{yROG*s;f^w2CurVb**e$ha@xvXq3>mX}^=zkndYOB0;>6=W a*gq9jDoI-F@iH(lFnGH9xvXwa5@AIJ%l6L0DDng-3EeF<|j{FmtsL>$!s9xei>mr|d zDMDS0QRkN#Z<%a)bHc;Y^8q~%ik{`2{it%dqvFDZDM>OWdO0V8+(RVw&fg5z?s?nU zkfPlcIN{8NHEI^QhW=lzr=2!-T7L7ScVBzg(HaG>)C&+j~peZ^w5&Wv#Vg=FhcWIET01V9N{BH>Wk5U1mI4!IJD%Avo>Wg2x>CadrNi zZ%_KlzvID)&pjGar>DGmdE(bg!Nn$qYHj~N_Q%gnUc6xK)|y#Xr_874h?@%URX--% zd|vak^7+KR7jy3PwnzvH)>+jbJ$&J#>tD&u($;)#3)vDa=LT-?5Am9D;j+Amckp3@ z2{FapGsE`$d^aoi{-j;geAv#^*&cLnKjNV!@~h_Hx|_!Stg|0vu3dDZb?e&7>W^KI zkC)GxCb~|3#!cB}GA-%#DlUqe4M&nV-h7>y%<3bW${ep}_U7HcBOS?EM#~HrIX{VS Y+`N*F|H7%S3=9kmp00i_>zopr07LC*Bme*a diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/crystal_flower.png b/src/main/resources/assets/ebwizardry/textures/blocks/crystal_flower.png index 65b5ec0e27311e6ae427459556a862f4a33cbfb9..f08694c485c2a828c2fa245d8936c73292956a4f 100644 GIT binary patch delta 323 zcmeBRZegCFWy-*?g5f{2R)iJ<0|RG)M`SSr1Gg{;GcwGYBf-GHz+U3%>&pI!gPT{w z?3GwaCj$ec;KX>9dcLy%@^ThOX4veX+t}FHn3$KO+Q#U!!)Myp4S)WBxMJ5fKVRbi zrU>e}dGSjS0Jze%doLGc%iC_h(~cV{5x$XMIU{((6St z{{NTwXT-6$^3;zozZd`aP2gQpeKhurdH+4XG2N+rf6w^O-{1WcbC^{uEG2jR ee^9QS%k0|RG)M`SSr1Gg{;GcwGYBf-GHz+U3%>&kwgQ&doq zbM2X>Z43;Iq7&m)>fb&4FaOTw*n)-z{1+HCF&~I zT@C;LH~f<-Q1yAr$F*}V{I6A%_W0g*dR4>!ecgBeO@70=KZRF-4) z4#m`4SHnJZ&wt}!?{f6zKM_X(*5@&6!(5lhUgkUQvf^+3;*-y2=BeI(xprMe$MT)e z%xq_ueSOqE;RpMDfBilD`saV|Ij_7VXyv5WyZ&re@l=xFVOsFoYSpSo7JUEPSFbc# zmKnz0>a>uHkA;b0#xhSGG3V>0DUoakN@HCbO00a3M5#^sKXuva%31548S*eQxCYLc zHB0G{_5{D>6H|AdT6e16Ay8z4%rCxuEC=$#^^|35C(CoO`dn5C)V^e1((t%_{?j{u zY%XSO+2!!(w^Czvn`2r{Q}<17n=AGnN21ieRZrX}&Nt!j9~IlZ%qmSvva+%oT}`Qx z9qV2v-8KtgUnGAp{P?qop6;8czu0W#|MNO#GtZJ;q5?KY>}_*yugg-@s_$}2Pgmz| zEcNS|_o&asy6vO!?CoxrhQF+8+xrT#{)pOKn_2TdbdOTY;lz+oUE=~7_Tz=8+<)XH ze7e!@FtPuBW%oVt_Mh+0XneOfaxt?#&b)j6qV#-w@xFciI;T%;>RG>f^=r$^CYiCf zPt1ERe_Z$3%->mU?+zaSQTI*7%UimBzl3p%v{})!yPh`d8)xV3n|tS_zQ>z8abkud zT!y=?&Yy1Q`+V}|W|KR&k4X#5e@L#Kk-zSYaL*RQ?~&7dH_G0T3b*|GwQ^GP?h7Vs z_c%;aIrPwA_0rI`c{lwxnmH)Vd~*A9q?GwlOS7su%XF=0SWbWXAX~V^eiyIrWd;G= z(@yo*OTC&7T>jnuqay*@)$Bwy8`&`-9-ajE^am76;-R*Zyo;Y#)&8?m7-to&$rqw-Kmn-;Z>Fb;iYZGpp zZPEdyo}i<%xVgE1#7@7|Ysa!~@}A|hWAxmMi;brri%E~ry!uFgZJ_?TqVER|>*(oC zTN_iEtRb>!=ia@q&c^7qt9a_@>Rz<_kYMU?G-=|?moJON{z+f-QEOhcDs+9g*X1qs eM|T?i=I$$W*S{5zzJY;(fx*+&&t;ucLK6Uh5uD)w delta 618 zcmZo-?`EB#Q~#gg|AM{CCo?cGa29w(7Bet#3xhBt!>lEak-ak_Q#+3a9Pk)!pB4<+YZH&9Aj^72sY500j$tT`QLlQ!PidhHUwB1@1L!;`@1KWc5hOsNDa))5g}d@~=8WzT955i#bBOrZw-B$(tV^ z_~vAdo&Eb=dWjN`EcjNxjxMp9`@_c2&{1vjL5agli_-=APM>?H_p)S`*HR}h&8^4x z{QLY>dUMLZbqTZN_HX}hu*_U@OO(yZ-&pKs<&b6b3H@5$XQ$)#n7Vr7mm zyqdLfPmGfq|K-Tl8v>%1UV6LfTHfTdX`ah3|L-^SQjXg8Z>@;a7qvo*;`5&$J>oe0 eT1N0c^Idm#g$k9|>lqjr7(8A5T-G@yGywnw+#a$3 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/ice_charge.png b/src/main/resources/assets/ebwizardry/textures/entity/ice_charge.png index 0c44b04788a5d9d41d64a2d53bf4881f901239b4..a181149a5dba243f76fbb24c84a7c32f61d62ded 100644 GIT binary patch delta 578 zcmZo+dB`$Bt9}Q=3Whc=mrLmk3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_PH_QM zlcwjhVi*`0-+8(?hFF|FJL#V$}{>N@#(;YHu6qxJdsojzqChFrSN*q zi#qXOc1=2bpMLF4d2d{@54%3-;P3uONZ%MrRtorCgm5*ZX zo9iDp=*qF{>P{>NU4@KUuw@%x)Xc4aO?KjS(lP3 z^?F~073P2a7u&fv+({|4dtPH**H0bmnJ%4ud*9mZDrKJjD&bej-U(8xUO7}mm@qCq m*?BmqqUh0_L-m>VjN-X3ca}7X@G~$lFnGH9xvX8~4_tPx-AYZU?a^xJZgZ~fM zAK3Unq2%q7&3&;)7f$1A<&q82(Ma2&vOv7@?AJ4@mBm^0PD1OQJq~^;`PNuoZGZlE z&Hd-x>%;yf>&wi0yiDG%Twjcp>CcOMj0K+ab+}gDUvjH1LHGMJPGd8!_a&qq%zR>mH=b@Ws|Qa;Uf`w(pfz|8su9ok=NyKSZx&E}4{5`~TFhoW4mb6`4-n zT$l=Be!uK`29Hdu$==;L@qg61n-p!NR;tvkZL^<$aO>NQ=5I$VxHmO( zs1*N8xYm?A**{w1kn%$go`<&akMov_gh`cNn$;)l@hOwLLErY|s#TAV#ELT9^Y=Nf z6#e1w@%jtV#wQztm)RyKT#=G7kVyXZ*n2KEw9Usv`=oZ|6YI8o$y{q*drCCl8WIAk=Txt`Dc_?@9U{vW zx>!sLg_cCKOfL)2(BM{` zG!|Gd3o=@DcHg>E!JcEP4SVfdr7 z@J`#&Ga=K8{lyBeOVzK@sdo-x>9cRS9`!f*bPxUd}HJs{k;P|@9k1cAS|NN-ntYqnyQP448II{2SccVHrCzWUK z_c)$hvFO__6}Fl?Csh~(L>+x47<|s^PBe}Y3tw|Czo)%9#9i;ix`)Ch^`Gh`I`YyV zzD#9!=es}k(X-O5Ll3T>bFTP&e%AY(-Hw+k)<)>ZEnJjTUwfo)_4mq|`V(gUZ<;pC z#idU`<9uGtk(o)XS3d@t-wP0CTg}_4y4&*3_Wnm-Vnt#fe-ElGR%csWC@CfLX!o7o z@U0h3crUknc=OndIhQMAYwqf$){NW4?fx+-6|PPS(3@k-z`(%Z>FVdQ&MBb@0MaP+ Axc~qF delta 410 zcmdnXvWt0wR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&%(ti zVC?V2WyZk3=A@;DqQpjRcx%G>TFFfpO}obFp* zU(*=J3l}a#2>9x{JBK*iPva2v)D7V5oucv1p!Gs_hfBSoZ^nn4_rCwElee=uFa9gG zPtSI@_}VK6Gq@EaA}W}}e6k|&Nym*4Aukn*z2RuDFGJ69i}$;$ zuV|&Zwb|OU^z|__q)cy*T6$*2b@w;l*cSY3iDmyY?ZCP#|NDymzvea(wkck{^qkg2 Q1_lNOPgg&ebxsLQ0BtL+ga7~l diff --git a/src/main/resources/assets/ebwizardry/textures/gui/arcane_workbench.png b/src/main/resources/assets/ebwizardry/textures/gui/arcane_workbench.png index 02a43a70761e37e0d575c8e9679d917ac8a5c33f..772720ef0b8df5a27f33bdc7317819ace2bf107b 100644 GIT binary patch literal 28839 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 delta 206 zcmdnUG=ph^mf?Q}Lk7mg&clZo7#KJUJR*x382Ao?FyoGi*>4#b7}!fZeO=ifa&ikx z8f2s}XHAUOsju;LaSV~ToZ7#Ux7k6&c|NmnK;XrTOFYFEEIq^PaIj~~799rTCCTk4 zGXWfF6yG*}tNLT%AdbsZM|NaCa6Bl)TkG%{G3=E#G KelF{r5}E+itx^I2 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/logo.png b/src/main/resources/assets/ebwizardry/textures/gui/logo.png index 1df56bc84fab3583ee7e2d079cc356f92bebf940..024b85567e120c061a01c240c20a9fe5cc8077d7 100644 GIT binary patch literal 14687 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 literal 11755 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 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/default.png index ce3109410f1a205414b597644fe21cacaccad794..000d3ee1d38e31dda35fda3e559b45709e5fb400 100644 GIT binary patch literal 11442 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 SDkla81_n=8KbLh*2~7YP%|)94 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/skyrim_style.png index 846f69cf746729dca1c307d18ce87a7f0218eafc..074a9575929f2d2255ae1bd722e0f59f681db53f 100644 GIT binary patch literal 21730 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éh8@7G8 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≻w`&n?IKJ5Nq_uMF^%KFlZy~ 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 diff --git a/src/main/resources/assets/ebwizardry/textures/items/firebomb.png b/src/main/resources/assets/ebwizardry/textures/items/firebomb.png index 60f6b11aee30102d957e75170405ba35edc81bf4..53eb999b62785621805bd1bc6f321b937acbf44b 100644 GIT binary patch delta 631 zcmcc1GL3bDR{ai!6%1`$E|=077#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=oZ>uI zss@JdR2UeTls#P>Lo80OopjMVxKQM{{r9xgh`uL!nZ9As1&4WMH2DNK%OvWndF=bD z(6~=U%;SmfkblXYsx(3iT_mOLNUJb7in8S;inSM|8>ZcS`!cpA&vs$o^EwaZb3cc-H07 zipf$khu19FznZm&OtpM9!|{~1y|a&~>(?pWZsK3a!sPrK@s32ACCPO$u}ICcIA zD}TT3g^!Vp3HM}Ok33i;e(L_?qz65rR^L-vr^<=$WcqgFl`2<3{*I~X_4hR9PUiX> ztGi{l)JIp*vdIdyj9)kMNt%r4#h zzTK<}=-i8{?aowOKi5 qhO&x!pWDCacJjQh`48$h+h5so%wt;DJp~2^1_n=8KbLh*2~7YEtsaU1 delta 574 zcmbQndY5H_R{bP~$qbtBlLAjMFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KI9a%@ zRIQ{I-ezE6eC6rl7-DgH?IcGJkwTGU^_wMByp>M#Jb7Yd8YOJh*s@{y3B* z7uOV5Ik$>P$XSOdT=d-K!Wz4aLolyo<=qJv7DR39y^~UZDD{=Vy6B|hfK|^EZ)K`a z|8Sw1|KEpy``_2{%jGOuv(o6=X9tFBlZ|HUWv}u{480KaG9dB&QTraF+GQrMzV)CabiL)P%U045h)q>0m?+#zEZmwCmD1!g=hP5Y4j+-6X$SWuqY1J;mCQ_K= zyzfrXp}53QrR8)FspK#N%b#1q*i}@NNlA9hi#~*zBN-=4@U2*N| zgAcYehJXH;Wj9&9YUYbIOa-qh+)ef+OB>ZP2u|b`zMJfEj%SjMb@z;2^;)ItmR?MG zvzqaD*`up940kSSX{$z5asJ-ky#2xFTBZyC4SKaT7~;;Rzgy>TB>4Qf&YGhSe6_#m ztzejQJ#*n2KEw9Usv`=oZ`HU z0@0t=b1*P4se8IOhFF|lJMpY{NTSHG`uBU!l`pQ<%5pTSGCg*;M!vZIpy#bTxs(kbnd`oD`JT@@5>X?U>(Q>D@p^r^`z^)zq$TN1 zCrV~SB*~P9Db79hz&_5Uu9(pv)$>c<+jyqWL5{B=WVe1uVVj{Zsy>vQYwC%g=4`|`+$!FB!;y*I8q!o*__#4x7i;Yi4sfxdRjK=)~QpMJoT5qzw-HM;w;;)Q~pN} ze7@nErQn>AV(!Uv{INjK(dVAec)09DOFo`b*}LOR*NMd~T_&;?N1p8U|6$vda!y0J zENI2cH;c~BP@8F-;_j_`adB~lk9dbr+wEmZ1+y74?nox+*zNz=)Mh+AvZ};2uVg`C v`T@neQxbf+h0j}x-HSH+vHj!zm*OYy+}L3Ma`Su!1_lOCS3j3^P6|z^O*-f;rt^oBWyAe#3(s8XJePgt9@_~!O{NEXCyCkZHhIDHa?K672^~DM-hGy{ zc^LmBotNpel=SquB|cN?Zx(V^?9QDcW}~xy9p|G(EOHy(?n`)_IP=dMN2~A!GgdyF zyCxw1&C}t)xzBt)i@8mi*p?R$(_Y~2sJ5N}C z_B-Lvzct?A*FOG++1l-e*F(I#*>BGJte~y6X^~N#?U{|nQVi48bk{Ft3}02xR`rql zWz5VQFBl%=xU1>a=yGXwn` zt>Jnpwrp$Dg%>v~Py3yCuC%~8w*AnqbFZtXnf|@vdE&XyHx`}s>lC%M-2K8VcdZoM z`T9ZirL!LM=YM@Zw`cBU4*n2KEw9Usv`=oZ`Gp zn)DBKkBIuSf;zOAXdcfSX)bLebJ=J z)#v}u|39btA(KIvZ_oF=3yCdv`XjT9xtm@xt5c{OXOy%5O^h7(U#sXLEMeV(5!K z{*j;I$IG7=UKtn|FdQf{W4!R6>#nlrZqWtLxu>kmp>|d z%Lua{`fSr8q^w=D$vl7JiDv>%3!ZenIVE^Wsl%kFX2~8qH=CIg)stk@*DuVJ>UY4HgD1NuJaD99^`<+jGzsNuDKlwkHU-j;}xA5>p76t|e22WQ% Jmvv4FO#thi3zYx> delta 527 zcmeytvW{hfR=pB~6oZJTrs)9&1_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmPtv$&YJ zP^ocjE&~JOZci7-5R21mC!Nm{4iq_7Z+`il{4y=SUV%aZB?~UST^cDbg_m#()-WHO zt1a(b!zk~xgxmaRSI4_u8ZSx|TegU8;q*0{xwHJ=ox*y-^pZjTewmv@m@3)WgZqc*vy6ydCvgGdT&yNZ=HI$2Ou;6Ez zabi(Sl@P=9`THIp@IBc0q40vqjazT7EhzphmpMzwRWQhF-7C-BExYX%Dr66-Mp)|a zEBtGA@}W3`%!3r0^!luI7rm5g&ZqiM&53AAQ2#S|!K=KocN65~3sk}jW!f)hwB+8- zSZnAz*+z<);azuYTYXU)y8LcUA05MWV8|ToZA1oR(UDV@XCbZ&%u* zV;uXQcl~@Z!{+?OkD4bmKYd}>uIv#KTWi83u2Mw$Urp zIP{NOQ`!3S`RR-tt3x7|KI&4{iqI*yH$L>`p?A&sT#3KDzvi8O_wT`*?`woYe*OIE jTRJuB^n?1#`n}ip3EbSPyN-c@fq}!*)z4*}Q$iB}@(k%c diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_boots.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_boots.png index 4ca991daa794221ac270113d9bcbeb3aadaf8907..84d3ae0fac4db7d79b0b46a39744c943812a116b 100644 GIT binary patch delta 336 zcmeBU`p7gvtKN*^Kf`~Q9lDkb3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_E_Oi) z!L0?3cNrKM{&~7MhFF}wJ87dAi=l|C|D#RWOMCBc*n2;5E@S-x4(7Txg=w>trv81V z%p$10|3FlZP73>6+49KbiRNi(5l6%HSq{~Hzgzy9<4&#yUu z;0QN=|GEbeN4DndJL)O)V}fv_bo!$^$}m-$RKgfF|n r>lk}$p}`8~>_>CkV-wozTl|-&MB7gK>wkiQfq}u()z4*}Q$iB}OE->^ delta 236 zcmey!)W)X${KLnW z!6MCxkCd{qd@Xnr5)u+3@?N%FUAg0kAy0?RKK|8CF^^Jxrm!h}g#2<_dv(MPB{g$hd!N9=4;OXk;vd$@?2>{MtTP*+p diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_pulling_0.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_pulling_0.png index f089e38d08a8dff908158049294ef608c1f08260..47525aeea3672a493f63e458213fc539fab1d54f 100644 GIT binary patch delta 406 zcmeBR-o`vZtKN*^Kf`~Q9lDkb3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_E_Oi) z@fhJJFBljYojqL~Lo80uoxIG{BZu4t zSiE;8tuhJI(`0t?l6TnPubQ!NshLwm_w9;%syiLT+EVLh{(N@-yDr1E{wbpUCxv-L z4$Pc)g*DnfEQ49_!m*j#W*oZ7@9DRcM=F!gqhUJFwG+9_7Cyd~Kl~PU8mA}y-FwLD z!!Q0V^Tkdo&ABOLeEV50LtWa>y|bNUqUp)X(j&X7i}&cAmNuYwQ1+oI1Zgz}9o_PN5lpbhm4KT66Br37IaxE59DE`}$neA%3|@ z^#3KMvMPy}12q%8R)6j1I=f5IOjBdgq$TQ>d#g7&B${XaO}+jrd+t}>E59B(tz?&a zykN}|rn(EMpYlXMyC?F@Sao5ha->`G(q@U*?B1*OZX7OHs{fZ;Yktu>AAT-{7Yqyx N44$rjF6*2UngE8+ui5|r delta 359 zcmdnS+`&9StNuU3e}?}H_AZ~yz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns~;XXWA% zw>B;QKZAjRQPk7LF~s8Z+=+&HhYUp8>Xnaaa0@MZbtp(*?(#}+eg7OswKKFzpOe^#o1B6N%#N%-}kEP85-`Nc75!}$xw0s{nyhO zE!RKZ_)=RJqZ8HIH@jD`q;u*e|J9;))4VUI&N`F!!%~KUVd4~xwXGR-d2JIW`lMv6 z`gE^DV6sz-fQ2}#U*$cc3zf5${n9?ob31*_6u&u_&qp5PE1$LO|NG_(e+=e7&fV*l zsrzczzFn=3KMM4?YThN3t=MC}bgRdl%ZXq8z8tZX)n0mdW`KwAT-61lt&^X5+-UId z+IId__2<2Jn_S-?R?p#^Yx3ssdl?Dw18;xM+9@jF$@%1`Z)jxU-}{T~LtnSNe-~Tn R#=yY9;OXk;vd$@?2>@%!qdx!u diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_pulling_1.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_pulling_1.png index 8f89801aaf61cbd4db8930ca6ce694089b0093dc..7497c59812060387f4469e4d512c37df811d1589 100644 GIT binary patch delta 410 zcmbQvyo-5)R=pX+e}?}qJ9I4>7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=T?m-wK0B%CVN;XF580N6sR<9&0|X9DYg#F06MgV~ zg6hMrl}yw0!jw3^ZA;3|oOr0d)z^U|d!zLGbGto6#Fy3Ym|dBFZ_nMv|5mr=p3W(C zzWB~}i!^7$DIsRY4Xe_-8l)RJGFo@|C(6m+?$i?d&YBfbny|&1`@nG#sgwn4S#CMB zgnGM8Rh`$tzNf`6yHkBugIUk|YO&Q}K6`DRS_?3r<~$N{)%0p!5918&GJBBAAB$ zI=MBgJa(mu`vwLRX2JU&yV$Za%C*DR&emipd?DvAxv4R9cG{^wwHM#*SbTTol;Y`+ z;*-B}zE2RW;7xu~zPL5i`kDIY*E9d92|SivpLliM&!=W_C*!yM5cU%;D~RWr{9S;7 Pfq}u()z4*}Q$iB}Msuxt delta 374 zcmdnRJe_%hR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&&tIk z&Mqa>EYHBesN(737-DgH>14yALk0q_`(?ZqcpOx5c5c>)xpd(vL%@;r4f+p+Gp_8q z$jTGG;1gpJgVhwtlfJWj(ll~!JqVdCktjVWXX~u1|8H%tpVUy#w)n~C5~1>W>gzd= zIVxz>-_J|!7wa^vu#`D+IYZ?(3&V#EF^@8If6ZCEC2T`g;fvo%Qpaz&PE<*ZWnkDD zbpJQ^TGirc72#tNUdbOOrlx;&%I0L4Y#@^V`YS)v(T3tDUWro2CC;Q7cwVv;KmW8g zX6=VPHx%p#4sq`^_Sce_iuu#J;Qga_fiZlWljhEx6vF>6xz!D82#kh*+Yl-@=UKC|817foe8Ji)X6)A{-JY9H>aoo)SS{_4q@ zWjonheHW%Rmjz{q#OuT&GkAKui4YsUr`w4==hXI<%5A>g>wht2B`oJ^_j|KzyY&Bc42MlD!z-d$W<`ohe2L^e;5O?|k96wOCx_TB zEG=8Tf5qh3*$fi(>*@mZ6IK@$Wirk=qjX~Jw~rYH5nI*0`7A8A8XWj>ob5z{?13c< zjdUkG=J>S4-eAU&S5Ko>`SB^8*lcxkvn@kqPwljaDfXG!i+f$KEXY_r;sr;3So2=xdpo}_Y}J?dZ=|<11|F8$lb+AOz`)??>gTe~DWM4f7eJ?K delta 359 zcmZ3++`&9StNuU3e}?}H_AZ~yz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns~;XXWA% zm#UO{e~f{FQPk7LF~s8Z(ICU3Lk0pdno}GmHhH$Su?6l}vhXzXf{yzMb`Qkw>?mE# zFR{+r1>+JZSC5GK&kRGp5Yx^gpfIcWi$sB}67@KF zzx&FNAdk+ zxH-B>=gdk~b0=4}^YN=Mc}Ka9-a<{-N3((Xxa3nQtp@E1aI@ R!oa}5;OXk;vd$@?2>`F~p_c#v diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_standby.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_standby.png index 9be035b3d11e15eb259db35f0039bb4eed1f3500..a19b8b5c30b94b8c50e43fb3d0aebfd8251cb83c 100644 GIT binary patch delta 370 zcmdnZG?{sVR=pX+e}?}qJ9I4>7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=T`{g&r0PbfJ0li?OOqqX$?1AakOy@$lI)u&Bs zTI<@ysD1nBzXO-d1=hG&=+rWDUyMjO7qe(*_pS{(XWo3TKmTt3<`3r;_urf&>dz&( zfz5@bbB<1XUMbrFXFlza;`83t6}b;KJ2EF6cg{&NbaY$y-?(Pwhl~f)^jn3Ra&{Zp zUsX_Mzwn=LzNSxc1glxigxc`)_p>LQT_3T2o=sTA$%nEL-yQp;KFnqF%-$Hc_n-C$ zHWj-QnauMtCd6((@HX4|Y*+IZ8&~7<#kqIpunPv*+qnOn*vZlX#6MB_>+c_=k>#hgZO_;&ndAIV-u7CW(9c#C@>lo#9@(cgv b{>~}$HZIU|-w|^L1_lOCS3j3^P6|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&&tIk zuB~z8{T~Jfh7+DHjv*GOmrgX~YjO~9wLeyrymsTlTWvvkjJ)C-ZZ`XTV~J_7WfpB$ z*myMM`mtj-y4g3}YH@W?^E01W`T74DhI+RnnRa5Vyr13cV_)mC-%6LfcaD*vWy*`W zi(iPpP*haSOO^bxXP2LQ@dw587o)q=FS9T(9Pzq%SHgDn94Y7L+m>FDkh-3{G@~$H z?@#HGdr>irF;gxjS6tf`ZXYW8c2Y}fwXx5iZi`a~85C8y7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=T|{f~BL)Jl^XE=z?b=+xT6M}rhC#DcJ1WD1F=SeS_s(fA zEEt7!h1eaPlBT{%6An(<^ieHIn@guRr~ldinLm>c?~ksptSGFE*tPTjxu*})o`okL znB6S;A#)+qwqvVT7cn@eE@U%U@bT3`mJ789b~o#DYjex)-5NO0H)U$;*0YDVGJAaI zezmAL`E$Yh2hk3V_iowVXi-Q!xs*|(VoO77%f+CZU-=d??y=H-c!lR&le#sV+5y20 z41NvC3Z~6$nR8@?xXS0{^50;JyfRH}k=ZpnE5^!-(!U~E3A$n2k;Wa_dv@v8Url&p zI?qY@U*4=@uL+(rFHiLnohu-#65&#=yE(sg$86Pr&+5MwtxOgE{Pu~7j&SCy1Y$Xf~3=E#GelF{r5}E*C`<{dV delta 340 zcmbQw{FP~fR{ej5GYn3~4#wFG3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPggQCQbn( zhUY<@ISdSpOr9=|Ar`04PTK2t*g&M!{?;lEwU!$*R<(U%k&KwYQ{9$RDYl45tWs}6TB6l-1xD@-y&A0 zW&W`@xA^<``dx!XcAfs2dFJO^)7{(44dRP5NrsBmk|+(S0O*J_zQtSY@^v;R%=#k99;u61&M z^+@$eD!njGwQ^ZUo$t@A$?pOrlS>U->Pk;PSblbQTDcUDVEd74e8;%h>Xi;`TlY2n vYRBZ$-GQH(Wp;F=ubx_Rbbt4MmiURg@@^@`&7Z=+z`)??>gTe~DWM4f=5vua diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_helmet.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_helmet.png index cd8b2e5dd252614b8c50e1571384aa10843232dc..dd773a5d0775816554035d9eb9d02999019f9db8 100644 GIT binary patch delta 294 zcmeBXI?gmftKN*^Kf`~Q9lDkb3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_E_Ojl zKE>qPOa=yqE1oWnAr`0KPTI|T$Uwx^U*X~94UF6yn4~YXvuaEzILhbK@Z=CH_W_ZP zXbK&<$}`3CFj$3Lk)<2&0a2hJ4?r3wkpe*SfG z$Ovbfc8js*j-*F22WQ%mvv4FO#n8yaP|NI delta 233 zcmX@k)Xg+OtNuU383rd~2jgr81_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmPt6Q_Wo zp1{iM2@DJjGdx`!Lo7}wCrEs15S+bW)8b@dvyZ!ff4?qh;&Aig#*n&Noy{NxH|zwqq_HTw&s&ZQ?OBvfq3v<`Egq0#HMhOMUN*OVIJsj{-OFF4O? kY;1IN@#S6pLn8s?G-loGGs1Dz3=9kmp00i_>zopr09dJ7O#lD@ diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_leggings.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_leggings.png index 20a2d845d7f583f69c5b88adc58a404a736ff35d..e650dc33792ecf08a74886ab97c09b8aa5fcc927 100644 GIT binary patch delta 326 zcmey$_?&5iR=pX+e}?}qJ9I4>7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=Tf`S8fq?_!PJ)=pXJop-@!KjGpkON-A_{%Q%FTwbH_ zvRr+&*|nL^^(P*^VQ(c{xt+l}hOc)*bY!udp-|&2j|SQHnvQ!XzVq$ycatdyCo9bHa)C+c2p*$&W%hzwd4|*8BU=qvoom{ogy&kp-&A8LN zKq#Y;d!rMB-E*xk>F?}C<5sd9jcE$gYFTp2muH3*>lJzNNhuH8&;Fgp@ZjjNbFNMH hw_b?<`(}2JQKB--=Gv{Ew+svn44$rjF6*2UngIFOjRODx delta 211 zcmaFP^p$afR{ej5GYn3~4#wFG3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPggQCQboE z+4Ys%$`}|Jnmk<`Lo7}wCrD%*=+Im6=EaQ`|HF6x{(fB`1>&UKifRu2JhybVgj~+8 zb03~v)7_!yb3;ULdr4A6-bU&Gp30x_z>Fk$7jQ;BhFF|FI(e@bv!h7s{>b`ALLXQ~baGR;;}4zsRQ4_SjPeamv1ww? zJ7NX669s~9{bDJLV%1h$5NhBO{v;}=qjSfu%#wszJB#b>-tA0h`&YelSJRE1hd3md zk`r8t)b|NGya{?}=ES+juZ&ZNwSrAy=eqnG2f3%dP&_34fp3dbku3j)7B)*&vx9dgA9rC)IbFcU*7q z&7XG5Av;TXwRpUC#2xn=oS#2O{FhZIGwv)jSK0nw_4k}e?)x3TwXW%EdEA|=y;hSa z?OA(%4 z>n8+#5Qq#|qk8T3jVMjUC+WIJ!p|9e-dD-|KWzQVhd=h!uec@`DHfjHyzJrII{$Sd zM?Z5OII+p1>BVd{=j%^*-98#GcxEw2gZI2*Z=oqu3Y8sY-`zAhnzWVa{A0VB3zo1P zxWJhu!;AEz=r`<0UcZWQ@>T{01_n=8KbLh* G2~7Zaj)lVj diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_sword.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_sword.png index 95b2dfaeded7cb2aae94df6d0aedfbf1e6c726d6..104d3efdee3dfcd49318149aa1d715c0d8438cbf 100644 GIT binary patch delta 401 zcmaFOw2^s&R=pX+e}?}qJ9I4>7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=TUXsEKHwM7Wj*TT_(h=SnT}cebbn#?Ww+`pzt!HCd?+uv{5{{XM$VLy z9|sRkJtVOqk$dsM?R+S=F4#%R?DSDmezX>zgPL*?l*w)Ii^o7tQu*gr64 zH|KJCA^Li0)~4?-$~U}wwB_BchnL0XXojzyo;rE{Nmq}C>fX!D;t!PB%PlJ|Rz;f6 z^gBB8kbQ!T$kw2Gi%-hkEP>kFIN8=5*AFQ~!6` zg-MIcDsCTace;6~`_SZLFE>iRYF^NDXv){3jD%Z<=Cr!=UVkC1=$EaRQWvJN{lT8q z!tAbla=!KiH7I>p6|gZbE7m!#jP2b52GxXvZPER4_EtN~l1nv&wlOepF)(<#`njxg HN@xNAiz=%= delta 330 zcmdnU{F-TkR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS#w&&nxm z${5I`y^?`};fJS-V~EA+rIXh4H3i7D^8d?xC#B=Fx%D-(08feA1KS#g(|2VzN5~xY zNMea=$oL>S=ftvuH}7!dTvs{CB3#;WeRAHZGO^Y;7h z^HPu5`fiVBRlfafRi^W!N52IM-*l)L<{ejVn-;45Qe^e_W65)3wy*gUGWWV1*TN~U m6HjnoT%XCP!9MvU^ZtsdD|nCYILyGnz~JfX=d#Wzp$P!yb&Wy* diff --git a/src/main/resources/assets/ebwizardry/textures/items/wizard_handbook.png b/src/main/resources/assets/ebwizardry/textures/items/wizard_handbook.png index aa0dffee0a3ded71c59213327adb5cef4395ee9a..32fa1337565b71821a530dea84b8e57a7ae7efad 100644 GIT binary patch delta 429 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 delta 2533 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 QFfcH9y85}Sb4q9e0CtnDA^-pY diff --git a/src/main/resources/assets/ebwizardry/textures/spells/clairvoyance.png b/src/main/resources/assets/ebwizardry/textures/spells/clairvoyance.png index 81ac7356cb1c26ddaec6c3e532b68579a70c9b2e..a4c57a57b121427a751c0a61ef9beca4db80dc86 100644 GIT binary patch delta 2288 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 Q3=9kmp00i_>zopr02bdz`2YX_ delta 1961 zcmZn?+RHydt6q+QkAXplcmFg71_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmPtqnMzj z)b>07J~J?|dwIGzhD01bI{j>abhzZP`uCRCzunlk?YZ`3A3LtbX)eB;OLJ#z@r{ZQ zxx%$kM_NTiBU)*r(;sn#vMK8nbQlyHS){#OOjlZEHf7XL3i>5_D`nZal4Hin_xbDZ zecohIp7u!X@FtnlpRR6w^SpBY^UCv;>-T&JiTr85jv*oS_2uUU89`;73^iLUnI1d{ zIk3?4Vfgyy;PzFI;_Frha`1@oPT{HA!E^qM;GFozg-LA(P9z#R&Ph5dRBC1O`)H@( zoa6nzg~g`#R2d3hWz;vu$BT)4eW0P&9`;V*k;o<V^YmA~riZ`Ny^_0TzwK@gW_-S0g8!8a$BsQ!?asU_G!{6p%{+8s;mk#= zZ6o{&&%a&#XQ$?=-`OE)&Z~?~Pkj|I_1b&SA+T=ejr$Yp&ontt-lSc^SKr4N%HOH+ z^`u+f+qE6LIae@meDTzG)qQKXr!F3koz9$eK3?&8{&i1tC7w2uE}P1U8+G1j6#VOw z{2YDs^!h~!3$Lws>~j2G;$pvu_06R%U$q_{ZMoUrZ}9)?<2jba)0)5EKYnJRrPf!Y zs|H_=gjT+M^dOJPBQBD!Pq6;{lLuiZ>w6Bfc4$KOx5lWxxWaz3`?Cm((yp|fyjQ3E z+rZ@B^2Auo)A&ph_vcSi%uy*b9X5LUpW1V2_lZ;N+dZNUGp9@{3)Xp7AFYri@c4j3 z?XH7wp7R_0zY*v+zp`nmy7|KGe(QI*#`IlS%kg=)=$W;4O%C?TdFl!6NB;WS)ul^b z4)>AY<=LaS{-1E}j(X<<5|7Jm8IyU{p0?HDCb2RGNoMl{dwnV*H zDy`!iyYS|}38lh<@}&j!9J4pF>v4#*Y?=IIuHuH+9u5z=oU@)aPQ9{BbNyyVEp|*` zx|GK5{V211D#)@2LA~_42Lm8G&8Wf*sBw$2{L$Wo=r(RcL*Rou6ZAW4%>( zkI|$uriHCh4Cb;AS5`Xd8e7|*eRFuS&DFY=vq`6pO-((+(9}37&#mOv+t?4)Z2|{- zYSmXTyE*NVbY|3$&|tRhWv$=H(|9OMzg1(e|4bM@-;8Olqy%T;n; zN%rU~^=B11%ib@$HQ=o6X_fuvpLC-IUa-}lh&GI$b@TX5;pLWl|66dkCeP89imQJl zAimjE?@om3tt{n;`?K=+xl`QRWh!QWHDi2!+gmhcNuA7Tk;R9$UMrZ5^Yv_6FnJm_Eb8c75-Q3`-#^Hf3x=B0&3yw88J)bCa z^rqdG>-7;{>o)zGFS>2k>osfdv|XJ0iTjv@%l8{ye>J8(zQ?%k6~p7D{GVnnNLiTH zDL+@CTA|^r*y8(JDnhMI?(aPM>-Om*uVo+kH3dFCZ~4)9UdK*$#*dN)KMPmB`pnS9 z$s~VZQtKp#qfRF$)Mm@g)xK!`-)`w^ZmtYI-P8vO0BNEDizqk%AMLh+aO?j#$t|zjhj-x+&z5a*MtY(eYw_e^_*o{ zkk4ZK^>*R1onMUD^4?AOU%yU$vG}=Zm4zE0KMiA^%5;_4c*ja6AMumt{3hB)9QEb+ zvz2rGHi;Y_MLDNg<;PAuJ#g%KR`fTSKgZ99?${|+eE;8vJl3#nQ^e0rVXXKV+xU`m z(yr#o!XFm1|6vT~O~~eWuP%^2A;n|SiGYKeZfp6o>rASJc5k{L(|f#q!`tPLm2%zY lU%RCyRP*WB^1c7K11}XRR-`B|W?*1o@O1TaS?83{1OUz_r27B> diff --git a/src/main/resources/assets/ebwizardry/textures/spells/conjure_armour.png b/src/main/resources/assets/ebwizardry/textures/spells/conjure_armour.png index 712476c5f716f7ffef9a48409efebf9ade46b6bc..e15ece3c506dffd83d652e29bd684a83a88e588f 100644 GIT binary patch delta 1803 zcmbO#xPWhhR=pX+e}?}qJ9I4>7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=TrefHbhb94X9eCaFN($=Nhw7`GmEwkL9*%@0G z@~du%5}4w)yvg;Wqo81}oM_FZ20N9ct^}n?Y!}0F9gft`oMh5wV#i_Eam3-M!;3pJ zcb>dceePcN&kg7Q>^ynoc*TQz#picEU-R|t*R}a;x2AsEsC(}J#}0;k{&zNQb892n z89uykWjSDLtz`ZCkiH%pPeGvz3xAW=6n%&5y`3j+EoDk;oAv0O#)dsR&Mdc!@c(i1 zZ=-C?POBJph7T8iYx&jhS-OK`+0hNz4vU&NR){d{>T^CK$XM=v=b-G@h`Mxv=9jYN zAKUlqE9uGHiuHG?;RRWxuFo2CfT34VTrq?(T=5EHlY_t(W<`z!Ru)-~Vw-difx8=z z1&F8ps-4EhTvxX3;e~g*sOyJTFmN(1a^iRq(tAbJD6}xVo^8>iK!HG&Lubx} z9oSKr%%Rzwt|EO;ZHw6+FOStrriR?;?n;!gzy9gcWphT2Jz~dOI()9CJ`EPV{Qi}4 z>63%u`}uhqFaG~?#=ej%-*}x<{W4eI#GEhh=Oq^8HvCqz+%PRN@S>JNsmr!67glz) zpO;~Fi>Y`wTh)A*yXq8~fJW)-?GudWMSq)9$t7X<{m1K!KMi)R=PS}Ea{jSYyU6qdlt*GYj)!MYXnRb zv^vB-M}-GioB6G%>O7F9<~#Ra^}L?pwOvSQ(vuI)C4(pW=MQ zb>DV(Sj??g(fDuki@8kJGW0-r>%L7ZEDru&CMdw!;ncA(d9n7vBSrce1}>{NZMu7$ zUs+MfqMpM;!>T<*DP!)-t44B6i*|M-6f?xKvTPCP$jPt~Vr1)(*j@im_Fe72#=hTg z4~R_f-yauXprsnU)mUHH_w_cxh$tz8;Qh0`m>#KihAe3bZ29y~z^3^9^Y_nBofZ%1 zY`C;#=I{L#6HXtGXBK+2=~+bBc|9Fny<{`al%^RE3nJ=o>Gw%>Jm*`ixQ~yatz-J4 z%WKv&SWY;whB=|)`??*H_hf;jgoED!4*$-y zIf7xEtsYuVEuQ`HT4Tr7rJg&hGdH`5FFeaNQ8L9nC~b$uf=MBAnL=u(?(h4?Z};W! zcjnIjbN*&C>c+BtGO7Q*_k+&#xSEX&lG~3K_)SQ#h&U2_-PF3%kD)+6r&DsC(Y&5L zlV(_Nn7?;_b#L+fS~1>&f5qaCGUwZ7D+@XFa-Wyivs6w!Dqr_g_|MY^nK>yHMr(98 zH&tH$mfv|G>(&fMqYR-dyxW4hCayK92)K~PV8~n?BP7H$uT^J?=ZT{F?|#Q-Pg|PJ zeL-rT>=`wU3tweEd}3%&_2{(8+E93S{`dFKCthBk@L0@^)6GpzdKyo@th8#)oDYG` zz0r1`PM`nqY_j^s!o!cYvhFd}QQh-dQTo=#do~eX?+)EpQIRzAyOD9`&p!3aFXqcP z9NYM0f~^08lM2$;)b^aT`Eg1ozwT4Lg;`$2zHJTty*B4s|G&|ws+QDR)2^AGA@ylR zW1!`E+p-4t`g*2(qgz##YSNQ<@_X9rewUuB`{SN{?z7jS^C6Sc>=ZfkqG zSJijjRMWcgdtckn`mfg(DO6nC%;BLWdRA(~i9gEc8?>sQ^)o4-t9zrJaO_h8W46$} zX;A@lrZ0MSGcxqo_W85!<;XQWeVV##`SR{LcLK|8RAWRA2P!@D+hBBc&&LmnE(w{L zoH`HJPF-|a?B&EYF2&8CXU~3gmb&A23@NBm3#z_niHvO!@qCZrY}DS((|pH6FBXHqv%`n|83n zO|`qsS+gVh<|38XWiCq>&AQpPA)oodsjClNSW-&M_jJARlU?ob=&bp>FCXK-nJ<-G VA@;3@fq{X+)78&~Wt~$(695)5O;!K^ delta 2178 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 JtaD0e0stFCC`(kcpH+RQe|NTh% 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 YA2e=o=ezoufq{X+)78&qol`;+0A(W^n*aa+ diff --git a/src/main/resources/assets/ebwizardry/textures/spells/conjure_pickaxe.png b/src/main/resources/assets/ebwizardry/textures/spells/conjure_pickaxe.png index e7a7febc6ce7db4d8e069f086a996c3fabfc7d33..9b1ae64b4bf6a24ea8bff56f0fec68d57d0b351c 100644 GIT binary patch delta 1740 zcmaDP@Q8PUR(&YLe}@0Fv=o*wFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#xY+r` z^t#?JRc2sd%lC9~42d|rce?M2*l^L~_1SN0&+XN(t(8A{U{ZvthRf2G3sfeU9dmqr zAWKkCkSlBvBR8MS(xjsSvL4xNQ7;xWUs1X$A{%i;e@RHaqM_!}t;~--yjQL4O}R9^ z`hE46z18R9P9MDYyiP@bk?fZPJD+cOfAjhO`2SxkpWK+p`aD-o@ABG5pSIl-WW2ZI z)qnK`)9!1oIQ!?H{*rHNPE27q@N}zK!`;;rZM6^i$1@opzFSz%Gn;Ak*-s8G0ihd; z-oEHuysC#y*{-s>p6~gE`hB5#v61tI7%VnyfAr<_Bu4HXGaoAL;8tQ=HKS?K0?8N` z2Nur0%76ZMCT@EF?CI>EcjMhwXvN#znH{`m@#%M0PZ-x<W<$DawB5&*l6rm7+b%KJuX%H) zljUIZ0>_&-?l6S5B;^({H8l5j&tCKAeN(scnd3)Y8qfWToIks3Cquvqq^B;Oq?ovIsm2waG|xWahhN{M5^&yQW#Ht77~l(5S^GA`Dw z$suHk{KZzOx2#)E>?_`S{@5=Lo;{uslN0Jsdqi^@h!iwWovOMnPIg+uKE_5(LC33w zsX`S(tZS8a32^+Cd$_DCAXR(ysSi^=6du|ZrDL`rL8(Klr#N8sp*6MUDhf&$etL^? zc3l&!VtgBV=i{I4jim{jW3E>|+!ud1t$FX%4ATXd67D5ziI^mra@5QB=DY(Y6@j8o z92q)d*!>vchCFAXin=a4+rLzhBb4H zxm4HZyDOaL+abI-NkfQ9h=q5egwn!Q9EKlGT|B;WTJ@27S=%jQ-)#RF#{K@ddWFh@ ze!VY78FM#GP>`6lXUEm_Q$JO1m_9GkoUg>#+jY#N$J8*)BUW)^Q-I%ZlHt9!}3KvaDGjw6lB-@BVUkW$FfyLfb|@rKL0*DYCf>`y{Zi$I6rqR`e5QN?ec zG#PmXKOSJ;|K0Up>96|tZ~h&s)3f;^Q{7*;gyZ)4e_^hnM%VfLmY>a?=b$0$m3%Me zx<}~3y`OdE|?(X@tRXy`wz1NL2Zk;4w zwFkT%mJxYp7auHG=i7aH57Xj{E0)B3+Z)mt5!wJACRZ^T{PQ7!E%aNJ^=^uIIF(i%E3hx(fo9 zKf2Q^zCPiv`2TV7od16ekH~y(N$%KMzvsiu{K6O0`wRcATb~r2oRi&S&S}nGd_dr4 zTf?en+oYKmojP`m?b0@v!mw##j#HZV|J1FwEo{2I@3%s_{nyA1EwdF@9<)`|Y&0OgIr@TE@FxP)h?L=;Vx%B_v<)5C3l|QcQ zn59s^bxB#z?1h@wtAm_u%++R@6gDmw`l__z^jEGO){DAUEQ<1SE3$cdY3u)qlmC3| zYfiOITzPP|?jBPW)k(`eFFb6Uq5O>J+O-c;(wU0gOJ@h&33b#hU6p6h5%Gcz6+;%j$xi?y5cGQihbFB{_WXS$3_kK#+?9O@*Mt!{lvZev$M;bm_?BA?$ zQE)>U&sxQK8=h3kI-ktqb9dgbXWs4ILc1i3b}N(!p5b{bXK;8n+vbL4ExDSOEybl1 zx1DXwZkyfcJyUk>#RQfqTeKG}-1Gey%N_Nnm-qg-r}MpV_BO+EeZjfw-}PB_Nc0&* zNS~QnE~wt&SFmj@bA9`FvpK)rZ5ai+o~+tA{d~@sN6Cy^q~m1U4qtp?y!7){2Cc+j zZy9PnU+%uW{qe(s6PGRt*)gkab`0$cU^3}{J?W|5_q#lX)6W?{Fb{d~DeCk_W$rmv z#&bg46oiZ1(>!?EoYS6t=LwqkKYzihQ|9k(9$c#Zde8IN?(5ngj)gwI;X09(VV=!y z&I1_+2VB?veD*oh;H=2{Y|b-H<(uMnZL<5n?%nGh$zS|rWhYj=J!D<`hy8_$(V2wG S`(_Lb3=E#GelF{r5}E+G(^OIb delta 2127 zcmaFF`$%AdR=p~NDuZh418;W*1_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmP~kARSv zN^8!HI}8l$?>$`{Ln00zo$j3zb5-(q{r#QmXKp=*NNMy|k(ONxL_#=A4>GL?SgIE>)j=UvG)#1L*DBHaAlBXtZ7o&BmX>F!laD;U zULp7G%$@4Uneb2egMX+Ciy-522|<(X915@A9}Aj$nEes&>pRue zQ(s2?wqiJ7{>^1isZzbuaz|!nw+j|b*}oYUTw;IWd_s!DfnimJ2kV@s(h#?8AKxuM z-4R+>6u-x@aPzlRche_tCvUvJQEqQ1HnN&Fbq%k#jI$z;9Zg<99TcPnI zo3D@xUm)Wl262hD<8F!qbKd@}KY6&};K{iryLeev^z>d>byZ|t>6pWV+;w~TwoNqNQg6Tas#t5i zQ-`G7v736+dJ>`~)g>KE1p-~So_=ulHmCPt6a9Fm^o@Z&0VN$SH?lXc;5a6ce=lZx zm_yS(;bV#}if>n64*CAJS)l9agmr2jnkmnp$i~!s7ipUBQQGRjvuk;?isI4Q-yGJG zbEA4o%J@2&Ai@Ooc8v%^M@0FMb4 z-#AqRRQfpCxmcFAM6EtnTW;$R(DmcgX8R{o#p4vp`I-ef3cgSFFZl3sxn=n;lj(hO zsV`nvzpSgb^A6E?7*_RU9p~J2+w0S|Gn_D*v-v@hkLI!f+0=v_5y_4dZS0! zKe6^x1A|hNqoe5T)RIelDuz#04nEVCxnXy7-zSN}peF%^UG;~j?){VVMbB^FH@T1N zH1Act(wt)@SNUxE7CoKcUvhaQ9?y;W)0K2ajKQ&i^UnhXp2Etmx1|xeS2DM~da}r8 zyLmNF`%~cD7R(^P~zV7UkX8wzRe*gaS=<4(z=OI^ zaUfxT#>};%8D`RU62F*xJnHw)s&ox__}~bmp8mN@oKr=Ue?EKMA3WpM(Ur>kpR@0; z?y{f%zawtm#8lfWkzR>M3QAiR&Mr49_{?&*NYXguTiv#k>;h41#ipjPG*8HpPAz!O zl4!W(>e|I~_1^o>f41%8+&NKuj!Emwr2b}ZpJ7?n(;i_Jo89my3M6Yk^2)<%DtCwxjqk|=@UABA+Z@id7NZvT;@Tgp1(oMCJlZ||Nx8Xo_6 zn>t_ceyih0=FPVF{W5Y|@xuqQ-!~c*Py4*KxaBV6v*}S8d5Yh)7IbY${42d^!TW+m zT@ma%TTKqvmj>VQ63-Ns{Qa(c=I`6pA^XbBH_xB5xIA;(v6$v}M% z=#6XnGIuwpiTM`K`nt=!G5Ctr`x~=GUfg!SqMSAB`{VEfj+O6q=hT1YIQn<-lFP;( z5(>u(-tM0-nC?Z&H+u<@b8-tzH{c z*!4v0 znBCfUsdE9BUg-=4huv~TnQ3g(pNW*cfB0$V`9FJVf6ul%qSo+ReYed1pik)y(rg`C zNlXWhZxIpt^i)mnykX<}!&BwVI5Ks0zC{c+{l8P{DamfOAmz(xL7`y6?BgjhmW9p2Z^T)?z*Y2^BR8_BQsuX5_|M7e0*@-_T% zd6MA6g-=v2Z#4^k+&o)!$EGzlW%Y~==6%Z-IC&Ire8;clwny`pwnyGy!`#0mOX4|F z|A##Pwdr>0&E?r|d9Mas^E;mH5`S$gn^4`yqtk2u@^3c&@i6I*p%4QD1B0ilpUXO@ GgeCx(_x)@D diff --git a/src/main/resources/assets/ebwizardry/textures/spells/conjure_sword.png b/src/main/resources/assets/ebwizardry/textures/spells/conjure_sword.png index cc78cf8ecc697194c3f76e4c467afb60c7d5ceeb..104d5e74364f5a19fa2882dda891cd052638e0c8 100644 GIT binary patch delta 1872 zcmbO(_>^ygR(&YLe}**SpWH4C3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_E_Oa1 z_KJezQy3W7K6$!0hD01*J3Y1|HeB?0efHbhbGDPurPl~ZukpPqrM)mV|48yVV~ez$K>n&9I)=lT}#MF=?rasg!EKmviC9 z-{)+;{wZ;O_49KnpOp3%%s4$K@t^$b{nz56`QFbgxVNmo`_6~CKaLp)KJdDKUoGJ{ zV`yw``ZmRhx|=t7F+7O>pUb$TQg2ggSjD^V328fizt}0bp+g{D z6<&v2`U@_zSY1@ko2B6AqmbI!-f&DP>5Sf-mF}rM*IBbY96mK`8yg4DoWLMebZYS< z#|0fe{(hV8T+4`DxVK4wi$y_o&&2vQn=)tI-81vw?EH0wR(W^A`eyg&IE#MX@+$I5 z%=1kSr<(%4c4#ix+aROV_=ZuHF9mC^_cGzsDScM{a)WU0+yre(#LsfeTnq%NkxwEsWVK zAW#_7D#7CAdaCKd>9Y2?6PfQrTjD%BY?o;4_}yCnIOfmA%L;sxZj`-I^t->G-Xk$->!IMh3t++!mNqGjyFPtRtv4=+M>g`(B)K0tb5d|qU`?$1u?Ufq~9B+yFb8Zy#G4Rf2 zpV+ND>36hf()Gu#p$kGi=jb%5>e^5wXsqxSI7C8iZ+2f2?ZEsw9RpJ)(R^zXs?oo`RS zfBH#3F8TN3`48rw|JNyD{9|qWj``vCr97UT`O$mwHdZxU=iSn_Rrg(IYn^?1LQejL zkNVxGyFEBsBsfAHb(D^}IIiL9TE!A}V)GXU2 zKA+l^?T?-*G~Q#HA$(0OV{P#f0rM1{3TZhvsbsZFmLIM?(4EGvy=IH4BAbcU?Y{R9 zdeikjuVcS|_Wt~R2bKyy-}zd-{o}Dsw{{(zJ!SrsO+^kdFTRTx^{=%cFxa@Zqhk*>^rZuHNxwv-X{;2WJ2NT*$9HpT2$b*W%q3e>Vodsrr|=Cr@!} zMRtYPipGk2bu}V8-h8p>ylN>R+Sw>DRlwS4)tkCP`wO3b39tXSPrt6iUapeU{NbO6 zlYb~|d^~fp!x47QFrIv&gLAL(#0Yrn=;$m;u3x)Pu~E_ZDvu7|Jf0a(^6hJ;-tK?* zf1gpOl#Qna&F}Z@bDl$?>#S#qy}g((=PX6>&E|?MqYe{NQ-1J9%|R zW^5d9w&SGdQ_TCevOV+2zPa;>&bQ|Wc?u<0$~X1jmtYUzy!! z>lMrwQZRT`Zm_*CXZxY8$Nv0bno+KL;=!%Pe(QoajVHgV8r-S>#F~_q#wObMWCh2( zs5O%RLfJ&7^ITdv=l%E3r}HjZcCA|6V*2pjg~mjN^#u>b%7 delta 2180 zcmaFLH(hXoR=p~NDuZh418;W*1_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmP~kARRE z%RZ(ZA`A>1DxNNmArXgK4m?*#+eIba`NcW77zxDHN z=S%1B{T^la#`v;ddd<i!MO_=)6RB?u!*qh}i`xmJ!+<*J1r1a5x7TW^TqbJYa z*wCNB>XlJ`>&A&Sm--D?+;GTI>=XWw(UEi@fpyB_>rW18G3)Q0ALrUDR#5V2t)azH zo24f?_sq;xdF-UtniBNnxVxrL-@+ofEREg@O_j-RMw&-TCzMD{J)6Ypq8)PTpw`3I z?TfzhoZw3Ja^PMh`Y7X(MncVJo%+9d($ei7dd(J`cNeiRa{c64o5uZ1@RYPt+&U$t z7cmn*I7tR_WiO17S{Asn`6dHHRAUUI3%AzWrstP(LnQBRY>wN1`o+4pF*e^7Pn8O+ zE!?ZPsH{8Wn)15e0+E*^}; z47ug{-1tg%>YkuR52Y_2a;9^frx!gj&v)Wa*Yt^Z⁢oMK10C#l?5N-$+*I6ka46 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 literal 17760 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 L)z4*}Q$iB}D4R@= From b8ba7d1ea48cf7f2b9da0e534ade0d1601c6d572 Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 6 Jan 2019 15:21:08 +0000 Subject: [PATCH 62/68] Transportation stone tweak --- .../electroblob/wizardry/block/BlockTransportationStone.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java b/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java index 9d1684a4..84c0c9c0 100644 --- a/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java +++ b/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java @@ -65,6 +65,11 @@ public class BlockTransportationStone extends Block { public boolean isOpaqueCube(IBlockState state){ return false; } + + @Override + public boolean isSideSolid(IBlockState base_state, IBlockAccess world, BlockPos pos, EnumFacing side){ + return side == EnumFacing.DOWN; + } @SuppressWarnings("deprecation") @Override From 2db96cf18ddf38d1d1dd6709b8be9c03a5dcb056 Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 6 Jan 2019 15:31:48 +0000 Subject: [PATCH 63/68] Change spell chat messages to hotbar toast notifications --- src/main/java/electroblob/wizardry/spell/Arc.java | 5 +++-- .../electroblob/wizardry/spell/ChainLightning.java | 5 +++-- .../electroblob/wizardry/spell/Clairvoyance.java | 12 ++++++------ .../java/electroblob/wizardry/spell/Firestorm.java | 5 +++-- .../java/electroblob/wizardry/spell/FlameRay.java | 7 ++++--- src/main/java/electroblob/wizardry/spell/Freeze.java | 4 ++-- .../java/electroblob/wizardry/spell/FrostRay.java | 5 +++-- src/main/java/electroblob/wizardry/spell/Ignite.java | 4 ++-- .../electroblob/wizardry/spell/LightningRay.java | 6 +++--- .../electroblob/wizardry/spell/LightningWeb.java | 6 +++--- .../java/electroblob/wizardry/spell/MindControl.java | 4 ++-- src/main/java/electroblob/wizardry/spell/Poison.java | 4 ++-- src/main/java/electroblob/wizardry/spell/Slime.java | 4 ++-- .../electroblob/wizardry/spell/Transportation.java | 6 +++--- src/main/java/electroblob/wizardry/spell/Wither.java | 4 ++-- 15 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/main/java/electroblob/wizardry/spell/Arc.java b/src/main/java/electroblob/wizardry/spell/Arc.java index e543790d..4da75483 100644 --- a/src/main/java/electroblob/wizardry/spell/Arc.java +++ b/src/main/java/electroblob/wizardry/spell/Arc.java @@ -39,8 +39,9 @@ public class Arc extends SpellRay { // This is a lot neater than it was, thanks to the damage type system. if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", + target.getName(), this.getNameForTranslationFormatted()), true); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); diff --git a/src/main/java/electroblob/wizardry/spell/ChainLightning.java b/src/main/java/electroblob/wizardry/spell/ChainLightning.java index 8e6bfb72..36bfa78d 100644 --- a/src/main/java/electroblob/wizardry/spell/ChainLightning.java +++ b/src/main/java/electroblob/wizardry/spell/ChainLightning.java @@ -96,8 +96,9 @@ public class ChainLightning extends SpellRay { private void electrocute(World world, Entity caster, Entity origin, Entity target, float damage){ if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), + true); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage); } diff --git a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java index 0b582f15..870f994a 100644 --- a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java +++ b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java @@ -57,7 +57,7 @@ public class Clairvoyance extends Spell { if(caster.dimension == properties.getClairvoyanceDimension()){ if(properties.getClairvoyanceLocation() != null){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".searching")); + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".searching"), true); EntityZombie arbitraryZombie = new EntityZombie(world){ @Override @@ -96,13 +96,13 @@ public class Clairvoyance extends Spell { } } - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".outofrange")); + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".outofrange"), true); }else{ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".undefined")); + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".undefined"), true); } }else{ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".wrongdimension")); + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".wrongdimension"), true); } } @@ -158,8 +158,8 @@ public class Clairvoyance extends Spell { properties.setClairvoyancePoint(pos, event.getWorld().provider.getDimension()); if(!event.getWorld().isRemote){ - event.getEntityPlayer().sendMessage( - new TextComponentTranslation("spell." + Spells.clairvoyance.getUnlocalisedName() + ".confirm", Spells.clairvoyance.getNameForTranslationFormatted())); + event.getEntityPlayer().sendStatusMessage( + new TextComponentTranslation("spell." + Spells.clairvoyance.getUnlocalisedName() + ".confirm", Spells.clairvoyance.getNameForTranslationFormatted()), true); } event.setCanceled(true); diff --git a/src/main/java/electroblob/wizardry/spell/Firestorm.java b/src/main/java/electroblob/wizardry/spell/Firestorm.java index 55bdd341..fc15aa2e 100644 --- a/src/main/java/electroblob/wizardry/spell/Firestorm.java +++ b/src/main/java/electroblob/wizardry/spell/Firestorm.java @@ -67,8 +67,9 @@ public class Firestorm extends SpellRay { if(target instanceof EntityLivingBase){ if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ - if(!world.isRemote && ticksInUse == 1) caster.sendMessage(new TextComponentTranslation("spell.resist", - target.getName(), this.getNameForTranslationFormatted())); + if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster) + .sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); }else{ target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); WizardryUtilities.attackEntityWithoutKnockback(target, diff --git a/src/main/java/electroblob/wizardry/spell/FlameRay.java b/src/main/java/electroblob/wizardry/spell/FlameRay.java index 71e686fd..893d9284 100644 --- a/src/main/java/electroblob/wizardry/spell/FlameRay.java +++ b/src/main/java/electroblob/wizardry/spell/FlameRay.java @@ -65,9 +65,10 @@ public class FlameRay extends SpellRay { if(target instanceof EntityLivingBase){ if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ - if(!world.isRemote && ticksInUse == 1) caster.sendMessage(new TextComponentTranslation("spell.resist", - target.getName(), this.getNameForTranslationFormatted())); - }else { + if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster) + .sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); + }else{ target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), diff --git a/src/main/java/electroblob/wizardry/spell/Freeze.java b/src/main/java/electroblob/wizardry/spell/Freeze.java index 3347b566..ab335bc6 100644 --- a/src/main/java/electroblob/wizardry/spell/Freeze.java +++ b/src/main/java/electroblob/wizardry/spell/Freeze.java @@ -47,8 +47,8 @@ public class Freeze extends SpellRay { } if(MagicDamage.isEntityImmune(DamageType.FROST, target)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost, (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1)); diff --git a/src/main/java/electroblob/wizardry/spell/FrostRay.java b/src/main/java/electroblob/wizardry/spell/FrostRay.java index 47c36b37..6aa97807 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostRay.java +++ b/src/main/java/electroblob/wizardry/spell/FrostRay.java @@ -70,8 +70,9 @@ public class FrostRay extends SpellRay { if(target.isBurning()) target.extinguish(); if(MagicDamage.isEntityImmune(DamageType.FROST, target)){ - if(!world.isRemote && ticksInUse == 1) caster.sendMessage(new TextComponentTranslation("spell.resist", - target.getName(), this.getNameForTranslationFormatted())); + if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster) + .sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); }else{ // For frost ray the entity can move slightly, unlike freeze ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost, diff --git a/src/main/java/electroblob/wizardry/spell/Ignite.java b/src/main/java/electroblob/wizardry/spell/Ignite.java index 145607f3..0acbe1c5 100644 --- a/src/main/java/electroblob/wizardry/spell/Ignite.java +++ b/src/main/java/electroblob/wizardry/spell/Ignite.java @@ -33,8 +33,8 @@ public class Ignite extends SpellRay { if(target instanceof EntityLivingBase) { if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); } diff --git a/src/main/java/electroblob/wizardry/spell/LightningRay.java b/src/main/java/electroblob/wizardry/spell/LightningRay.java index 3521b3d5..ce6ddd15 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningRay.java +++ b/src/main/java/electroblob/wizardry/spell/LightningRay.java @@ -62,9 +62,9 @@ public class LightningRay extends SpellRay { if(WizardryUtilities.isLiving(target)){ if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ - if(!world.isRemote && ticksInUse == 1) - caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) + ((EntityPlayer)caster).sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); }else{ WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), diff --git a/src/main/java/electroblob/wizardry/spell/LightningWeb.java b/src/main/java/electroblob/wizardry/spell/LightningWeb.java index 8f5f1256..cdc11ea2 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningWeb.java +++ b/src/main/java/electroblob/wizardry/spell/LightningWeb.java @@ -143,9 +143,9 @@ public class LightningWeb extends SpellRay { private void electrocute(World world, Entity caster, Entity origin, Entity target, float damage, int ticksInUse){ if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ - if(!world.isRemote && ticksInUse == 1) - caster.sendMessage(new TextComponentTranslation("spell.resist", - target.getName(), this.getNameForTranslationFormatted())); + if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) + ((EntityPlayer)caster).sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); }else{ WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage); diff --git a/src/main/java/electroblob/wizardry/spell/MindControl.java b/src/main/java/electroblob/wizardry/spell/MindControl.java index 0c10155b..a472cf92 100644 --- a/src/main/java/electroblob/wizardry/spell/MindControl.java +++ b/src/main/java/electroblob/wizardry/spell/MindControl.java @@ -54,8 +54,8 @@ public class MindControl extends SpellRay { if(!canControl(target)){ // Adds a message saying that the player/boss entity/wizard resisted mind control - caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + ((EntityPlayer)caster).sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); }else if(target instanceof EntityLiving){ diff --git a/src/main/java/electroblob/wizardry/spell/Poison.java b/src/main/java/electroblob/wizardry/spell/Poison.java index 057f0f2c..a08a5920 100644 --- a/src/main/java/electroblob/wizardry/spell/Poison.java +++ b/src/main/java/electroblob/wizardry/spell/Poison.java @@ -41,8 +41,8 @@ public class Poison extends SpellRay { // Has no effect on undead or spiders. if(MagicDamage.isEntityImmune(DamageType.POISON, target)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), 1 * modifiers.get(SpellModifiers.POTENCY)); diff --git a/src/main/java/electroblob/wizardry/spell/Slime.java b/src/main/java/electroblob/wizardry/spell/Slime.java index b972686b..9b9e53fe 100644 --- a/src/main/java/electroblob/wizardry/spell/Slime.java +++ b/src/main/java/electroblob/wizardry/spell/Slime.java @@ -54,8 +54,8 @@ public class Slime extends SpellRay { if(WizardryUtilities.isLiving(target) && !(target instanceof EntityMagicSlime)){ if(target instanceof EntitySlime){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ if(target instanceof EntitySkeleton && caster instanceof EntityPlayer) diff --git a/src/main/java/electroblob/wizardry/spell/Transportation.java b/src/main/java/electroblob/wizardry/spell/Transportation.java index 2e91f4dd..cbb838d0 100644 --- a/src/main/java/electroblob/wizardry/spell/Transportation.java +++ b/src/main/java/electroblob/wizardry/spell/Transportation.java @@ -46,15 +46,15 @@ public class Transportation extends Spell { return true; }else{ if(!world.isRemote) - caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".missing")); + caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".missing"), true); } }else{ if(!world.isRemote) - caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".undefined")); + caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".undefined"), true); } }else{ if(!world.isRemote) - caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".wrongdimension")); + caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".wrongdimension"), true); } } return false; diff --git a/src/main/java/electroblob/wizardry/spell/Wither.java b/src/main/java/electroblob/wizardry/spell/Wither.java index 54d260fb..9055c0c4 100644 --- a/src/main/java/electroblob/wizardry/spell/Wither.java +++ b/src/main/java/electroblob/wizardry/spell/Wither.java @@ -37,8 +37,8 @@ public class Wither extends SpellRay { // Has no effect on withers or wither skeletons. if(MagicDamage.isEntityImmune(DamageType.WITHER, target)){ - if(!world.isRemote) caster.sendMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted())); + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); From f6f36a30fd7059a1318fdc466f641d5b8b9129ac Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 6 Jan 2019 15:35:18 +0000 Subject: [PATCH 64/68] Register resource reload listener for handbook, missed in 1356905 --- src/main/java/electroblob/wizardry/CommonProxy.java | 2 +- src/main/java/electroblob/wizardry/client/ClientProxy.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index 6347dea8..7e45ebe8 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -49,7 +49,7 @@ public class CommonProxy { public void initGuiBits(){} - public void registerResourceReloadListener(){} + public void registerResourceReloadListeners(){} // SECTION Particles // =============================================================================================================== diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 685455be..9cd21404 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -172,15 +172,15 @@ public class ClientProxy extends CommonProxy { public void initGuiBits(){ mixedFontRenderer = new MixedFontRenderer(Minecraft.getMinecraft().gameSettings, new ResourceLocation("textures/font/ascii.png"), Minecraft.getMinecraft().renderEngine, false); - GuiWizardHandbook.initDisplayRecipes(); } @Override - public void registerResourceReloadListener(){ + public void registerResourceReloadListeners(){ IResourceManager manager = Minecraft.getMinecraft().getResourceManager(); if(manager instanceof IReloadableResourceManager){ ((IReloadableResourceManager)manager).registerReloadListener(GuiSpellDisplay::loadSkins); - } + ((IReloadableResourceManager)manager).registerReloadListener(GuiWizardHandbook::loadHandbookFile); + } } // SECTION Misc From 31673cf247062401daa2905ff846095182b0136c Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 6 Jan 2019 15:35:56 +0000 Subject: [PATCH 65/68] Missed in b374f71 --- src/main/java/electroblob/wizardry/client/ClientProxy.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 9cd21404..910938eb 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -306,11 +306,6 @@ public class ClientProxy extends CommonProxy { IBlockState block, BlockPos pos){ Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTornado(world, maxAge, x, z, radius, y, velX, velZ, block).setBlockPos(pos));// , world.rand.nextInt(6))); } - - @Override - public void spawnEntityParticle(World world, Entity entity, int maxAge, float r, float g, float b){ - Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleBuff(world, entity, maxAge, r, g, b, world.rand.nextBoolean())); - } // SECTION Packet Handlers // =============================================================================================================== From f564fdce60043a4561d0b958dbb2a206a72b8b7c Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 6 Jan 2019 17:51:41 +0000 Subject: [PATCH 66/68] Add DamageSafetyChecker, which implements an if-all-else-fails fix for cross-mod infinite looping in attack/hurt/damage events, and changes relevant calls to attack methods to use the safety checker methods instead. Also adds damage source blacklist and compatibility warnings config options. Fixes #72. --- .../java/electroblob/wizardry/WizardData.java | 7 +- .../wizardry/WizardryEventHandler.java | 10 +- .../entity/living/ISummonedCreature.java | 7 +- .../integration/DamageSafetyChecker.java | 148 ++++++++++++++++++ .../wizardry/spell/CurseOfSoulbinding.java | 2 +- .../wizardry/spell/ShadowWard.java | 3 +- 6 files changed, 165 insertions(+), 12 deletions(-) create mode 100644 src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java diff --git a/src/main/java/electroblob/wizardry/WizardData.java b/src/main/java/electroblob/wizardry/WizardData.java index 1ca6f9e7..fd27d9c0 100644 --- a/src/main/java/electroblob/wizardry/WizardData.java +++ b/src/main/java/electroblob/wizardry/WizardData.java @@ -15,6 +15,7 @@ import electroblob.wizardry.entity.EntityShield; import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent.Source; +import electroblob.wizardry.integration.DamageSafetyChecker; import electroblob.wizardry.packet.PacketCastContinuousSpell; import electroblob.wizardry.packet.PacketPlayerSync; import electroblob.wizardry.packet.PacketTransportation; @@ -344,7 +345,7 @@ public class WizardData implements INBTSerializable { * Damages all creatures soulbound to this player by the given amount, and removes from the list any that no longer * exist. */ - public void damageAllSoulboundCreatures(float damage){ + public void damageAllSoulboundCreatures(float damage, String originalSourceName){ for(Iterator iterator = this.soulboundCreatures.iterator(); iterator.hasNext();){ @@ -354,8 +355,8 @@ public class WizardData implements INBTSerializable { if(entity instanceof EntityLivingBase){ // Retaliatory effect - if(entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(this.player, DamageType.MAGIC, true), - damage)){ + if(DamageSafetyChecker.attackEntitySafely(entity, MagicDamage.causeDirectMagicDamage(this.player, + DamageType.MAGIC, true), damage, originalSourceName)){ // Sound only plays if the damage succeeds player.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, player.world.rand.nextFloat() * 0.2F + 1.0F); } diff --git a/src/main/java/electroblob/wizardry/WizardryEventHandler.java b/src/main/java/electroblob/wizardry/WizardryEventHandler.java index 32da4e75..ebebcb77 100644 --- a/src/main/java/electroblob/wizardry/WizardryEventHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryEventHandler.java @@ -7,6 +7,7 @@ import electroblob.wizardry.entity.living.ISpellCaster; import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.event.DiscoverSpellEvent; import electroblob.wizardry.event.SpellCastEvent; +import electroblob.wizardry.integration.DamageSafetyChecker; import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.item.ItemWizardArmour; import electroblob.wizardry.registry.Spells; @@ -17,8 +18,6 @@ import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.FreezingWeapon; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.IElementalDamage; -import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.SpellModifiers; @@ -40,6 +39,7 @@ import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemSword; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; @@ -217,9 +217,9 @@ public final class WizardryEventHandler { attacker.getEntityBoundingBox().minY + attacker.height, attacker.posZ); } - attacker.attackEntityFrom( - MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.SHOCK, true), 4.0f); - attacker.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + DamageSafetyChecker.attackEntitySafely(attacker, MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), + DamageType.SHOCK, true), 4.0f, event.getSource().getDamageType()); + attacker.playSound(WizardrySounds.SPELL_STATIC_AURA_RETALIATE, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java index b510dc9c..5e27cb57 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java @@ -10,6 +10,7 @@ import com.google.common.base.Predicate; import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.integration.DamageSafetyChecker; import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.util.IElementalDamage; import electroblob.wizardry.util.IndirectMinionDamage; @@ -383,8 +384,10 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { // For some reason Minecraft calculates knockback relative to DamageSource#getTrueSource. In vanilla this // is unnoticeable, but it looks a bit weird with summoned creatures involved - so this fixes that. - if(WizardryUtilities.attackEntityWithoutKnockback(event.getEntity(), newSource, event.getAmount())){ - // Using event.getSource().getTrueSource() as this means the target is knocked back from the minion + // Damage safety checker falls back to the original damage source, so it behaves as if the creature has + // no summoner. + if(DamageSafetyChecker.attackEntitySafely(event.getEntity(), newSource, event.getAmount(), event.getSource(), false)){ + // Uses event.getSource().getTrueSource() as this means the target is knocked back from the minion WizardryUtilities.applyStandardKnockback(event.getSource().getTrueSource(), event.getEntityLiving()); ((ISummonedCreature)event.getSource().getTrueSource()).onSuccessfulAttack(event.getEntityLiving()); // If the target revenge-targeted the summoner, make it revenge-target the minion instead diff --git a/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java b/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java new file mode 100644 index 00000000..5e3dfefd --- /dev/null +++ b/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java @@ -0,0 +1,148 @@ +package electroblob.wizardry.integration; + +import com.google.common.collect.ImmutableSet; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.util.DamageSource; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.Set; + +/** + * This class implements an 'if-all-else-fails' fix for cross-mod infinite looping caused by re-applying damage in + * attack events (see GitHub issue #72 for details). + * The methods in this class should only be used when intercepting one of the attack/damage events and + * dealing damage from within it. + */ +@Mod.EventBusSubscriber +public final class DamageSafetyChecker { + + /** We don't want to tell users to add any of these to the blacklist, as that would be problematic. */ + // NOTE: Make sure this is updated for each new version of Minecraft + private static final Set VANILLA_DAMAGE_NAMES = ImmutableSet.of("inFire", "lightningBolt", "onFire", + "lava", "hotFloor", "inWall", "cramming", "drown", "starve", "cactus", "fall", "flyIntoWall", "outOfWorld", + "generic", "magic", "wither", "anvil", "fallingBlock", "dragonBreath", "fireworks", "mob", "player", "arrow", + "thrown", "indirectMagic", "thorns", "explosion", "explosion.player"); + + /** + * Global counter which is incremented once for each call to + * {@link DamageSafetyChecker#attackEntitySafely(Entity, DamageSource, float, String, DamageSource, boolean)} + * This allows for detection and avoidance of imminent StackOverflowErrors caused by looping between mods. + */ + private static int attacksThisTick = 0; + + /** The number of calls per loaded entity after which damage will be reassigned. */ + private static final int EXCESSIVE_CALL_THRESHOLD = 50; + /** The number of calls per loaded entity after which damage will be cancelled entirely. */ + private static final int EXCESSIVE_CALL_LIMIT = 100; + + /** + * Attacks the specified target with specified damage source and damage amount, checking for the blacklist and + * excessive looping in the process. Under normal circumstances, this method simply calls + * {@code target.attackEntityFrom(...)}. If excessive looping is detected, the damage source is substituted for + * the given fallback instead, and a warning is printed to the console. + *

    + * This method should only be used within the attack events (LivingAttackEvent, LivingHurtEvent, LivingDamageEvent + * and possibly LivingKnockBackEvent, depending on the circumstances). + * @param target The target to apply the damage to. + * @param source The source of the damage. + * @param damage The amount of damage to be applied. + * @param originalSourceName The string identifier for the original damage source (i.e. the one being replaced). + * This allows wizardry to request that users add it to the blacklist. + * @param fallback The fallback damage source for when excessive looping is detected. This must not be the + * same as the re-applied source, or this method is pointless! Usually it will be more general. + * @param knockback True to apply knockback as normal, false to use the knockback-free methods in WizardryUtilities. + * {@link WizardryUtilities#attackEntityWithoutKnockback(Entity, DamageSource, float)}. + */ + public static boolean attackEntitySafely(Entity target, DamageSource source, float damage, + String originalSourceName, DamageSource fallback, boolean knockback){ + + for(String sourceName : Wizardry.settings.damageSourceBlacklist){ + if(originalSourceName.equals(sourceName)){ + // Blacklist behaviour + // Same as fallback behaviour, but without the log message + attacksThisTick++; + return knockback ? target.attackEntityFrom(fallback, damage) + : WizardryUtilities.attackEntityWithoutKnockback(target, fallback, damage); + } + } + + if(attacksThisTick > EXCESSIVE_CALL_LIMIT * target.world.loadedEntityList.size()){ + // This should never ever happen unless another mod is intercepting non-entity-based damage and damaging + // the same target. + logInterception(originalSourceName, true); + return false; + } + + if(attacksThisTick > EXCESSIVE_CALL_THRESHOLD * target.world.loadedEntityList.size()){ + // Sometimes this is unavoidable, it's neither mod's fault but without some kind of forge standard or + // universal cooperation there's no easy way to prevent it. + logInterception(originalSourceName, false); + // Fallback behaviour + attacksThisTick++; + return knockback ? target.attackEntityFrom(fallback, damage) + : WizardryUtilities.attackEntityWithoutKnockback(target, fallback, damage); + + }else{ + // Normal behaviour + attacksThisTick++; + return knockback ? target.attackEntityFrom(source, damage) + : WizardryUtilities.attackEntityWithoutKnockback(target, source, damage); + } + } + + /** + * See {@link DamageSafetyChecker#attackEntitySafely(Entity, DamageSource, float, String, DamageSource, boolean)}. + * This version is for when the original source is used as a fallback, i.e. when a damage source is being replaced + * for technical reasons (e.g. summoned creatures) rather than as part of a game mechanic (e.g. shadow ward). + */ + public static boolean attackEntitySafely(Entity target, DamageSource source, float damage, DamageSource originalSource, boolean knockback){ + return attackEntitySafely(target, source, damage, originalSource.getDamageType(), originalSource, knockback); + } + + /** + * See {@link DamageSafetyChecker#attackEntitySafely(Entity, DamageSource, float, String, DamageSource, boolean)}. + * Fallback defaults to {@link DamageSource#MAGIC} and knockback defaults to true. + */ + public static boolean attackEntitySafely(Entity target, DamageSource source, float damage, String originalSourceName){ + return attackEntitySafely(target, source, damage, originalSourceName, DamageSource.MAGIC, true); + } + + /** Prints the appropriate message about the damage interception to the console. */ + private static void logInterception(String originalSourceName, boolean aborted){ + + if(!Wizardry.settings.compatibilityWarnings) return; // No warnings if they're disabled! + + boolean vanillaName = VANILLA_DAMAGE_NAMES.contains(originalSourceName); + + if(aborted){ + Wizardry.logger.warn("Entity attack excessive call limit exceeded, aborting entity damage entirely!"); + }else{ + Wizardry.logger.warn("Entity attack excessive call threshold exceeded, substituting for non-entity-based " + + "damage to avert a crash."); + } + + if(vanillaName){ + Wizardry.logger.info("The damage source in question had a vanilla identifier. If you know which mod may " + + "have caused this, consider asking the author to add a custom identifier so it may be blacklisted. " + + "You can turn this warning off using the compatibilityWarnings config option. Please do not report " + + "it to wizardry's author."); + }else{ + Wizardry.logger.info("To prevent this message and improve efficiency, add \"" + originalSourceName + "\" " + + "(without quotes) to the damage source blacklist in the config. Please do not report " + + "this warning unless you have added the damage source to the blacklist already."); + } + } + + @SubscribeEvent + public static void tick(TickEvent event){ + // We actually want this to fire on both sides, because attacks are common code. + if(event.phase == TickEvent.Phase.START && event.type == TickEvent.Type.WORLD){ + attacksThisTick = 0; // Reset the attack call counter + } + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java index d6e73fb2..76797c44 100644 --- a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java +++ b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java @@ -67,7 +67,7 @@ public class CurseOfSoulbinding extends SpellRay { && ((IElementalDamage)event.getSource()).isRetaliatory())){ WizardData data = WizardData.get((EntityPlayer)event.getEntityLiving()); if(data != null){ - data.damageAllSoulboundCreatures(event.getAmount()); + data.damageAllSoulboundCreatures(event.getAmount(), event.getSource().getDamageType()); } } } diff --git a/src/main/java/electroblob/wizardry/spell/ShadowWard.java b/src/main/java/electroblob/wizardry/spell/ShadowWard.java index 6c1db4c4..7d2736ea 100644 --- a/src/main/java/electroblob/wizardry/spell/ShadowWard.java +++ b/src/main/java/electroblob/wizardry/spell/ShadowWard.java @@ -4,6 +4,7 @@ import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.integration.DamageSafetyChecker; import electroblob.wizardry.util.IElementalDamage; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; @@ -62,7 +63,7 @@ public class ShadowWard extends Spell { // For some reason this isn't working, so I've reverted to plain old magic damage for now. //event.getEntityLiving().attackEntityFrom( // MagicDamage.causeDirectMagicDamage(event.getSource().getTrueSource(), DamageType.MAGIC, true), event.getAmount() * 0.5f); - event.getEntityLiving().attackEntityFrom(DamageSource.MAGIC, event.getAmount() * 0.5f); + DamageSafetyChecker.attackEntitySafely(event.getEntity(), DamageSource.MAGIC, event.getAmount() * 0.5f, event.getSource().getDamageType()); ((EntityLivingBase)event.getSource().getTrueSource()).attackEntityFrom( MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.MAGIC, true), event.getAmount() * 0.5f); } From 2680d02304e97362c56278fceb91273901c23b8d Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 6 Jan 2019 18:00:24 +0000 Subject: [PATCH 67/68] Reduce excessive call limits based on crash report in issue #72 --- .../wizardry/integration/DamageSafetyChecker.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java b/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java index 5e3dfefd..cb3ea34b 100644 --- a/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java +++ b/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java @@ -35,9 +35,12 @@ public final class DamageSafetyChecker { private static int attacksThisTick = 0; /** The number of calls per loaded entity after which damage will be reassigned. */ - private static final int EXCESSIVE_CALL_THRESHOLD = 50; + // It's a fair bet that if an entity is being damaged 15 times in a single tick, then something is wrong! + // Based on the crash report in issue #72, there were approximately 38 calls before the error was thrown. + // The number of calls will vary depending on the stack size and possibly what else is happening at the time. + private static final int EXCESSIVE_CALL_THRESHOLD = 15; /** The number of calls per loaded entity after which damage will be cancelled entirely. */ - private static final int EXCESSIVE_CALL_LIMIT = 100; + private static final int EXCESSIVE_CALL_LIMIT = 25; /** * Attacks the specified target with specified damage source and damage amount, checking for the blacklist and From f37812be3ec4ddc1f6d89bede6e478b2c7c53bad Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sun, 18 Aug 2019 00:04:18 +0100 Subject: [PATCH 68/68] That's one heck of a commit you've got there... I may have got a bit behind with version control. A lot behind, in fact. Maybe I'll go back and split this sometime - then again, I probably won't. But hey, at least it's here! --- .gitignore | 7 +- build.gradle | 39 +- gradle.properties | 2 + gradlew | 4 +- gradlew.bat | 4 +- .../electroblob/wizardry/CommonProxy.java | 164 +- .../java/electroblob/wizardry/Settings.java | 705 +++++-- .../java/electroblob/wizardry/Wizardry.java | 176 +- .../wizardry/WizardryEventHandler.java | 479 ++--- .../wizardry/WizardryGuiFactory.java | 6 +- .../wizardry/WizardryGuiHandler.java | 7 +- .../wizardry/WizardryWorldGenerator.java | 949 --------- .../advancement/ArcaneWorkbenchTrigger.java | 135 ++ .../CustomAdvancementTrigger.java | 5 +- .../advancement/SpellCastTrigger.java | 139 ++ .../advancement/SpellDiscoveryTrigger.java | 143 ++ .../wizardry/advancement/SpellPredicate.java | 117 ++ .../advancement/StructureTrigger.java | 136 ++ .../wizardry/api/WizardryEnumHelper.java | 96 + .../wizardry/block/BlockArcaneWorkbench.java | 11 + .../wizardry/block/BlockCrystal.java | 76 + .../wizardry/block/BlockCrystalFlower.java | 4 +- .../wizardry/block/BlockCrystalOre.java | 4 +- .../wizardry/block/BlockDryFrostedIce.java | 28 + .../wizardry/block/BlockMagicLight.java | 49 +- .../wizardry/block/BlockObsidianCrust.java | 116 ++ .../wizardry/block/BlockPedestal.java | 123 ++ .../wizardry/block/BlockRunestone.java | 85 + .../wizardry/block/BlockSnare.java | 25 +- .../wizardry/block/BlockSpectral.java | 15 +- .../wizardry/block/BlockStatue.java | 31 +- .../wizardry/block/BlockThorns.java | 181 ++ .../block/BlockTransportationStone.java | 109 +- .../wizardry/block/BlockVanishingCobweb.java | 18 +- .../wizardry/client/ClientProxy.java | 473 +++-- .../wizardry/client/DrawingUtils.java | 39 +- .../wizardry/client/MixedFontRenderer.java | 4 +- .../wizardry/client/MovingSoundEntity.java | 52 - .../client/WizardryClientEventHandler.java | 550 ++--- .../client/WizardryControlHandler.java | 95 +- .../client/audio/MovingSoundEntity.java | 35 + .../wizardry/client/audio/SoundLoop.java | 94 + .../wizardry/client/audio/SoundLoopSpell.java | 117 ++ .../client/gui/GuiArcaneWorkbench.java | 452 ++-- .../client/gui/GuiButtonInvisible.java | 4 +- .../client/gui/GuiButtonResurrect.java | 90 + .../wizardry/client/gui/GuiSpellBook.java | 53 +- .../wizardry/client/gui/GuiSpellDisplay.java | 113 +- .../{ => gui/config}/EntityNameEntry.java | 16 +- .../gui/{ => config}/GuiConfigWizardry.java | 75 +- .../gui/{ => config}/GuiSelectHUDSkin.java | 13 +- .../client/gui/config/NamedBooleanEntry.java | 93 + .../config}/SpellHUDSkinChooserEntry.java | 17 +- .../client/gui/handbook/Contents.java | 49 +- .../client/gui/handbook/CraftingRecipe.java | 73 +- .../gui/handbook/GuiButtonHyperlink.java | 70 +- .../gui/handbook/GuiButtonTurnPage.java | 4 +- .../gui/handbook/GuiWizardHandbook.java | 106 +- .../client/gui/handbook/HandbookToast.java | 54 + .../wizardry/client/gui/handbook/Image.java | 31 +- .../wizardry/client/gui/handbook/Section.java | 132 +- .../model/BakedModelGlowingOverlay.java | 234 +++ .../wizardry/client/model/ModelIceGiant.java | 10 +- .../wizardry/client/model/ModelWizard.java | 8 +- .../client/model/ModelWizardArmour.java | 153 +- .../client/model/WizardryItemModels.java | 197 -- .../wizardry/client/model/WizardryModels.java | 343 ++++ .../client/particle/ParticleBeam.java | 14 +- .../client/particle/ParticleBuff.java | 65 +- .../client/particle/ParticleDarkMagic.java | 4 +- .../client/particle/ParticleDust.java | 6 +- .../client/particle/ParticleFlash.java | 13 +- .../wizardry/client/particle/ParticleIce.java | 3 +- .../client/particle/ParticleLeaf.java | 5 +- .../client/particle/ParticleLightning.java | 18 +- .../particle/ParticleLightningPulse.java | 10 +- .../client/particle/ParticleMagicBubble.java | 4 +- .../client/particle/ParticleMagicFlame.java | 50 +- .../client/particle/ParticlePath.java | 8 +- .../client/particle/ParticleScorch.java | 12 +- .../client/particle/ParticleSnow.java | 5 +- .../client/particle/ParticleSpark.java | 11 +- .../client/particle/ParticleSparkle.java | 3 +- .../client/particle/ParticleSphere.java | 131 ++ .../client/particle/ParticleSummon.java | 132 ++ .../client/particle/ParticleTargeted.java | 97 +- .../client/particle/ParticleTornado.java | 17 +- .../client/particle/ParticleVine.java | 154 ++ .../client/particle/ParticleWizardry.java | 280 ++- .../wizardry/client/renderer/LayerFrost.java | 153 ++ .../wizardry/client/renderer/LayerStone.java | 19 +- .../renderer/LayerStrayMinionClothing.java | 33 + .../client/renderer/RenderArcaneLock.java | 89 + .../renderer/RenderArcaneWorkbench.java | 21 +- .../client/renderer/RenderBlackHole.java | 40 +- .../client/renderer/RenderBubble.java | 3 +- .../renderer/RenderContainmentField.java | 268 +++ .../wizardry/client/renderer/RenderDecay.java | 3 +- .../wizardry/client/renderer/RenderDecoy.java | 10 +- .../client/renderer/RenderEvilWizard.java | 4 +- .../client/renderer/RenderFireRing.java | 3 +- .../client/renderer/RenderForceArrow.java | 7 +- .../client/renderer/RenderForcefield.java | 124 ++ .../client/renderer/RenderHammer.java | 4 +- .../client/renderer/RenderIceGiant.java | 4 +- .../client/renderer/RenderIceSpike.java | 10 +- .../client/renderer/RenderLightningDisc.java | 3 +- .../client/renderer/RenderMagicArrow.java | 7 +- .../client/renderer/RenderMagicLight.java | 29 +- .../client/renderer/RenderPhoenix.java | 7 +- .../renderer/RenderPossessingPlayer.java | 41 + .../client/renderer/RenderProjectile.java | 7 +- .../client/renderer/RenderShadowWard.java | 148 ++ .../client/renderer/RenderShield.java | 168 ++ .../wizardry/client/renderer/RenderSigil.java | 9 +- .../client/renderer/RenderSpiritHorse.java | 41 +- .../client/renderer/RenderSpiritWolf.java | 37 +- .../client/renderer/RenderStrayMinion.java | 24 + .../renderer/RenderTransportationUI.java | 177 ++ .../wizardry/client/renderer/RenderWings.java | 113 + .../client/renderer/RenderWizard.java | 4 +- .../client/renderer/RenderWraithMinion.java | 4 +- .../wizardry/command/CommandCastSpell.java | 204 +- .../command/CommandDiscoverSpell.java | 39 +- .../wizardry/command/CommandSetAlly.java | 43 +- .../wizardry/command/CommandViewAllies.java | 20 +- .../wizardry/command/SpellEmitter.java | 177 ++ .../wizardry/constants/Constants.java | 26 +- .../wizardry/constants/Element.java | 51 +- .../wizardry/constants/SpellType.java | 18 +- .../electroblob/wizardry/constants/Tier.java | 51 +- .../wizardry/data/BlockCastingData.java | 183 ++ .../wizardry/data/DispenserCastingData.java | 219 ++ .../wizardry/data/IStoredVariable.java | 256 +++ .../electroblob/wizardry/data/IVariable.java | 118 ++ .../wizardry/data/Persistence.java | 25 + .../wizardry/data/SpellEmitterData.java | 128 ++ .../wizardry/{ => data}/SpellGlyphData.java | 39 +- .../wizardry/{ => data}/WizardData.java | 530 +++-- .../EnchantmentMagicProtection.java | 111 + .../wizardry/enchantment/Imbuement.java | 16 +- .../entity/EntityLevitatingBlock.java | 296 +++ .../wizardry/entity/EntityMeteor.java | 37 +- .../wizardry/entity/EntityShield.java | 28 +- .../wizardry/entity/ICustomHitbox.java | 31 + .../entity/construct/EntityArrowRain.java | 5 +- .../entity/construct/EntityBlackHole.java | 72 +- .../entity/construct/EntityBlizzard.java | 16 +- .../entity/construct/EntityBubble.java | 23 +- .../construct/EntityCombustionRune.java | 58 + .../entity/construct/EntityDecay.java | 18 +- .../entity/construct/EntityEarthquake.java | 91 +- .../entity/construct/EntityFireRing.java | 23 +- .../entity/construct/EntityFireSigil.java | 23 +- .../entity/construct/EntityForcefield.java | 357 +++- .../entity/construct/EntityFrostSigil.java | 20 +- .../entity/construct/EntityHailstorm.java | 5 +- .../entity/construct/EntityHammer.java | 174 +- .../entity/construct/EntityHealAura.java | 21 +- .../entity/construct/EntityIceSpike.java | 47 +- .../construct/EntityLightningSigil.java | 28 +- .../construct/EntityMagicConstruct.java | 73 +- .../entity/construct/EntityTornado.java | 122 +- .../entity/living/EntityAIAttackSpell.java | 26 +- .../entity/living/EntityBlazeMinion.java | 39 +- .../wizardry/entity/living/EntityDecoy.java | 30 +- .../entity/living/EntityEvilWizard.java | 144 +- .../entity/living/EntityHuskMinion.java | 42 + .../entity/living/EntityIceGiant.java | 39 +- .../entity/living/EntityIceWraith.java | 27 +- .../entity/living/EntityLightningWraith.java | 25 +- .../entity/living/EntityMagicSlime.java | 30 +- .../wizardry/entity/living/EntityPhoenix.java | 22 +- .../entity/living/EntityShadowWraith.java | 24 +- .../entity/living/EntitySilverfishMinion.java | 38 +- .../entity/living/EntitySkeletonMinion.java | 55 +- .../entity/living/EntitySpiderMinion.java | 31 +- .../entity/living/EntitySpiritHorse.java | 57 +- .../entity/living/EntitySpiritWolf.java | 61 +- .../entity/living/EntityStormElemental.java | 25 +- .../entity/living/EntityStrayMinion.java | 35 + .../entity/living/EntitySummonedCreature.java | 35 +- .../entity/living/EntityVexMinion.java | 151 ++ .../living/EntityWitherSkeletonMinion.java | 37 +- .../wizardry/entity/living/EntityWizard.java | 272 +-- .../entity/living/EntityZombieMinion.java | 33 +- .../living/IIntelligentSpellCaster.java | 4 +- .../wizardry/entity/living/ISpellCaster.java | 11 +- .../entity/living/ISummonedCreature.java | 224 +- .../entity/projectile/EntityDarknessOrb.java | 22 +- .../entity/projectile/EntityDart.java | 20 +- .../entity/projectile/EntityEmber.java | 87 + .../entity/projectile/EntityFirebolt.java | 32 +- .../entity/projectile/EntityFirebomb.java | 30 +- .../entity/projectile/EntityForceArrow.java | 69 +- .../entity/projectile/EntityForceOrb.java | 23 +- .../entity/projectile/EntityIceCharge.java | 74 +- .../entity/projectile/EntityIceLance.java | 21 +- .../entity/projectile/EntityIceShard.java | 21 +- .../entity/projectile/EntityIceball.java | 117 ++ .../projectile/EntityLargeMagicFireball.java | 106 + .../projectile/EntityLightningArrow.java | 28 +- .../projectile/EntityLightningDisc.java | 55 +- .../entity/projectile/EntityMagicArrow.java | 103 +- .../projectile/EntityMagicFireball.java | 198 ++ .../entity/projectile/EntityMagicMissile.java | 19 +- .../projectile/EntityMagicProjectile.java | 94 +- .../entity/projectile/EntityPoisonBomb.java | 35 +- .../entity/projectile/EntitySmokeBomb.java | 26 +- .../entity/projectile/EntitySpark.java | 56 +- .../entity/projectile/EntitySparkBomb.java | 30 +- .../entity/projectile/EntityThunderbolt.java | 25 +- .../wizardry/event/DiscoverSpellEvent.java | 27 +- .../wizardry/event/SpellCastEvent.java | 160 +- .../integration/DamageSafetyChecker.java | 14 +- .../WizardryAntiqueAtlasIntegration.java | 71 + .../baubles/WizardryBaublesIntegration.java | 110 + .../wizardry/item/IConjuredItem.java | 83 +- .../wizardry/item/IManaStoringItem.java | 72 + .../wizardry/item/IMultiTexturedItem.java | 23 + .../wizardry/item/ISpellCastingItem.java | 129 ++ .../wizardry/item/IWorkbenchItem.java | 10 +- .../wizardry/item/ItemArcaneTome.java | 12 +- .../wizardry/item/ItemArmourUpgrade.java | 10 +- .../wizardry/item/ItemArtefact.java | 875 ++++++++ .../wizardry/item/ItemBlankScroll.java | 18 +- .../item/ItemBlockMultiTexturedElemental.java | 42 + .../wizardry/item/ItemCrystal.java | 44 + .../wizardry/item/ItemFirebomb.java | 8 +- .../wizardry/item/ItemFlamingAxe.java | 57 +- .../wizardry/item/ItemFrostAxe.java | 47 +- .../item/ItemIdentificationScroll.java | 41 +- .../wizardry/item/ItemLightningHammer.java | 220 ++ .../wizardry/item/ItemManaFlask.java | 37 + .../wizardry/item/ItemPoisonBomb.java | 8 +- .../wizardry/item/ItemPurifyingElixir.java | 99 + .../electroblob/wizardry/item/ItemScroll.java | 138 +- .../wizardry/item/ItemSmokeBomb.java | 8 +- .../wizardry/item/ItemSparkBomb.java | 41 + .../wizardry/item/ItemSpectralArmour.java | 38 +- .../wizardry/item/ItemSpectralBow.java | 76 +- .../wizardry/item/ItemSpectralPickaxe.java | 45 +- .../wizardry/item/ItemSpectralSword.java | 47 +- .../wizardry/item/ItemSpellBook.java | 35 +- .../electroblob/wizardry/item/ItemWand.java | 694 ++++--- .../wizardry/item/ItemWandUpgrade.java | 32 + .../wizardry/item/ItemWizardArmour.java | 247 ++- .../wizardry/item/ItemWizardHandbook.java | 10 +- .../wizardry/loot/RandomSpell.java | 130 +- .../wizardry/loot/WizardSpell.java | 9 +- .../wizardry/misc/BehaviourSpellDispense.java | 105 + .../electroblob/wizardry/misc/Forfeit.java | 487 +++++ .../{util => misc}/WildcardTradeList.java | 2 +- .../{util => misc}/WizardryPathFinder.java | 10 +- .../packet/PacketCastContinuousSpell.java | 29 +- .../wizardry/packet/PacketCastSpell.java | 12 +- .../wizardry/packet/PacketCastSpellAtPos.java | 85 + .../wizardry/packet/PacketClairvoyance.java | 6 +- .../wizardry/packet/PacketConquerShrine.java | 58 + .../wizardry/packet/PacketControlInput.java | 133 +- .../packet/PacketDispenserCastSpell.java | 94 + .../wizardry/packet/PacketEmitterData.java | 55 + .../wizardry/packet/PacketEndSlowTime.java | 47 + .../wizardry/packet/PacketGlyphData.java | 17 +- .../wizardry/packet/PacketNPCCastSpell.java | 5 +- .../wizardry/packet/PacketPlayerSync.java | 43 +- .../wizardry/packet/PacketPossession.java | 58 + .../packet/PacketRequestAdvancementSync.java | 50 + .../wizardry/packet/PacketResurrection.java | 47 + .../packet/PacketSpellProperties.java | 64 + .../packet/PacketSyncAdvancements.java | 61 + .../wizardry/packet/PacketSyncSettings.java | 34 +- .../wizardry/packet/PacketTransportation.java | 7 +- .../packet/WizardryPacketHandler.java | 10 + .../electroblob/wizardry/potion/Curse.java | 70 + .../wizardry/potion/CurseEnfeeblement.java | 49 + .../wizardry/potion/CurseUndeath.java | 58 + .../potion/ICustomPotionParticles.java | 19 +- .../wizardry/potion/ISyncedPotion.java | 81 + .../wizardry/potion/PotionContainment.java | 121 ++ .../wizardry/potion/PotionDecay.java | 13 +- .../wizardry/potion/PotionFrost.java | 5 - .../wizardry/potion/PotionFrostStep.java | 116 ++ .../wizardry/potion/PotionMagicEffect.java | 3 +- .../wizardry/potion/PotionSlowTime.java | 172 ++ .../electroblob/wizardry/registry/Spells.java | 525 ++--- .../registry/WizardryAdvancementTriggers.java | 59 +- .../wizardry/registry/WizardryBlocks.java | 84 +- .../registry/WizardryEnchantments.java | 28 +- .../wizardry/registry/WizardryEntities.java | 190 ++ .../wizardry/registry/WizardryItems.java | 726 ++++--- .../wizardry/registry/WizardryLoot.java | 156 ++ .../wizardry/registry/WizardryPotions.java | 98 +- .../wizardry/registry/WizardryRecipes.java | 137 ++ .../wizardry/registry/WizardryRegistry.java | 225 -- .../wizardry/registry/WizardrySounds.java | 273 ++- .../wizardry/registry/WizardryTabs.java | 156 +- .../java/electroblob/wizardry/spell/Arc.java | 28 +- .../wizardry/spell/ArcaneJammer.java | 36 +- .../wizardry/spell/ArcaneLock.java | 133 ++ .../electroblob/wizardry/spell/ArrowRain.java | 13 +- .../electroblob/wizardry/spell/Banish.java | 110 +- .../electroblob/wizardry/spell/Blink.java | 38 +- .../electroblob/wizardry/spell/Bubble.java | 40 +- .../wizardry/spell/ChainLightning.java | 80 +- .../electroblob/wizardry/spell/Charge.java | 125 ++ .../wizardry/spell/Clairvoyance.java | 73 +- .../electroblob/wizardry/spell/Cobwebs.java | 45 +- .../wizardry/spell/ConjureArmour.java | 20 +- .../wizardry/spell/ConjureBlock.java | 79 + .../wizardry/spell/Containment.java | 54 + .../wizardry/spell/CureEffects.java | 27 +- .../wizardry/spell/CurseOfEnfeeblement.java | 60 + .../wizardry/spell/CurseOfSoulbinding.java | 96 +- .../wizardry/spell/CurseOfUndeath.java | 55 + .../electroblob/wizardry/spell/Decay.java | 26 +- .../electroblob/wizardry/spell/Decoy.java | 25 +- .../electroblob/wizardry/spell/Detonate.java | 34 +- .../wizardry/spell/Disintegration.java | 97 + .../wizardry/spell/Divination.java | 149 ++ .../{Fireball.java => DragonFireball.java} | 48 +- .../wizardry/spell/Earthquake.java | 54 +- .../wizardry/spell/EmpoweringPresence.java | 81 + .../wizardry/spell/Entrapment.java | 19 +- .../electroblob/wizardry/spell/Evade.java | 48 + .../wizardry/spell/FireBreath.java | 95 + .../electroblob/wizardry/spell/Firestorm.java | 110 - .../electroblob/wizardry/spell/FlameRay.java | 76 +- .../wizardry/spell/FlamingAxe.java | 7 +- .../wizardry/spell/FlamingWeapon.java | 19 +- .../electroblob/wizardry/spell/Flight.java | 39 +- .../wizardry/spell/FontOfMana.java | 63 +- .../wizardry/spell/ForceArrow.java | 21 + .../wizardry/spell/Forcefield.java | 21 + .../wizardry/spell/ForestOfThorns.java | 99 + .../wizardry/spell/ForestsCurse.java | 26 +- .../electroblob/wizardry/spell/Freeze.java | 55 +- .../wizardry/spell/FreezingWeapon.java | 19 +- .../electroblob/wizardry/spell/FrostAxe.java | 6 +- .../electroblob/wizardry/spell/FrostRay.java | 79 +- .../electroblob/wizardry/spell/Glide.java | 51 +- .../electroblob/wizardry/spell/Grapple.java | 419 ++++ .../wizardry/spell/GreaterFireball.java | 85 - .../wizardry/spell/GreaterHeal.java | 9 +- .../wizardry/spell/GreaterTelekinesis.java | 159 ++ .../electroblob/wizardry/spell/GroupHeal.java | 76 +- .../wizardry/spell/GrowthAura.java | 60 +- .../electroblob/wizardry/spell/Hailstorm.java | 15 +- .../java/electroblob/wizardry/spell/Heal.java | 9 +- .../electroblob/wizardry/spell/HealAlly.java | 34 +- .../electroblob/wizardry/spell/IceAge.java | 148 +- .../electroblob/wizardry/spell/IceSpikes.java | 62 +- .../electroblob/wizardry/spell/IceStatue.java | 38 +- .../electroblob/wizardry/spell/Ignite.java | 26 +- .../wizardry/spell/ImbueWeapon.java | 41 +- .../wizardry/spell/Intimidate.java | 52 +- .../wizardry/spell/InvigoratingPresence.java | 38 +- .../wizardry/spell/InvokeWeather.java | 28 +- .../java/electroblob/wizardry/spell/Leap.java | 25 +- .../wizardry/spell/Levitation.java | 39 +- .../electroblob/wizardry/spell/LifeDrain.java | 74 +- .../electroblob/wizardry/spell/Light.java | 36 +- .../wizardry/spell/LightningBolt.java | 67 +- .../wizardry/spell/LightningHammer.java | 18 +- .../wizardry/spell/LightningPulse.java | 47 +- .../wizardry/spell/LightningRay.java | 98 +- .../wizardry/spell/LightningWeb.java | 160 +- .../wizardry/spell/Metamorphosis.java | 60 +- .../electroblob/wizardry/spell/Meteor.java | 25 +- .../wizardry/spell/MindControl.java | 91 +- .../electroblob/wizardry/spell/MindTrick.java | 21 +- .../java/electroblob/wizardry/spell/Mine.java | 157 ++ .../java/electroblob/wizardry/spell/None.java | 7 +- .../electroblob/wizardry/spell/Paralysis.java | 123 ++ .../electroblob/wizardry/spell/Petrify.java | 30 +- .../electroblob/wizardry/spell/PhaseStep.java | 140 +- .../wizardry/spell/PlagueOfDarkness.java | 42 +- .../wizardry/spell/PocketFurnace.java | 27 +- .../wizardry/spell/PocketWorkbench.java | 11 +- .../electroblob/wizardry/spell/Poison.java | 33 +- .../wizardry/spell/Possession.java | 714 +++++++ .../wizardry/spell/RayOfPurification.java | 103 + .../wizardry/spell/RemoveCurse.java | 53 + .../wizardry/spell/ReplenishHunger.java | 14 +- .../wizardry/spell/Resurrection.java | 111 + .../electroblob/wizardry/spell/Reversal.java | 83 + .../electroblob/wizardry/spell/Satiety.java | 40 + .../wizardry/spell/ShadowWard.java | 49 +- .../electroblob/wizardry/spell/Shield.java | 48 +- .../electroblob/wizardry/spell/Shockwave.java | 84 +- .../wizardry/spell/ShulkerBullet.java | 101 + .../wizardry/spell/SixthSense.java | 45 +- .../electroblob/wizardry/spell/Slime.java | 52 +- .../electroblob/wizardry/spell/SlowTime.java | 46 + .../electroblob/wizardry/spell/Snare.java | 17 +- .../electroblob/wizardry/spell/Snowball.java | 24 +- .../wizardry/spell/SpectralPathway.java | 26 +- .../electroblob/wizardry/spell/SpeedTime.java | 133 ++ .../electroblob/wizardry/spell/Spell.java | 658 ++++-- .../wizardry/spell/SpellAreaEffect.java | 75 +- .../wizardry/spell/SpellArrow.java | 144 +- .../electroblob/wizardry/spell/SpellBuff.java | 169 +- .../wizardry/spell/SpellConjuration.java | 55 +- .../wizardry/spell/SpellConstruct.java | 127 +- .../wizardry/spell/SpellConstructRanged.java | 126 +- .../wizardry/spell/SpellMinion.java | 225 +- .../wizardry/spell/SpellProjectile.java | 148 +- .../electroblob/wizardry/spell/SpellRay.java | 301 +-- .../wizardry/spell/SummonIronGolem.java | 15 +- .../wizardry/spell/SummonShadowWraith.java | 5 +- .../wizardry/spell/SummonSkeleton.java | 24 +- .../wizardry/spell/SummonSkeletonLegion.java | 26 +- .../wizardry/spell/SummonSnowGolem.java | 10 +- .../wizardry/spell/SummonSpiritHorse.java | 76 +- .../wizardry/spell/SummonSpiritWolf.java | 68 +- .../wizardry/spell/SummonWitherSkeleton.java | 24 + .../wizardry/spell/SummonZombie.java | 28 + .../wizardry/spell/Telekinesis.java | 26 +- .../wizardry/spell/Thunderstorm.java | 139 +- .../electroblob/wizardry/spell/Tornado.java | 16 +- .../wizardry/spell/Transience.java | 59 +- .../wizardry/spell/Transportation.java | 190 +- .../wizardry/spell/VanishingBox.java | 11 +- .../wizardry/spell/WallOfFrost.java | 92 +- .../electroblob/wizardry/spell/Whirlwind.java | 57 +- .../electroblob/wizardry/spell/Wither.java | 34 +- .../wizardry/spell/WitherSkull.java | 57 +- .../tileentity/ContainerArcaneWorkbench.java | 45 +- .../tileentity/SlotItemClassList.java | 40 + .../wizardry/tileentity/SlotItemList.java | 14 +- .../tileentity/SlotWorkbenchItem.java | 2 +- .../tileentity/TileEntityArcaneWorkbench.java | 61 +- .../tileentity/TileEntityMagicLight.java | 5 + .../tileentity/TileEntityPlayerSave.java | 54 +- .../tileentity/TileEntityPlayerSaveTimed.java | 69 + .../tileentity/TileEntityShrineCore.java | 218 ++ .../wizardry/tileentity/TileEntityStatue.java | 9 +- .../wizardry/tileentity/TileEntityTimer.java | 7 +- .../wizardry/util/AllyDesignationSystem.java | 234 +++ .../wizardry/util/CustomSoundCategory.java | 86 + .../wizardry/util/IElementalDamage.java | 6 - .../electroblob/wizardry/util/Location.java | 47 + .../wizardry/util/MagicDamage.java | 77 +- .../electroblob/wizardry/util/NBTExtras.java | 231 +++ .../wizardry/util/ParticleBuilder.java | 387 +++- .../electroblob/wizardry/util/RayTracer.java | 207 ++ .../wizardry/util/RelativeFacing.java | 42 + .../wizardry/util/SpellModifiers.java | 98 +- .../wizardry/util/SpellProperties.java | 361 ++++ .../electroblob/wizardry/util/WandHelper.java | 116 +- .../wizardry/util/WizardryUtilities.java | 1061 +++++----- .../worldgen/MossifierTemplateProcessor.java | 51 + .../worldgen/MultiTemplateProcessor.java | 39 + .../worldgen/WoodTypeTemplateProcessor.java | 90 + .../worldgen/WorldGenCrystalFlower.java | 61 + .../wizardry/worldgen/WorldGenCrystalOre.java | 61 + .../wizardry/worldgen/WorldGenObelisk.java | 101 + .../wizardry/worldgen/WorldGenShrine.java | 95 + .../worldgen/WorldGenSurfaceStructure.java | 450 ++++ .../worldgen/WorldGenWizardTower.java | 165 ++ .../ebwizardry/advancements/advanced.json | 108 + .../advancements/all_artefacts.json | 647 ++++++ .../ebwizardry/advancements/all_spells.json | 1385 ++++++++++++- .../ebwizardry/advancements/anger_wizard.json | 4 +- .../ebwizardry/advancements/apprentice.json | 99 +- .../advancements/arcane_initiate.json | 4 +- .../ebwizardry/advancements/armour_set.json | 24 +- .../ebwizardry/advancements/artefact.json | 713 +++++++ .../advancements/buy_master_spell.json | 6 +- .../advancements/charge_creeper.json | 19 - .../ebwizardry/advancements/craft_flask.json | 26 - .../ebwizardry/advancements/crystal.json | 10 +- .../advancements/defeat_evil_wizard.json | 6 +- .../advancements/discover_master_spell.json | 28 + .../advancements/discover_spell.json | 22 + .../advancements/element_master.json | 20 - .../ebwizardry/advancements/elemental.json | 19 - .../advancements/enchant_scroll.json | 24 + .../ebwizardry/advancements/frankenstein.json | 20 - .../ebwizardry/advancements/freeze_blaze.json | 19 - .../handbook/arcane_workbench.json | 14 + .../handbook/crystal_flowers.json | 14 + .../advancements/handbook/elements.json | 92 + .../handbook/magical_creatures.json | 242 +++ .../advancements/handbook/mana_flasks.json | 10 + .../advancements/handbook/obelisks.json | 10 + .../handbook/on_subsection_unlock.json | 7 + .../advancements/handbook/scrolls.json | 14 + .../advancements/handbook/spells.json | 14 + .../advancements/handbook/throwables.json | 14 + .../advancements/handbook/tome_of_arcana.json | 14 + .../advancements/identify_spell.json | 11 +- .../ebwizardry/advancements/jam_wizard.json | 19 - .../ebwizardry/advancements/legendary.json | 4 +- .../ebwizardry/advancements/master.json | 101 +- .../ebwizardry/advancements/max_out_wand.json | 6 +- .../ebwizardry/advancements/pig_tornado.json | 20 - .../assets/ebwizardry/advancements/root.json | 4 +- .../advancements/self_destruct.json | 20 - .../advancements/slime_skeleton.json | 19 - .../advancements/special_upgrade.json | 6 +- .../advancements/spell_failure.json | 19 + .../ebwizardry/advancements/visit_shrine.json | 23 + .../ebwizardry/advancements/wizard_tower.json | 22 + .../ebwizardry/advancements/wizard_trade.json | 6 +- .../ebwizardry/blockstates/crystal_block.json | 6 - .../blockstates/dry_frosted_ice.json | 8 + .../blockstates/earth_crystal_block.json | 6 + .../blockstates/earth_runestone.json | 31 + .../blockstates/earth_runestone_pedestal.json | 6 + .../blockstates/fire_crystal_block.json | 6 + .../blockstates/fire_runestone.json | 31 + .../blockstates/fire_runestone_pedestal.json | 6 + .../blockstates/healing_crystal_block.json | 6 + .../blockstates/healing_runestone.json | 31 + .../healing_runestone_pedestal.json | 6 + .../blockstates/ice_crystal_block.json | 6 + .../ebwizardry/blockstates/ice_runestone.json | 31 + .../blockstates/ice_runestone_pedestal.json | 6 + .../blockstates/lightning_crystal_block.json | 6 + .../blockstates/lightning_runestone.json | 31 + .../lightning_runestone_pedestal.json | 6 + .../blockstates/magic_crystal_block.json | 6 + .../blockstates/necromancy_crystal_block.json | 6 + .../blockstates/necromancy_runestone.json | 31 + .../necromancy_runestone_pedestal.json | 6 + .../blockstates/obsidian_crust.json | 8 + .../blockstates/sorcery_crystal_block.json | 6 + .../blockstates/sorcery_runestone.json | 31 + .../sorcery_runestone_pedestal.json | 6 + .../assets/ebwizardry/blockstates/thorns.json | 20 + .../assets/ebwizardry/lang/en_gb.lang | 1812 +++++++++++------ .../assets/ebwizardry/lang/en_us.lang | 1808 ++++++++++------ .../assets/ebwizardry/lang/es_es.lang | 118 +- .../assets/ebwizardry/lang/es_mx.lang | 118 +- .../assets/ebwizardry/lang/fr_fr.lang | 760 +++++++ .../assets/ebwizardry/lang/ko_kr.lang | 760 +++++++ .../assets/ebwizardry/lang/ru_ru.lang | 116 +- .../assets/ebwizardry/lang/zh_cn.lang | 116 +- .../loot_tables/chests/dungeon_additions.json | 75 +- .../chests/jungle_dispenser_additions.json | 65 + .../loot_tables/chests/obelisk.json | 195 ++ .../ebwizardry/loot_tables/chests/shrine.json | 210 ++ .../loot_tables/chests/wizard_tower.json | 19 +- .../loot_tables/entities/mob_additions.json | 8 +- .../subsets/elemental_crystals.json | 24 + .../loot_tables/subsets/epic_artefacts.json | 75 + .../loot_tables/subsets/novice_wands.json | 50 - .../loot_tables/subsets/rare_artefacts.json | 145 ++ .../subsets/uncommon_artefacts.json | 115 ++ .../loot_tables/subsets/wand_upgrades.json | 7 +- .../models/block/earth_crystal_block.json | 6 + .../models/block/earth_runestone_1.json | 8 + .../models/block/earth_runestone_2.json | 8 + .../models/block/earth_runestone_3.json | 8 + .../models/block/earth_runestone_4.json | 8 + .../block/earth_runestone_pedestal.json | 9 + .../models/block/fire_crystal_block.json | 6 + .../models/block/fire_runestone_1.json | 8 + .../models/block/fire_runestone_2.json | 8 + .../models/block/fire_runestone_3.json | 8 + .../models/block/fire_runestone_4.json | 8 + .../models/block/fire_runestone_pedestal.json | 9 + .../models/block/healing_crystal_block.json | 6 + .../models/block/healing_runestone_1.json | 8 + .../models/block/healing_runestone_2.json | 8 + .../models/block/healing_runestone_3.json | 8 + .../models/block/healing_runestone_4.json | 8 + .../block/healing_runestone_pedestal.json | 9 + .../models/block/ice_crystal_block.json | 6 + .../models/block/ice_runestone_1.json | 8 + .../models/block/ice_runestone_2.json | 8 + .../models/block/ice_runestone_3.json | 8 + .../models/block/ice_runestone_4.json | 8 + .../models/block/ice_runestone_pedestal.json | 9 + .../models/block/lightning_crystal_block.json | 6 + .../models/block/lightning_runestone_1.json | 8 + .../models/block/lightning_runestone_2.json | 8 + .../models/block/lightning_runestone_3.json | 8 + .../models/block/lightning_runestone_4.json | 8 + .../block/lightning_runestone_pedestal.json | 9 + ...al_block.json => magic_crystal_block.json} | 0 .../block/necromancy_crystal_block.json | 6 + .../models/block/necromancy_runestone_1.json | 8 + .../models/block/necromancy_runestone_2.json | 8 + .../models/block/necromancy_runestone_3.json | 8 + .../models/block/necromancy_runestone_4.json | 8 + .../block/necromancy_runestone_pedestal.json | 9 + .../models/block/obsidian_crust_0.json | 6 + .../models/block/obsidian_crust_1.json | 6 + .../models/block/obsidian_crust_2.json | 6 + .../models/block/obsidian_crust_3.json | 6 + .../ebwizardry/models/block/runestone.json | 27 + .../models/block/runestone_pedestal.json | 30 + .../models/block/sorcery_crystal_block.json | 6 + .../models/block/sorcery_runestone_1.json | 8 + .../models/block/sorcery_runestone_2.json | 8 + .../models/block/sorcery_runestone_3.json | 8 + .../models/block/sorcery_runestone_4.json | 8 + .../block/sorcery_runestone_pedestal.json | 9 + .../models/block/thorns_lower_0.json | 6 + .../models/block/thorns_lower_1.json | 6 + .../models/block/thorns_lower_2.json | 6 + .../models/block/thorns_lower_3.json | 6 + .../models/block/thorns_lower_4.json | 6 + .../models/block/thorns_lower_5.json | 6 + .../models/block/thorns_lower_6.json | 6 + .../models/block/thorns_lower_7.json | 6 + .../models/block/thorns_upper_0.json | 6 + .../models/block/thorns_upper_1.json | 6 + .../models/block/thorns_upper_2.json | 6 + .../models/block/thorns_upper_3.json | 6 + .../models/block/thorns_upper_4.json | 6 + .../models/block/thorns_upper_5.json | 6 + .../models/block/thorns_upper_6.json | 6 + .../models/block/thorns_upper_7.json | 6 + .../models/item/amulet_anchoring.json | 6 + .../models/item/amulet_arcane_defence.json | 6 + .../models/item/amulet_auto_shield.json | 6 + .../models/item/amulet_banishing.json | 6 + .../models/item/amulet_channeling.json | 6 + .../models/item/amulet_fire_cloaking.json | 6 + .../models/item/amulet_fire_protection.json | 6 + .../ebwizardry/models/item/amulet_glide.json | 6 + .../models/item/amulet_ice_immunity.json | 6 + .../models/item/amulet_ice_protection.json | 6 + .../ebwizardry/models/item/amulet_lich.json | 6 + .../models/item/amulet_potential.json | 6 + .../models/item/amulet_recovery.json | 6 + .../models/item/amulet_resurrection.json | 6 + .../models/item/amulet_transience.json | 6 + .../models/item/amulet_warding.json | 6 + .../ebwizardry/models/item/amulet_wisdom.json | 6 + .../models/item/amulet_wither_immunity.json | 6 + .../models/item/astral_diamond.json | 6 + .../models/item/basic_lightning_wand.json | 6 - .../models/item/basic_necromancy_wand.json | 6 - .../models/item/basic_sorcery_wand.json | 6 - .../models/item/charm_abseiling.json | 6 + .../models/item/charm_auto_smelt.json | 6 + .../models/item/charm_experience_tome.json | 6 + .../ebwizardry/models/item/charm_feeding.json | 6 + .../ebwizardry/models/item/charm_flight.json | 6 + .../ebwizardry/models/item/charm_growth.json | 6 + .../ebwizardry/models/item/charm_haggler.json | 6 + .../models/item/charm_lava_walking.json | 6 + .../ebwizardry/models/item/charm_light.json | 6 + .../models/item/charm_minion_health.json | 6 + .../models/item/charm_minion_variants.json | 6 + .../models/item/charm_silk_touch.json | 6 + .../models/item/charm_stop_time.json | 6 + .../ebwizardry/models/item/charm_storm.json | 6 + .../models/item/charm_transportation.json | 6 + .../ebwizardry/models/item/crystal_block.json | 3 - ...{magic_crystal.json => crystal_earth.json} | 2 +- .../ebwizardry/models/item/crystal_fire.json | 6 + .../models/item/crystal_healing.json | 6 + .../ebwizardry/models/item/crystal_ice.json | 6 + .../models/item/crystal_lightning.json | 6 + .../ebwizardry/models/item/crystal_magic.json | 6 + .../models/item/crystal_necromancy.json | 6 + .../ebwizardry/models/item/crystal_shard.json | 6 + .../models/item/crystal_sorcery.json | 6 + .../models/item/earth_crystal_block.json | 3 + .../models/item/earth_runestone.json | 8 + .../models/item/earth_runestone_pedestal.json | 9 + .../models/item/fire_crystal_block.json | 3 + .../models/item/fire_runestone.json | 8 + .../models/item/fire_runestone_pedestal.json | 9 + .../ebwizardry/models/item/flaming_axe.json | 59 +- .../models/item/flaming_axe_conjuring_0.json | 6 + .../models/item/flaming_axe_conjuring_1.json | 6 + .../models/item/flaming_axe_conjuring_2.json | 6 + .../models/item/flaming_axe_conjuring_3.json | 6 + .../models/item/flaming_axe_conjuring_4.json | 6 + .../models/item/flaming_axe_conjuring_5.json | 6 + .../models/item/flaming_axe_conjuring_6.json | 6 + .../models/item/flaming_axe_conjuring_7.json | 6 + .../ebwizardry/models/item/frost_axe.json | 59 +- .../models/item/frost_axe_conjuring_0.json | 6 + .../models/item/frost_axe_conjuring_1.json | 6 + .../models/item/frost_axe_conjuring_2.json | 6 + .../models/item/frost_axe_conjuring_3.json | 6 + .../models/item/frost_axe_conjuring_4.json | 6 + .../models/item/frost_axe_conjuring_5.json | 6 + .../models/item/frost_axe_conjuring_6.json | 6 + .../models/item/frost_axe_conjuring_7.json | 6 + .../ebwizardry/models/item/grand_crystal.json | 6 + .../models/item/healing_crystal_block.json | 3 + .../models/item/healing_runestone.json | 8 + .../item/healing_runestone_pedestal.json | 9 + .../models/item/ice_crystal_block.json | 3 + .../ebwizardry/models/item/ice_runestone.json | 8 + .../models/item/ice_runestone_pedestal.json | 9 + .../models/item/large_mana_flask.json | 6 + .../models/item/lightning_crystal_block.json | 3 + .../models/item/lightning_hammer.json | 122 ++ .../models/item/lightning_runestone.json | 8 + .../item/lightning_runestone_pedestal.json | 9 + .../models/item/magic_crystal_block.json | 3 + .../ebwizardry/models/item/magic_wand.json | 2 +- .../models/item/medium_mana_flask.json | 6 + .../ebwizardry/models/item/melee_upgrade.json | 6 + .../models/item/necromancy_crystal_block.json | 3 + .../models/item/necromancy_runestone.json | 8 + .../item/necromancy_runestone_pedestal.json | 9 + ..._fire_wand.json => novice_earth_wand.json} | 2 +- ..._earth_wand.json => novice_fire_wand.json} | 2 +- ...ing_wand.json => novice_healing_wand.json} | 2 +- ...sic_ice_wand.json => novice_ice_wand.json} | 2 +- .../models/item/novice_lightning_wand.json | 6 + .../models/item/novice_necromancy_wand.json | 6 + .../models/item/novice_sorcery_wand.json | 6 + .../models/item/purifying_elixir.json | 6 + .../models/item/ring_arcane_frost.json | 6 + .../models/item/ring_battlemage.json | 6 + .../models/item/ring_blockwrangler.json | 6 + .../models/item/ring_combustion.json | 6 + .../models/item/ring_condensing.json | 6 + .../ebwizardry/models/item/ring_conjurer.json | 6 + .../ebwizardry/models/item/ring_defender.json | 6 + .../models/item/ring_disintegration.json | 6 + .../models/item/ring_earth_biome.json | 6 + .../models/item/ring_earth_melee.json | 6 + .../models/item/ring_extraction.json | 6 + .../models/item/ring_fire_biome.json | 6 + .../models/item/ring_fire_melee.json | 6 + .../models/item/ring_full_moon.json | 6 + .../ebwizardry/models/item/ring_hammer.json | 6 + .../models/item/ring_ice_biome.json | 6 + .../models/item/ring_ice_melee.json | 6 + .../models/item/ring_interdiction.json | 6 + .../ebwizardry/models/item/ring_leeching.json | 6 + .../models/item/ring_lightning_melee.json | 6 + .../models/item/ring_mana_return.json | 6 + .../models/item/ring_mind_control.json | 6 + .../models/item/ring_necromancy_melee.json | 6 + .../ebwizardry/models/item/ring_paladin.json | 6 + .../ebwizardry/models/item/ring_poison.json | 6 + .../ebwizardry/models/item/ring_seeking.json | 6 + .../models/item/ring_shattering.json | 6 + .../models/item/ring_siphoning.json | 6 + .../models/item/ring_soulbinding.json | 6 + .../models/item/ring_spirit_animal.json | 6 + .../ebwizardry/models/item/ring_storm.json | 6 + .../models/item/runestone_item.json | 28 + .../models/item/runestone_pedestal_item.json | 31 + .../models/item/small_mana_flask.json | 6 + .../models/item/sorcery_crystal_block.json | 3 + .../models/item/sorcery_runestone.json | 8 + .../item/sorcery_runestone_pedestal.json | 9 + .../item/{mana_flask.json => spark_bomb.json} | 2 +- .../ebwizardry/models/item/spectral_bow.json | 55 + .../models/item/spectral_bow_conjuring_0.json | 6 + .../models/item/spectral_bow_conjuring_1.json | 6 + .../models/item/spectral_bow_conjuring_2.json | 6 + .../models/item/spectral_bow_conjuring_3.json | 6 + .../models/item/spectral_bow_conjuring_4.json | 6 + .../models/item/spectral_bow_conjuring_5.json | 6 + .../models/item/spectral_bow_conjuring_6.json | 6 + .../models/item/spectral_bow_conjuring_7.json | 6 + .../models/item/spectral_pickaxe.json | 59 +- .../item/spectral_pickaxe_conjuring_0.json | 6 + .../item/spectral_pickaxe_conjuring_1.json | 6 + .../item/spectral_pickaxe_conjuring_2.json | 6 + .../item/spectral_pickaxe_conjuring_3.json | 6 + .../item/spectral_pickaxe_conjuring_4.json | 6 + .../item/spectral_pickaxe_conjuring_5.json | 6 + .../item/spectral_pickaxe_conjuring_6.json | 6 + .../item/spectral_pickaxe_conjuring_7.json | 6 + .../models/item/spectral_sword.json | 59 +- .../item/spectral_sword_conjuring_0.json | 6 + .../item/spectral_sword_conjuring_1.json | 6 + .../item/spectral_sword_conjuring_2.json | 6 + .../item/spectral_sword_conjuring_3.json | 6 + .../item/spectral_sword_conjuring_4.json | 6 + .../item/spectral_sword_conjuring_5.json | 6 + .../item/spectral_sword_conjuring_6.json | 6 + .../item/spectral_sword_conjuring_7.json | 6 + .../assets/ebwizardry/models/item/thorns.json | 6 + .../ebwizardry/recipes/arcane_workbench.json | 37 +- .../ebwizardry/recipes/crystal_block.json | 6 +- .../recipes/crystal_block_earth.json | 18 + .../recipes/crystal_block_fire.json | 18 + .../recipes/crystal_block_healing.json | 18 + .../ebwizardry/recipes/crystal_block_ice.json | 18 + .../recipes/crystal_block_lightning.json | 18 + .../recipes/crystal_block_necromancy.json | 18 + .../recipes/crystal_block_sorcery.json | 18 + .../recipes/crystal_block_to_crystals.json | 4 +- .../crystal_block_to_crystals_earth.json | 15 + .../crystal_block_to_crystals_fire.json | 15 + .../crystal_block_to_crystals_healing.json | 15 + .../crystal_block_to_crystals_ice.json | 15 + .../crystal_block_to_crystals_lightning.json | 15 + .../crystal_block_to_crystals_necromancy.json | 15 + .../crystal_block_to_crystals_sorcery.json | 15 + .../recipes/crystal_flower_to_crystals.json | 1 + .../ebwizardry/recipes/crystal_shard.json | 13 + .../ebwizardry/recipes/large_mana_flask.json | 19 + .../recipes/magic_missile_spell_book.json | 3 +- .../assets/ebwizardry/recipes/magic_silk.json | 37 +- .../assets/ebwizardry/recipes/magic_wand.json | 3 +- .../ebwizardry/recipes/medium_mana_flask.json | 50 + .../ebwizardry/recipes/runestone_earth.json | 23 + .../ebwizardry/recipes/runestone_fire.json | 23 + .../ebwizardry/recipes/runestone_healing.json | 23 + .../ebwizardry/recipes/runestone_ice.json | 23 + .../recipes/runestone_lightning.json | 23 + .../recipes/runestone_necromancy.json | 23 + .../recipes/runestone_pedestal_earth.json | 23 + .../recipes/runestone_pedestal_fire.json | 23 + .../recipes/runestone_pedestal_healing.json | 23 + .../recipes/runestone_pedestal_ice.json | 23 + .../recipes/runestone_pedestal_lightning.json | 23 + .../runestone_pedestal_necromancy.json | 23 + .../recipes/runestone_pedestal_sorcery.json | 23 + .../ebwizardry/recipes/runestone_sorcery.json | 23 + ...{mana_flask.json => small_mana_flask.json} | 6 +- .../assets/ebwizardry/recipes/spark_bomb.json | 23 + .../recipes/transportation_stone.json | 37 +- .../assets/ebwizardry/recipes/wand_earth.json | 25 + .../assets/ebwizardry/recipes/wand_fire.json | 25 + .../ebwizardry/recipes/wand_healing.json | 25 + .../assets/ebwizardry/recipes/wand_ice.json | 25 + .../ebwizardry/recipes/wand_lightning.json | 25 + .../ebwizardry/recipes/wand_necromancy.json | 25 + .../ebwizardry/recipes/wand_sorcery.json | 25 + .../ebwizardry/recipes/wizard_handbook.json | 37 +- .../ebwizardry/shaders/post/possession.json | 73 + .../ebwizardry/shaders/post/sixth_sense.json | 67 + .../ebwizardry/shaders/post/slow_time.json | 37 + .../ebwizardry/shaders/post/transience.json | 67 + .../resources/assets/ebwizardry/sounds.json | 390 +++- .../assets/ebwizardry/sounds/aura_end.ogg | Bin 0 -> 51608 bytes .../assets/ebwizardry/sounds/aura_loop.ogg | Bin 0 -> 216380 bytes .../assets/ebwizardry/sounds/aura_start.ogg | Bin 0 -> 18824 bytes .../assets/ebwizardry/sounds/book.ogg | Bin 0 -> 21349 bytes .../assets/ebwizardry/sounds/boom.ogg | Bin 38721 -> 0 bytes .../assets/ebwizardry/sounds/buff.ogg | Bin 0 -> 28647 bytes .../sounds/{aura.ogg => conjure.ogg} | Bin .../{largeaura.ogg => conjure_large.ogg} | Bin .../ebwizardry/sounds/dark_aura_end.ogg | Bin 0 -> 63140 bytes .../ebwizardry/sounds/dark_aura_loop.ogg | Bin 0 -> 59784 bytes .../ebwizardry/sounds/dark_aura_start.ogg | Bin 0 -> 30358 bytes .../assets/ebwizardry/sounds/firebolt.ogg | Bin 0 -> 70607 bytes .../assets/ebwizardry/sounds/flameray1.ogg | Bin 23817 -> 0 bytes .../assets/ebwizardry/sounds/flameray2.ogg | Bin 31282 -> 0 bytes .../assets/ebwizardry/sounds/flames_end.ogg | Bin 0 -> 37073 bytes .../assets/ebwizardry/sounds/flames_loop.ogg | Bin 0 -> 285773 bytes .../assets/ebwizardry/sounds/flames_start.ogg | Bin 0 -> 30379 bytes .../assets/ebwizardry/sounds/grow.ogg | Bin 0 -> 47592 bytes ...electricityb.ogg => lightning_ray_end.ogg} | Bin .../ebwizardry/sounds/lightning_ray_loop.ogg | Bin 0 -> 43032 bytes ...ectricitya.ogg => lightning_ray_start.ogg} | Bin .../assets/ebwizardry/sounds/page1.ogg | Bin 0 -> 11164 bytes .../assets/ebwizardry/sounds/page2.ogg | Bin 0 -> 14045 bytes .../assets/ebwizardry/sounds/page3.ogg | Bin 0 -> 17081 bytes .../assets/ebwizardry/sounds/pull1.ogg | Bin 0 -> 29901 bytes .../assets/ebwizardry/sounds/pull2.ogg | Bin 0 -> 31418 bytes .../assets/ebwizardry/sounds/shockwave.ogg | Bin 0 -> 44395 bytes .../ebwizardry/sounds/small_aura_end.ogg | Bin 0 -> 59448 bytes .../ebwizardry/sounds/small_aura_loop.ogg | Bin 0 -> 209049 bytes .../ebwizardry/sounds/small_aura_start.ogg | Bin 0 -> 87860 bytes .../assets/ebwizardry/sounds/spellbind.ogg | Bin 0 -> 78949 bytes .../sounds/{darkaura1.ogg => summon1.ogg} | Bin .../sounds/{darkaura2.ogg => summon2.ogg} | Bin .../assets/ebwizardry/spells/agility.json | 25 + .../assets/ebwizardry/spells/arc.json | 23 + .../ebwizardry/spells/arcane_jammer.json | 23 + .../assets/ebwizardry/spells/arcane_lock.json | 22 + .../assets/ebwizardry/spells/arrow_rain.json | 23 + .../assets/ebwizardry/spells/banish.json | 24 + .../assets/ebwizardry/spells/black_hole.json | 23 + .../assets/ebwizardry/spells/blink.json | 22 + .../assets/ebwizardry/spells/blizzard.json | 24 + .../assets/ebwizardry/spells/bubble.json | 23 + .../ebwizardry/spells/chain_lightning.json | 29 + .../assets/ebwizardry/spells/charge.json | 25 + .../ebwizardry/spells/clairvoyance.json | 23 + .../assets/ebwizardry/spells/cobwebs.json | 24 + .../ebwizardry/spells/combustion_rune.json | 23 + .../ebwizardry/spells/conjure_armour.json | 22 + .../ebwizardry/spells/conjure_block.json | 23 + .../assets/ebwizardry/spells/conjure_bow.json | 22 + .../ebwizardry/spells/conjure_pickaxe.json | 22 + .../ebwizardry/spells/conjure_sword.json | 22 + .../assets/ebwizardry/spells/containment.json | 24 + .../ebwizardry/spells/cure_effects.json | 20 + .../spells/curse_of_enfeeblement.json | 23 + .../spells/curse_of_soulbinding.json | 22 + .../ebwizardry/spells/curse_of_undeath.json | 23 + .../ebwizardry/spells/darkness_orb.json | 25 + .../assets/ebwizardry/spells/darkvision.json | 23 + .../assets/ebwizardry/spells/dart.json | 25 + .../assets/ebwizardry/spells/decay.json | 25 + .../assets/ebwizardry/spells/decoy.json | 23 + .../assets/ebwizardry/spells/detonate.json | 24 + .../ebwizardry/spells/diamondflesh.json | 23 + .../ebwizardry/spells/disintegration.json | 26 + .../assets/ebwizardry/spells/divination.json | 22 + .../ebwizardry/spells/dragon_fireball.json | 22 + .../assets/ebwizardry/spells/earthquake.json | 23 + .../spells/empowering_presence.json | 24 + .../assets/ebwizardry/spells/entrapment.json | 24 + .../assets/ebwizardry/spells/evade.json | 22 + .../assets/ebwizardry/spells/fire_breath.json | 24 + .../ebwizardry/spells/fire_resistance.json | 23 + .../assets/ebwizardry/spells/fire_sigil.json | 24 + .../assets/ebwizardry/spells/fireball.json | 24 + .../assets/ebwizardry/spells/firebolt.json | 24 + .../assets/ebwizardry/spells/firebomb.json | 26 + .../assets/ebwizardry/spells/fireskin.json | 24 + .../assets/ebwizardry/spells/flame_ray.json | 24 + .../assets/ebwizardry/spells/flaming_axe.json | 24 + .../ebwizardry/spells/flaming_weapon.json | 22 + .../assets/ebwizardry/spells/flight.json | 23 + .../ebwizardry/spells/font_of_mana.json | 24 + .../ebwizardry/spells/font_of_vitality.json | 25 + .../assets/ebwizardry/spells/force_arrow.json | 23 + .../assets/ebwizardry/spells/force_orb.json | 24 + .../assets/ebwizardry/spells/forcefield.json | 23 + .../ebwizardry/spells/forest_of_thorns.json | 24 + .../ebwizardry/spells/forests_curse.json | 25 + .../assets/ebwizardry/spells/freeze.json | 25 + .../ebwizardry/spells/freezing_weapon.json | 22 + .../assets/ebwizardry/spells/frost_axe.json | 22 + .../assets/ebwizardry/spells/frost_ray.json | 25 + .../assets/ebwizardry/spells/frost_sigil.json | 25 + .../assets/ebwizardry/spells/frost_step.json | 23 + .../assets/ebwizardry/spells/glide.json | 24 + .../assets/ebwizardry/spells/grapple.json | 24 + .../ebwizardry/spells/greater_fireball.json | 24 + .../ebwizardry/spells/greater_heal.json | 22 + .../spells/greater_telekinesis.json | 25 + .../ebwizardry/spells/greater_ward.json | 23 + .../assets/ebwizardry/spells/group_heal.json | 23 + .../assets/ebwizardry/spells/growth_aura.json | 22 + .../assets/ebwizardry/spells/hailstorm.json | 23 + .../assets/ebwizardry/spells/heal.json | 22 + .../assets/ebwizardry/spells/heal_ally.json | 23 + .../ebwizardry/spells/healing_aura.json | 24 + .../ebwizardry/spells/homing_spark.json | 24 + .../assets/ebwizardry/spells/ice_age.json | 23 + .../assets/ebwizardry/spells/ice_charge.json | 29 + .../assets/ebwizardry/spells/ice_lance.json | 25 + .../assets/ebwizardry/spells/ice_shard.json | 25 + .../assets/ebwizardry/spells/ice_shroud.json | 25 + .../assets/ebwizardry/spells/ice_spikes.json | 27 + .../assets/ebwizardry/spells/ice_statue.json | 23 + .../assets/ebwizardry/spells/iceball.json | 25 + .../assets/ebwizardry/spells/ignite.json | 23 + .../ebwizardry/spells/imbue_weapon.json | 22 + .../assets/ebwizardry/spells/intimidate.json | 24 + .../spells/invigorating_presence.json | 24 + .../ebwizardry/spells/invisibility.json | 23 + .../ebwizardry/spells/invoke_weather.json | 22 + .../assets/ebwizardry/spells/ironflesh.json | 23 + .../assets/ebwizardry/spells/leap.json | 23 + .../assets/ebwizardry/spells/levitation.json | 23 + .../assets/ebwizardry/spells/life_drain.json | 24 + .../assets/ebwizardry/spells/light.json | 23 + .../ebwizardry/spells/lightning_arrow.json | 23 + .../ebwizardry/spells/lightning_bolt.json | 22 + .../ebwizardry/spells/lightning_disc.json | 24 + .../ebwizardry/spells/lightning_hammer.json | 28 + .../ebwizardry/spells/lightning_pulse.json | 24 + .../ebwizardry/spells/lightning_ray.json | 23 + .../ebwizardry/spells/lightning_sigil.json | 26 + .../ebwizardry/spells/lightning_web.json | 29 + .../ebwizardry/spells/magic_missile.json | 23 + .../ebwizardry/spells/metamorphosis.json | 22 + .../assets/ebwizardry/spells/meteor.json | 23 + .../ebwizardry/spells/mind_control.json | 23 + .../assets/ebwizardry/spells/mind_trick.json | 23 + .../assets/ebwizardry/spells/mine.json | 22 + .../assets/ebwizardry/spells/muffle.json | 23 + .../assets/ebwizardry/spells/none.json | 20 + .../assets/ebwizardry/spells/oakflesh.json | 23 + .../assets/ebwizardry/spells/paralysis.json | 25 + .../assets/ebwizardry/spells/petrify.json | 23 + .../assets/ebwizardry/spells/phase_step.json | 23 + .../ebwizardry/spells/plague_of_darkness.json | 25 + .../ebwizardry/spells/pocket_furnace.json | 22 + .../ebwizardry/spells/pocket_workbench.json | 20 + .../assets/ebwizardry/spells/poison.json | 25 + .../assets/ebwizardry/spells/poison_bomb.json | 29 + .../assets/ebwizardry/spells/possession.json | 24 + .../spells/ray_of_purification.json | 26 + .../ebwizardry/spells/remove_curse.json | 20 + .../ebwizardry/spells/replenish_hunger.json | 23 + .../ebwizardry/spells/resurrection.json | 23 + .../assets/ebwizardry/spells/reversal.json | 23 + .../ebwizardry/spells/ring_of_fire.json | 24 + .../assets/ebwizardry/spells/satiety.json | 23 + .../assets/ebwizardry/spells/shadow_ward.json | 22 + .../assets/ebwizardry/spells/shield.json | 22 + .../assets/ebwizardry/spells/shockwave.json | 24 + .../ebwizardry/spells/shulker_bullet.json | 22 + .../ebwizardry/spells/silverfish_swarm.json | 24 + .../assets/ebwizardry/spells/sixth_sense.json | 23 + .../assets/ebwizardry/spells/slime.json | 23 + .../assets/ebwizardry/spells/slow_time.json | 24 + .../assets/ebwizardry/spells/smoke_bomb.json | 24 + .../assets/ebwizardry/spells/snare.json | 25 + .../assets/ebwizardry/spells/snowball.json | 22 + .../assets/ebwizardry/spells/spark_bomb.json | 26 + .../ebwizardry/spells/spectral_pathway.json | 23 + .../assets/ebwizardry/spells/speed_time.json | 24 + .../ebwizardry/spells/spider_swarm.json | 24 + .../assets/ebwizardry/spells/static_aura.json | 24 + .../ebwizardry/spells/summon_blaze.json | 24 + .../ebwizardry/spells/summon_ice_giant.json | 24 + .../ebwizardry/spells/summon_ice_wraith.json | 24 + .../ebwizardry/spells/summon_iron_golem.json | 22 + .../spells/summon_lightning_wraith.json | 24 + .../ebwizardry/spells/summon_phoenix.json | 24 + .../spells/summon_shadow_wraith.json | 24 + .../ebwizardry/spells/summon_skeleton.json | 24 + .../spells/summon_skeleton_legion.json | 24 + .../ebwizardry/spells/summon_snow_golem.json | 22 + .../spells/summon_spirit_horse.json | 22 + .../ebwizardry/spells/summon_spirit_wolf.json | 22 + .../spells/summon_storm_elemental.json | 24 + .../spells/summon_wither_skeleton.json | 24 + .../ebwizardry/spells/summon_zombie.json | 24 + .../assets/ebwizardry/spells/telekinesis.json | 22 + .../assets/ebwizardry/spells/thunderbolt.json | 24 + .../ebwizardry/spells/thunderstorm.json | 29 + .../assets/ebwizardry/spells/tornado.json | 26 + .../assets/ebwizardry/spells/transience.json | 22 + .../ebwizardry/spells/transportation.json | 22 + .../ebwizardry/spells/vanishing_box.json | 20 + .../assets/ebwizardry/spells/vex_swarm.json | 24 + .../ebwizardry/spells/wall_of_frost.json | 23 + .../assets/ebwizardry/spells/ward.json | 23 + .../ebwizardry/spells/water_breathing.json | 23 + .../assets/ebwizardry/spells/whirlwind.json | 23 + .../assets/ebwizardry/spells/wither.json | 25 + .../ebwizardry/spells/wither_skull.json | 22 + .../ebwizardry/structures/obelisk_0.nbt | Bin 0 -> 578 bytes .../ebwizardry/structures/obelisk_1.nbt | Bin 0 -> 615 bytes .../ebwizardry/structures/obelisk_2.nbt | Bin 0 -> 601 bytes .../ebwizardry/structures/obelisk_3.nbt | Bin 0 -> 609 bytes .../ebwizardry/structures/obelisk_4.nbt | Bin 0 -> 660 bytes .../assets/ebwizardry/structures/shrine_0.nbt | Bin 0 -> 742 bytes .../assets/ebwizardry/structures/shrine_1.nbt | Bin 0 -> 743 bytes .../assets/ebwizardry/structures/shrine_2.nbt | Bin 0 -> 744 bytes .../assets/ebwizardry/structures/shrine_3.nbt | Bin 0 -> 748 bytes .../assets/ebwizardry/structures/shrine_4.nbt | Bin 0 -> 741 bytes .../assets/ebwizardry/structures/shrine_5.nbt | Bin 0 -> 743 bytes .../assets/ebwizardry/structures/shrine_6.nbt | Bin 0 -> 745 bytes .../assets/ebwizardry/structures/shrine_7.nbt | Bin 0 -> 754 bytes .../ebwizardry/structures/wizard_tower_0.nbt | Bin 0 -> 2188 bytes .../ebwizardry/structures/wizard_tower_1.nbt | Bin 0 -> 2341 bytes .../ebwizardry/structures/wizard_tower_2.nbt | Bin 0 -> 2422 bytes .../ebwizardry/structures/wizard_tower_3.nbt | Bin 0 -> 1927 bytes .../structures/wizard_tower_chest_0.nbt | Bin 0 -> 2249 bytes .../structures/wizard_tower_chest_1.nbt | Bin 0 -> 2396 bytes .../structures/wizard_tower_chest_2.nbt | Bin 0 -> 2480 bytes .../structures/wizard_tower_chest_3.nbt | Bin 0 -> 1986 bytes .../ebwizardry/texts/handbook_en_gb.json | 396 +++- .../ebwizardry/texts/handbook_en_gb.txt | 225 -- .../ebwizardry/texts/handbook_en_us.json | 394 +++- .../ebwizardry/texts/handbook_en_us.txt | 225 -- .../ebwizardry/texts/handbook_es_es.txt | 2 +- .../ebwizardry/texts/handbook_es_mx.txt | 2 +- .../ebwizardry/texts/handbook_ko_kr.txt | 239 +++ .../textures/armour/invisible_armour.png | Bin 2411 -> 0 bytes .../armour/legendary_wizard_armour.png | Bin 0 -> 12450 bytes .../armour/legendary_wizard_armour_earth.png | Bin 0 -> 13287 bytes .../legendary_wizard_armour_earth_legs.png | Bin 0 -> 1726 bytes .../armour/legendary_wizard_armour_fire.png | Bin 0 -> 13116 bytes .../legendary_wizard_armour_fire_legs.png | Bin 0 -> 1703 bytes .../legendary_wizard_armour_healing.png | Bin 0 -> 14008 bytes .../legendary_wizard_armour_healing_legs.png | Bin 0 -> 2067 bytes .../armour/legendary_wizard_armour_ice.png | Bin 0 -> 14111 bytes .../legendary_wizard_armour_ice_legs.png | Bin 0 -> 1999 bytes .../armour/legendary_wizard_armour_legs.png | Bin 0 -> 1693 bytes .../legendary_wizard_armour_lightning.png | Bin 0 -> 12621 bytes ...legendary_wizard_armour_lightning_legs.png | Bin 0 -> 1749 bytes .../legendary_wizard_armour_necromancy.png | Bin 0 -> 12490 bytes ...egendary_wizard_armour_necromancy_legs.png | Bin 0 -> 1926 bytes .../legendary_wizard_armour_sorcery.png | Bin 0 -> 13352 bytes .../legendary_wizard_armour_sorcery_legs.png | Bin 0 -> 1874 bytes .../textures/armour/wizard_armour.png | Bin 2566 -> 11798 bytes .../textures/armour/wizard_armour_earth.png | Bin 2803 -> 11486 bytes .../armour/wizard_armour_earth_legs.png | Bin 425 -> 1851 bytes .../textures/armour/wizard_armour_fire.png | Bin 2807 -> 12095 bytes .../textures/armour/wizard_armour_healing.png | Bin 2797 -> 12777 bytes .../textures/armour/wizard_armour_ice.png | Bin 2781 -> 12968 bytes .../armour/wizard_armour_ice_legs.png | Bin 417 -> 1941 bytes .../armour/wizard_armour_lightning.png | Bin 2787 -> 11578 bytes .../armour/wizard_armour_necromancy.png | Bin 2800 -> 11032 bytes .../textures/armour/wizard_armour_sorcery.png | Bin 2792 -> 11818 bytes .../blocks/arcane_workbench_bottom.png | Bin 741 -> 1391 bytes .../textures/blocks/arcane_workbench_side.png | Bin 695 -> 2183 bytes .../textures/blocks/arcane_workbench_top.png | Bin 658 -> 2338 bytes .../textures/blocks/crystal_block_earth.png | Bin 0 -> 2864 bytes .../textures/blocks/crystal_block_fire.png | Bin 0 -> 704 bytes .../textures/blocks/crystal_block_healing.png | Bin 0 -> 740 bytes .../textures/blocks/crystal_block_ice.png | Bin 0 -> 876 bytes .../blocks/crystal_block_lightning.png | Bin 0 -> 858 bytes .../blocks/crystal_block_necromancy.png | Bin 0 -> 858 bytes .../textures/blocks/crystal_block_sorcery.png | Bin 0 -> 806 bytes .../textures/blocks/obsidian_crust_0.png | Bin 0 -> 884 bytes .../textures/blocks/obsidian_crust_1.png | Bin 0 -> 918 bytes .../textures/blocks/obsidian_crust_2.png | Bin 0 -> 949 bytes .../textures/blocks/obsidian_crust_3.png | Bin 0 -> 973 bytes .../textures/blocks/runestone_earth_0.png | Bin 0 -> 627 bytes .../textures/blocks/runestone_earth_1.png | Bin 0 -> 742 bytes .../blocks/runestone_earth_1_overlay.png | Bin 0 -> 749 bytes .../textures/blocks/runestone_earth_2.png | Bin 0 -> 732 bytes .../blocks/runestone_earth_2_overlay.png | Bin 0 -> 734 bytes .../textures/blocks/runestone_earth_3.png | Bin 0 -> 727 bytes .../blocks/runestone_earth_3_overlay.png | Bin 0 -> 730 bytes .../textures/blocks/runestone_earth_4.png | Bin 0 -> 733 bytes .../blocks/runestone_earth_4_overlay.png | Bin 0 -> 739 bytes .../textures/blocks/runestone_fire_0.png | Bin 0 -> 626 bytes .../textures/blocks/runestone_fire_1.png | Bin 0 -> 712 bytes .../blocks/runestone_fire_1_overlay.png | Bin 0 -> 713 bytes .../textures/blocks/runestone_fire_2.png | Bin 0 -> 738 bytes .../blocks/runestone_fire_2_overlay.png | Bin 0 -> 743 bytes .../textures/blocks/runestone_fire_3.png | Bin 0 -> 712 bytes .../blocks/runestone_fire_3_overlay.png | Bin 0 -> 714 bytes .../textures/blocks/runestone_fire_4.png | Bin 0 -> 717 bytes .../blocks/runestone_fire_4_overlay.png | Bin 0 -> 715 bytes .../textures/blocks/runestone_healing_0.png | Bin 0 -> 661 bytes .../textures/blocks/runestone_healing_1.png | Bin 0 -> 838 bytes .../blocks/runestone_healing_1_overlay.png | Bin 0 -> 841 bytes .../textures/blocks/runestone_healing_2.png | Bin 0 -> 813 bytes .../blocks/runestone_healing_2_overlay.png | Bin 0 -> 815 bytes .../textures/blocks/runestone_healing_3.png | Bin 0 -> 724 bytes .../blocks/runestone_healing_3_overlay.png | Bin 0 -> 724 bytes .../textures/blocks/runestone_healing_4.png | Bin 0 -> 813 bytes .../blocks/runestone_healing_4_overlay.png | Bin 0 -> 821 bytes .../textures/blocks/runestone_ice_0.png | Bin 0 -> 746 bytes .../textures/blocks/runestone_ice_1.png | Bin 0 -> 860 bytes .../blocks/runestone_ice_1_overlay.png | Bin 0 -> 869 bytes .../textures/blocks/runestone_ice_2.png | Bin 0 -> 829 bytes .../blocks/runestone_ice_2_overlay.png | Bin 0 -> 833 bytes .../textures/blocks/runestone_ice_3.png | Bin 0 -> 839 bytes .../blocks/runestone_ice_3_overlay.png | Bin 0 -> 843 bytes .../textures/blocks/runestone_ice_4.png | Bin 0 -> 862 bytes .../blocks/runestone_ice_4_overlay.png | Bin 0 -> 871 bytes .../textures/blocks/runestone_lightning_0.png | Bin 0 -> 629 bytes .../textures/blocks/runestone_lightning_1.png | Bin 0 -> 747 bytes .../blocks/runestone_lightning_1_overlay.png | Bin 0 -> 751 bytes .../textures/blocks/runestone_lightning_2.png | Bin 0 -> 735 bytes .../blocks/runestone_lightning_2_overlay.png | Bin 0 -> 742 bytes .../textures/blocks/runestone_lightning_3.png | Bin 0 -> 738 bytes .../blocks/runestone_lightning_3_overlay.png | Bin 0 -> 745 bytes .../textures/blocks/runestone_lightning_4.png | Bin 0 -> 773 bytes .../blocks/runestone_lightning_4_overlay.png | Bin 0 -> 783 bytes .../blocks/runestone_necromancy_0.png | Bin 0 -> 571 bytes .../blocks/runestone_necromancy_1.png | Bin 0 -> 703 bytes .../blocks/runestone_necromancy_1_overlay.png | Bin 0 -> 705 bytes .../blocks/runestone_necromancy_2.png | Bin 0 -> 714 bytes .../blocks/runestone_necromancy_2_overlay.png | Bin 0 -> 717 bytes .../blocks/runestone_necromancy_3.png | Bin 0 -> 685 bytes .../blocks/runestone_necromancy_3_overlay.png | Bin 0 -> 685 bytes .../blocks/runestone_necromancy_4.png | Bin 0 -> 723 bytes .../blocks/runestone_necromancy_4_overlay.png | Bin 0 -> 727 bytes .../blocks/runestone_pedestal_earth.png | Bin 0 -> 737 bytes .../runestone_pedestal_earth_overlay.png | Bin 0 -> 6570 bytes .../blocks/runestone_pedestal_fire.png | Bin 0 -> 702 bytes .../runestone_pedestal_fire_overlay.png | Bin 0 -> 6467 bytes .../blocks/runestone_pedestal_healing.png | Bin 0 -> 769 bytes .../runestone_pedestal_healing_overlay.png | Bin 0 -> 6610 bytes .../blocks/runestone_pedestal_ice.png | Bin 0 -> 785 bytes .../blocks/runestone_pedestal_ice_overlay.png | Bin 0 -> 6510 bytes .../blocks/runestone_pedestal_lightning.png | Bin 0 -> 712 bytes .../runestone_pedestal_lightning_overlay.png | Bin 0 -> 6497 bytes .../blocks/runestone_pedestal_necromancy.png | Bin 0 -> 713 bytes .../runestone_pedestal_necromancy_overlay.png | Bin 0 -> 6436 bytes .../blocks/runestone_pedestal_sorcery.png | Bin 0 -> 709 bytes .../runestone_pedestal_sorcery_overlay.png | Bin 0 -> 6273 bytes .../textures/blocks/runestone_sorcery_0.png | Bin 0 -> 521 bytes .../textures/blocks/runestone_sorcery_1.png | Bin 0 -> 636 bytes .../blocks/runestone_sorcery_1_overlay.png | Bin 0 -> 644 bytes .../textures/blocks/runestone_sorcery_2.png | Bin 0 -> 679 bytes .../blocks/runestone_sorcery_2_overlay.png | Bin 0 -> 678 bytes .../textures/blocks/runestone_sorcery_3.png | Bin 0 -> 619 bytes .../blocks/runestone_sorcery_3_overlay.png | Bin 0 -> 621 bytes .../textures/blocks/runestone_sorcery_4.png | Bin 0 -> 649 bytes .../blocks/runestone_sorcery_4_overlay.png | Bin 0 -> 653 bytes .../textures/blocks/thorns_lower_0.png | Bin 0 -> 368 bytes .../textures/blocks/thorns_lower_1.png | Bin 0 -> 506 bytes .../textures/blocks/thorns_lower_2.png | Bin 0 -> 718 bytes .../textures/blocks/thorns_lower_3.png | Bin 0 -> 903 bytes .../textures/blocks/thorns_lower_4.png | Bin 0 -> 947 bytes .../textures/blocks/thorns_lower_5.png | Bin 0 -> 968 bytes .../textures/blocks/thorns_lower_6.png | Bin 0 -> 987 bytes .../textures/blocks/thorns_lower_7.png | Bin 0 -> 995 bytes .../textures/blocks/thorns_upper_0.png | Bin 0 -> 170 bytes .../textures/blocks/thorns_upper_1.png | Bin 0 -> 170 bytes .../textures/blocks/thorns_upper_2.png | Bin 0 -> 170 bytes .../textures/blocks/thorns_upper_3.png | Bin 0 -> 210 bytes .../textures/blocks/thorns_upper_4.png | Bin 0 -> 343 bytes .../textures/blocks/thorns_upper_5.png | Bin 0 -> 580 bytes .../textures/blocks/thorns_upper_6.png | Bin 0 -> 699 bytes .../textures/blocks/thorns_upper_7.png | Bin 0 -> 804 bytes .../textures/entity/arcane_lock_0.png | Bin 0 -> 1860 bytes .../textures/entity/arcane_lock_1.png | Bin 0 -> 1876 bytes .../textures/entity/arcane_lock_2.png | Bin 0 -> 1890 bytes .../textures/entity/arcane_lock_3.png | Bin 0 -> 1879 bytes .../textures/entity/arcane_lock_4.png | Bin 0 -> 1844 bytes .../textures/entity/arcane_lock_5.png | Bin 0 -> 1878 bytes .../textures/entity/arcane_lock_6.png | Bin 0 -> 1889 bytes .../textures/entity/arcane_lock_7.png | Bin 0 -> 1836 bytes .../textures/entity/combustion_rune.png | Bin 0 -> 1512 bytes .../textures/entity/containment_field_0.png | Bin 0 -> 571 bytes .../textures/entity/containment_field_1.png | Bin 0 -> 576 bytes .../textures/entity/containment_field_2.png | Bin 0 -> 587 bytes .../textures/entity/containment_field_3.png | Bin 0 -> 583 bytes .../textures/entity/containment_field_4.png | Bin 0 -> 573 bytes .../textures/entity/containment_field_5.png | Bin 0 -> 587 bytes .../textures/entity/containment_field_6.png | Bin 0 -> 600 bytes .../textures/entity/containment_field_7.png | Bin 0 -> 585 bytes .../ebwizardry/textures/entity/ember.png | Bin 0 -> 1244 bytes .../ebwizardry/textures/entity/fireball.png | Bin 0 -> 1764 bytes .../ebwizardry/textures/entity/firebolt.png | Bin 255 -> 1348 bytes .../textures/entity/frost_overlay.png | Bin 0 -> 242 bytes .../ebwizardry/textures/entity/iceball.png | Bin 0 -> 1803 bytes .../ebwizardry/textures/entity/wizard_7.png | Bin 0 -> 1599 bytes .../ebwizardry/textures/entity/wizard_8.png | Bin 0 -> 1598 bytes .../textures/entity/wizard_female_0.png | Bin 0 -> 1544 bytes .../textures/entity/wizard_female_1.png | Bin 0 -> 1543 bytes .../textures/entity/wizard_female_2.png | Bin 0 -> 1544 bytes .../textures/gui/advancement_background.png | Bin 703 -> 2337 bytes .../textures/gui/arcane_workbench.png | Bin 28839 -> 30590 bytes .../textures/gui/armour_picture.png | Bin 0 -> 75075 bytes .../textures/gui/curse_background.png | Bin 0 -> 621 bytes ...icon_simple.png => element_icon_magic.png} | Bin .../textures/gui/elements_picture.png | Bin 0 -> 7821 bytes .../ebwizardry/textures/gui/handbook.png | Bin 12848 -> 23928 bytes .../textures/gui/obelisk_picture.png | Bin 0 -> 123931 bytes .../gui/potion_icon_arcane_jammer.png | Bin 0 -> 15501 bytes .../textures/gui/potion_icon_containment.png | Bin 0 -> 12674 bytes .../gui/potion_icon_curse_of_enfeeblement.png | Bin 0 -> 8068 bytes .../gui/potion_icon_curse_of_soulbinding.png | Bin 0 -> 13480 bytes .../gui/potion_icon_curse_of_undeath.png | Bin 0 -> 6870 bytes .../{decay_icon.png => potion_icon_decay.png} | Bin .../textures/gui/potion_icon_empowerment.png | Bin 0 -> 11629 bytes .../textures/gui/potion_icon_fear.png | Bin 0 -> 12325 bytes .../textures/gui/potion_icon_fireskin.png | Bin 0 -> 9284 bytes .../textures/gui/potion_icon_font_of_mana.png | Bin 0 -> 14340 bytes .../{frost_icon.png => potion_icon_frost.png} | Bin .../textures/gui/potion_icon_frost_step.png | Bin 0 -> 14405 bytes .../textures/gui/potion_icon_ice_shroud.png | Bin 0 -> 11596 bytes .../textures/gui/potion_icon_mind_control.png | Bin 0 -> 8152 bytes .../textures/gui/potion_icon_mind_trick.png | Bin 0 -> 9578 bytes .../textures/gui/potion_icon_muffle.png | Bin 0 -> 9869 bytes .../textures/gui/potion_icon_paralysis.png | Bin 0 -> 11924 bytes .../textures/gui/potion_icon_sixth_sense.png | Bin 0 -> 14563 bytes .../textures/gui/potion_icon_slow_time.png | Bin 0 -> 10784 bytes .../textures/gui/potion_icon_static_aura.png | Bin 0 -> 11658 bytes .../textures/gui/potion_icon_transience.png | Bin 0 -> 12311 bytes .../textures/gui/potion_icon_ward.png | Bin 0 -> 8631 bytes .../ebwizardry/textures/gui/potion_icons.png | Bin 3317 -> 0 bytes .../textures/gui/shrine_picture.png | Bin 0 -> 196524 bytes .../textures/gui/spell_book_advanced.png | Bin 5292 -> 12024 bytes .../textures/gui/spell_book_apprentice.png | Bin 5272 -> 11927 bytes .../textures/gui/spell_book_basic.png | Bin 5267 -> 0 bytes .../textures/gui/spell_book_master.png | Bin 5666 -> 12366 bytes .../textures/gui/spell_book_novice.png | Bin 0 -> 11511 bytes .../textures/gui/spell_hud/_index.json | 12 + .../textures/gui/spell_hud/mahogany.json | 33 + .../textures/gui/spell_hud/mahogany.png | Bin 0 -> 20766 bytes .../textures/gui/spell_hud/oceanic.json | 33 + .../textures/gui/spell_hud/oceanic.png | Bin 0 -> 21417 bytes .../textures/gui/spell_hud/planks.json | 33 + .../textures/gui/spell_hud/planks.png | Bin 0 -> 22007 bytes .../ebwizardry/textures/gui/spellbook.png | Bin 20096 -> 0 bytes .../ebwizardry/textures/gui/tiers_picture.png | Bin 0 -> 927 bytes .../ebwizardry/textures/gui/tower_picture.png | Bin 0 -> 206602 bytes .../textures/gui/transportation_marker.png | Bin 0 -> 5708 bytes .../integration/antiqueatlas/obelisk.png | Bin 0 -> 3297 bytes .../integration/antiqueatlas/shrine.png | Bin 0 -> 3333 bytes .../integration/antiqueatlas/wizard_tower.png | Bin 0 -> 3328 bytes .../textures/items/amulet_anchoring.png | Bin 0 -> 5710 bytes .../textures/items/amulet_arcane_defence.png | Bin 0 -> 2150 bytes .../textures/items/amulet_auto_shield.png | Bin 0 -> 422 bytes .../textures/items/amulet_banishing.png | Bin 0 -> 5865 bytes .../textures/items/amulet_channeling.png | Bin 0 -> 500 bytes .../textures/items/amulet_fire_cloaking.png | Bin 0 -> 1803 bytes .../textures/items/amulet_fire_protection.png | Bin 0 -> 405 bytes .../textures/items/amulet_glide.png | Bin 0 -> 440 bytes .../textures/items/amulet_ice_immunity.png | Bin 0 -> 6552 bytes .../textures/items/amulet_ice_protection.png | Bin 0 -> 1873 bytes .../ebwizardry/textures/items/amulet_lich.png | Bin 0 -> 558 bytes .../textures/items/amulet_potential.png | Bin 0 -> 478 bytes .../textures/items/amulet_recovery.png | Bin 0 -> 6026 bytes .../textures/items/amulet_resurrection.png | Bin 0 -> 5914 bytes .../textures/items/amulet_transience.png | Bin 0 -> 496 bytes .../textures/items/amulet_warding.png | Bin 0 -> 430 bytes .../textures/items/amulet_wisdom.png | Bin 0 -> 1793 bytes .../textures/items/amulet_wither_immunity.png | Bin 0 -> 1831 bytes .../textures/items/astral_diamond.png | Bin 0 -> 2141 bytes .../textures/items/charm_abseiling.png | Bin 0 -> 6509 bytes .../textures/items/charm_auto_smelt.png | Bin 0 -> 419 bytes .../textures/items/charm_experience_tome.png | Bin 0 -> 2170 bytes .../textures/items/charm_feeding.png | Bin 0 -> 2114 bytes .../textures/items/charm_flight.png | Bin 0 -> 5949 bytes .../textures/items/charm_growth.png | Bin 0 -> 5722 bytes .../textures/items/charm_haggler.png | Bin 0 -> 1788 bytes .../textures/items/charm_lava_walking.png | Bin 0 -> 507 bytes .../ebwizardry/textures/items/charm_light.png | Bin 0 -> 456 bytes .../textures/items/charm_minion_health.png | Bin 0 -> 430 bytes .../textures/items/charm_minion_variants.png | Bin 0 -> 2098 bytes .../textures/items/charm_silk_touch.png | Bin 0 -> 387 bytes .../textures/items/charm_stop_time.png | Bin 0 -> 569 bytes .../ebwizardry/textures/items/charm_storm.png | Bin 0 -> 1945 bytes .../textures/items/charm_transportation.png | Bin 0 -> 556 bytes .../textures/items/crystal_earth.png | Bin 0 -> 656 bytes .../textures/items/crystal_fire.png | Bin 0 -> 623 bytes .../textures/items/crystal_grand.png | Bin 0 -> 667 bytes .../textures/items/crystal_healing.png | Bin 0 -> 618 bytes .../ebwizardry/textures/items/crystal_ice.png | Bin 0 -> 562 bytes .../textures/items/crystal_lightning.png | Bin 0 -> 688 bytes .../textures/items/crystal_magic.png | Bin 0 -> 519 bytes .../textures/items/crystal_necromancy.png | Bin 0 -> 588 bytes .../textures/items/crystal_shard.png | Bin 0 -> 361 bytes .../textures/items/crystal_sorcery.png | Bin 0 -> 620 bytes .../items/flaming_axe_conjuring_0.png | Bin 0 -> 1979 bytes .../items/flaming_axe_conjuring_1.png | Bin 0 -> 5979 bytes .../items/flaming_axe_conjuring_1.png.mcmeta | 12 + .../items/flaming_axe_conjuring_2.png | Bin 0 -> 5994 bytes .../items/flaming_axe_conjuring_2.png.mcmeta | 12 + .../items/flaming_axe_conjuring_3.png | Bin 0 -> 5955 bytes .../items/flaming_axe_conjuring_3.png.mcmeta | 12 + .../items/flaming_axe_conjuring_4.png | Bin 0 -> 5845 bytes .../items/flaming_axe_conjuring_4.png.mcmeta | 12 + .../items/flaming_axe_conjuring_5.png | Bin 0 -> 5875 bytes .../items/flaming_axe_conjuring_5.png.mcmeta | 12 + .../items/flaming_axe_conjuring_6.png | Bin 0 -> 5743 bytes .../items/flaming_axe_conjuring_6.png.mcmeta | 12 + .../items/flaming_axe_conjuring_7.png | Bin 0 -> 5908 bytes .../items/flaming_axe_conjuring_7.png.mcmeta | 12 + .../textures/items/frost_axe_conjuring_0.png | Bin 0 -> 1979 bytes .../textures/items/frost_axe_conjuring_1.png | Bin 0 -> 1977 bytes .../textures/items/frost_axe_conjuring_2.png | Bin 0 -> 2009 bytes .../textures/items/frost_axe_conjuring_3.png | Bin 0 -> 2012 bytes .../textures/items/frost_axe_conjuring_4.png | Bin 0 -> 1996 bytes .../textures/items/frost_axe_conjuring_5.png | Bin 0 -> 1977 bytes .../textures/items/frost_axe_conjuring_6.png | Bin 0 -> 1977 bytes .../textures/items/frost_axe_conjuring_7.png | Bin 0 -> 1915 bytes .../textures/items/magic_crystal.png | Bin 510 -> 0 bytes .../ebwizardry/textures/items/mana_flask.png | Bin 409 -> 0 bytes .../textures/items/mana_flask_large.png | Bin 0 -> 473 bytes .../textures/items/mana_flask_medium.png | Bin 0 -> 470 bytes .../textures/items/mana_flask_small.png | Bin 0 -> 432 bytes .../textures/items/purifying_elixir.png | Bin 0 -> 1946 bytes .../textures/items/ring_arcane_frost.png | Bin 0 -> 429 bytes .../textures/items/ring_battlemage.png | Bin 0 -> 1725 bytes .../textures/items/ring_blockwrangler.png | Bin 0 -> 5961 bytes .../textures/items/ring_bronze_generic.png | Bin 0 -> 5855 bytes .../textures/items/ring_combustion.png | Bin 0 -> 9840 bytes .../textures/items/ring_combustion.png.mcmeta | 12 + .../textures/items/ring_condensing.png | Bin 0 -> 579 bytes .../textures/items/ring_conjurer.png | Bin 0 -> 335 bytes .../textures/items/ring_defender.png | Bin 0 -> 6228 bytes .../textures/items/ring_defender.png.mcmeta | 12 + .../textures/items/ring_disintegration.png | Bin 0 -> 424 bytes .../textures/items/ring_earth_biome.png | Bin 0 -> 5746 bytes .../textures/items/ring_earth_melee.png | Bin 0 -> 1859 bytes .../textures/items/ring_extraction.png | Bin 0 -> 1882 bytes .../textures/items/ring_fire_biome.png | Bin 0 -> 1819 bytes .../textures/items/ring_fire_melee.png | Bin 0 -> 2023 bytes .../textures/items/ring_full_moon.png | Bin 0 -> 5455 bytes .../textures/items/ring_gold_generic.png | Bin 0 -> 5866 bytes .../ebwizardry/textures/items/ring_hammer.png | Bin 0 -> 367 bytes .../textures/items/ring_ice_biome.png | Bin 0 -> 458 bytes .../textures/items/ring_ice_melee.png | Bin 0 -> 1889 bytes .../textures/items/ring_interdiction.png | Bin 0 -> 541 bytes .../textures/items/ring_leeching.png | Bin 0 -> 392 bytes .../textures/items/ring_lightning_melee.png | Bin 0 -> 589 bytes .../textures/items/ring_mana_return.png | Bin 0 -> 444 bytes .../textures/items/ring_mind_control.png | Bin 0 -> 357 bytes .../textures/items/ring_necromancy_melee.png | Bin 0 -> 1997 bytes .../textures/items/ring_paladin.png | Bin 0 -> 577 bytes .../ebwizardry/textures/items/ring_poison.png | Bin 0 -> 5591 bytes .../textures/items/ring_seeking.png | Bin 0 -> 387 bytes .../textures/items/ring_shattering.png | Bin 0 -> 311 bytes .../textures/items/ring_silver_generic.png | Bin 0 -> 5910 bytes .../textures/items/ring_siphoning.png | Bin 0 -> 384 bytes .../textures/items/ring_soulbinding.png | Bin 0 -> 456 bytes .../ebwizardry/textures/items/ring_storm.png | Bin 0 -> 1206 bytes .../textures/items/ring_storm.png.mcmeta | 42 + .../textures/{entity => items}/spark_bomb.png | Bin .../items/spectral_bow_conjuring_0.png | Bin 0 -> 1651 bytes .../items/spectral_bow_conjuring_1.png | Bin 0 -> 1693 bytes .../items/spectral_bow_conjuring_2.png | Bin 0 -> 1786 bytes .../items/spectral_bow_conjuring_3.png | Bin 0 -> 1815 bytes .../items/spectral_bow_conjuring_4.png | Bin 0 -> 1833 bytes .../items/spectral_bow_conjuring_5.png | Bin 0 -> 1809 bytes .../items/spectral_bow_conjuring_6.png | Bin 0 -> 1797 bytes .../items/spectral_bow_conjuring_7.png | Bin 0 -> 1786 bytes .../items/spectral_pickaxe_conjuring_0.png | Bin 0 -> 1588 bytes .../items/spectral_pickaxe_conjuring_1.png | Bin 0 -> 1593 bytes .../items/spectral_pickaxe_conjuring_2.png | Bin 0 -> 1616 bytes .../items/spectral_pickaxe_conjuring_3.png | Bin 0 -> 1673 bytes .../items/spectral_pickaxe_conjuring_4.png | Bin 0 -> 1686 bytes .../items/spectral_pickaxe_conjuring_5.png | Bin 0 -> 1723 bytes .../items/spectral_pickaxe_conjuring_6.png | Bin 0 -> 1707 bytes .../items/spectral_pickaxe_conjuring_7.png | Bin 0 -> 1694 bytes .../items/spectral_sword_conjuring_0.png | Bin 0 -> 1668 bytes .../items/spectral_sword_conjuring_1.png | Bin 0 -> 1729 bytes .../items/spectral_sword_conjuring_2.png | Bin 0 -> 1777 bytes .../items/spectral_sword_conjuring_3.png | Bin 0 -> 1791 bytes .../items/spectral_sword_conjuring_4.png | Bin 0 -> 1791 bytes .../items/spectral_sword_conjuring_5.png | Bin 0 -> 1797 bytes .../items/spectral_sword_conjuring_6.png | Bin 0 -> 1817 bytes .../items/spectral_sword_conjuring_7.png | Bin 0 -> 1803 bytes .../textures/items/upgrade_attunement.png | Bin 556 -> 5741 bytes .../textures/items/upgrade_blast.png | Bin 371 -> 5553 bytes .../textures/items/upgrade_condenser.png | Bin 411 -> 5610 bytes .../textures/items/upgrade_cooldown.png | Bin 452 -> 5698 bytes .../textures/items/upgrade_duration.png | Bin 412 -> 5594 bytes .../textures/items/upgrade_melee.png | Bin 0 -> 5965 bytes .../textures/items/upgrade_range.png | Bin 535 -> 5613 bytes .../textures/items/upgrade_siphon.png | Bin 447 -> 5851 bytes .../textures/items/upgrade_storage.png | Bin 392 -> 5865 bytes .../textures/items/wand_basic_lightning.png | Bin 363 -> 0 bytes .../textures/items/wand_basic_necromancy.png | Bin 361 -> 0 bytes .../items/{wand_basic.png => wand_novice.png} | Bin ..._basic_earth.png => wand_novice_earth.png} | Bin ...nd_basic_fire.png => wand_novice_fire.png} | Bin ...ic_healing.png => wand_novice_healing.png} | Bin ...wand_basic_ice.png => wand_novice_ice.png} | Bin .../textures/items/wand_novice_lightning.png | Bin 0 -> 502 bytes .../textures/items/wand_novice_necromancy.png | Bin 0 -> 496 bytes ...ic_sorcery.png => wand_novice_sorcery.png} | Bin .../textures/particle/flame_0_0.png | Bin 0 -> 1695 bytes .../textures/particle/flame_0_1.png | Bin 0 -> 1719 bytes .../textures/particle/flame_0_2.png | Bin 0 -> 1741 bytes .../textures/particle/flame_0_3.png | Bin 0 -> 1769 bytes .../textures/particle/flame_0_4.png | Bin 0 -> 1748 bytes .../textures/particle/flame_0_5.png | Bin 0 -> 1680 bytes .../textures/particle/flame_0_6.png | Bin 0 -> 1685 bytes .../textures/particle/flame_0_7.png | Bin 0 -> 1679 bytes .../textures/particle/flame_1_0.png | Bin 0 -> 1716 bytes .../textures/particle/flame_1_1.png | Bin 0 -> 1737 bytes .../textures/particle/flame_1_2.png | Bin 0 -> 1729 bytes .../textures/particle/flame_1_3.png | Bin 0 -> 1763 bytes .../textures/particle/flame_1_4.png | Bin 0 -> 1762 bytes .../textures/particle/flame_1_5.png | Bin 0 -> 1671 bytes .../textures/particle/flame_1_6.png | Bin 0 -> 1671 bytes .../textures/particle/flame_1_7.png | Bin 0 -> 1667 bytes .../textures/particle/flame_2_0.png | Bin 0 -> 1683 bytes .../textures/particle/flame_2_1.png | Bin 0 -> 1730 bytes .../textures/particle/flame_2_2.png | Bin 0 -> 1694 bytes .../textures/particle/flame_2_3.png | Bin 0 -> 1564 bytes .../textures/particle/flame_2_4.png | Bin 0 -> 1633 bytes .../textures/particle/flame_2_5.png | Bin 0 -> 1605 bytes .../textures/particle/flame_2_6.png | Bin 0 -> 1581 bytes .../textures/particle/flame_2_7.png | Bin 0 -> 1579 bytes .../textures/particle/flame_3_0.png | Bin 0 -> 1683 bytes .../textures/particle/flame_3_1.png | Bin 0 -> 1730 bytes .../textures/particle/flame_3_2.png | Bin 0 -> 1719 bytes .../textures/particle/flame_3_3.png | Bin 0 -> 1593 bytes .../textures/particle/flame_3_4.png | Bin 0 -> 1618 bytes .../textures/particle/flame_3_5.png | Bin 0 -> 1606 bytes .../textures/particle/flame_3_6.png | Bin 0 -> 1562 bytes .../textures/particle/flame_3_7.png | Bin 0 -> 1559 bytes .../ebwizardry/textures/particle/ice_0.png | Bin 307 -> 1649 bytes .../ebwizardry/textures/particle/ice_1.png | Bin 238 -> 1333 bytes .../ebwizardry/textures/particle/ice_2.png | Bin 217 -> 1363 bytes .../ebwizardry/textures/particle/ice_3.png | Bin 191 -> 1213 bytes .../ebwizardry/textures/particle/ice_4.png | Bin 289 -> 1591 bytes .../ebwizardry/textures/particle/ice_5.png | Bin 259 -> 1498 bytes .../ebwizardry/textures/particle/ice_6.png | Bin 187 -> 1177 bytes .../ebwizardry/textures/particle/ice_7.png | Bin 183 -> 1162 bytes .../ebwizardry/textures/particle/leaf_0.png | Bin 196 -> 1274 bytes .../ebwizardry/textures/particle/leaf_1.png | Bin 187 -> 1155 bytes .../ebwizardry/textures/particle/leaf_10.png | Bin 184 -> 1170 bytes .../ebwizardry/textures/particle/leaf_11.png | Bin 184 -> 1091 bytes .../ebwizardry/textures/particle/leaf_12.png | Bin 191 -> 1120 bytes .../ebwizardry/textures/particle/leaf_13.png | Bin 180 -> 1074 bytes .../ebwizardry/textures/particle/leaf_14.png | Bin 181 -> 1084 bytes .../ebwizardry/textures/particle/leaf_15.png | Bin 243 -> 1373 bytes .../ebwizardry/textures/particle/leaf_2.png | Bin 194 -> 1165 bytes .../ebwizardry/textures/particle/leaf_3.png | Bin 167 -> 1091 bytes .../ebwizardry/textures/particle/leaf_4.png | Bin 197 -> 1186 bytes .../ebwizardry/textures/particle/leaf_5.png | Bin 229 -> 1285 bytes .../ebwizardry/textures/particle/leaf_6.png | Bin 223 -> 1227 bytes .../ebwizardry/textures/particle/leaf_7.png | Bin 232 -> 1269 bytes .../ebwizardry/textures/particle/leaf_8.png | Bin 251 -> 1324 bytes .../ebwizardry/textures/particle/leaf_9.png | Bin 243 -> 1309 bytes .../ebwizardry/textures/particle/path.png | Bin 219 -> 1046 bytes .../ebwizardry/textures/particle/snow_0.png | Bin 140 -> 991 bytes .../ebwizardry/textures/particle/snow_1.png | Bin 140 -> 990 bytes .../ebwizardry/textures/particle/snow_2.png | Bin 145 -> 995 bytes .../ebwizardry/textures/particle/snow_3.png | Bin 137 -> 961 bytes .../textures/particle/sparkle_0.png | Bin 307 -> 1521 bytes .../textures/particle/sparkle_1.png | Bin 239 -> 1252 bytes .../textures/particle/sparkle_10.png | Bin 134 -> 904 bytes .../textures/particle/sparkle_2.png | Bin 240 -> 1225 bytes .../textures/particle/sparkle_3.png | Bin 215 -> 1154 bytes .../textures/particle/sparkle_4.png | Bin 298 -> 1564 bytes .../textures/particle/sparkle_5.png | Bin 243 -> 1359 bytes .../textures/particle/sparkle_6.png | Bin 182 -> 1183 bytes .../textures/particle/sparkle_7.png | Bin 191 -> 1146 bytes .../textures/particle/sparkle_8.png | Bin 257 -> 1491 bytes .../textures/particle/sparkle_9.png | Bin 181 -> 1214 bytes .../ebwizardry/textures/particle/summon.png | Bin 0 -> 1310 bytes .../ebwizardry/textures/particle/vine.png | Bin 0 -> 865 bytes .../textures/particle/vine_leaf_0.png | Bin 0 -> 1272 bytes .../textures/particle/vine_leaf_1.png | Bin 0 -> 1246 bytes .../textures/particle/vine_leaf_2.png | Bin 0 -> 1351 bytes .../textures/particle/vine_leaf_3.png | Bin 0 -> 1195 bytes .../textures/particle/vine_leaf_4.png | Bin 0 -> 1087 bytes .../ebwizardry/textures/spells/agility.png | Bin 2200 -> 5547 bytes .../textures/spells/arcane_lock.png | Bin 0 -> 5300 bytes .../ebwizardry/textures/spells/arrow_rain.png | Bin 2421 -> 6382 bytes .../ebwizardry/textures/spells/charge.png | Bin 0 -> 2260 bytes .../textures/spells/combustion_rune.png | Bin 0 -> 6199 bytes .../textures/spells/conjure_axe.png | Bin 0 -> 4557 bytes .../textures/spells/conjure_block.png | Bin 0 -> 1744 bytes .../textures/spells/conjure_shovel.png | Bin 0 -> 4317 bytes .../textures/spells/containment.png | Bin 0 -> 4994 bytes .../textures/spells/curse_of_enfeeblement.png | Bin 0 -> 1726 bytes .../textures/spells/curse_of_undeath.png | Bin 0 -> 1990 bytes .../textures/spells/disintegration.png | Bin 0 -> 2076 bytes .../ebwizardry/textures/spells/divination.png | Bin 0 -> 5844 bytes .../textures/spells/dragon_fireball.png | Bin 0 -> 5692 bytes .../textures/spells/empowering_presence.png | Bin 0 -> 2527 bytes .../ebwizardry/textures/spells/evade.png | Bin 0 -> 5322 bytes .../textures/spells/fire_breath.png | Bin 0 -> 1938 bytes .../textures/spells/fire_resistance.png | Bin 2381 -> 6180 bytes .../textures/spells/forest_of_thorns.png | Bin 0 -> 2579 bytes .../ebwizardry/textures/spells/frost_step.png | Bin 0 -> 5334 bytes .../ebwizardry/textures/spells/grapple.png | Bin 0 -> 6134 bytes .../textures/spells/greater_telekinesis.png | Bin 0 -> 2461 bytes .../textures/spells/greater_ward.png | Bin 0 -> 2424 bytes .../textures/spells/guardian_angel.png | Bin 0 -> 6455 bytes .../textures/spells/guardian_beam.png | Bin 0 -> 5882 bytes .../textures/spells/healing_totem.png | Bin 0 -> 5218 bytes .../ebwizardry/textures/spells/iceball.png | Bin 0 -> 1848 bytes .../ebwizardry/textures/spells/levitation.png | Bin 2188 -> 6044 bytes .../textures/spells/lightning_hammer.png | Bin 2426 -> 6121 bytes .../ebwizardry/textures/spells/mine.png | Bin 0 -> 1575 bytes .../ebwizardry/textures/spells/muffle.png | Bin 0 -> 1979 bytes .../ebwizardry/textures/spells/paralysis.png | Bin 0 -> 2420 bytes .../ebwizardry/textures/spells/permafrost.png | Bin 0 -> 5249 bytes .../ebwizardry/textures/spells/phase_step.png | Bin 2023 -> 5141 bytes .../ebwizardry/textures/spells/possession.png | Bin 0 -> 2290 bytes .../textures/spells/ray_of_purification.png | Bin 0 -> 2278 bytes .../textures/spells/remove_curse.png | Bin 0 -> 2459 bytes .../textures/spells/resurrection.png | Bin 0 -> 2254 bytes .../ebwizardry/textures/spells/reversal.png | Bin 0 -> 5726 bytes .../ebwizardry/textures/spells/rupture.png | Bin 0 -> 1846 bytes .../ebwizardry/textures/spells/satiety.png | Bin 0 -> 2450 bytes .../ebwizardry/textures/spells/shapeshift.png | Bin 0 -> 5336 bytes .../textures/spells/shocking_weapon.png | Bin 0 -> 5691 bytes .../textures/spells/shulker_bullet.png | Bin 0 -> 4963 bytes .../ebwizardry/textures/spells/slow_time.png | Bin 0 -> 2411 bytes .../ebwizardry/textures/spells/speed_time.png | Bin 0 -> 2530 bytes .../textures/spells/summon_creeper.png | Bin 0 -> 5393 bytes .../textures/spells/summon_spirit_horse.png | Bin 2211 -> 5855 bytes .../textures/spells/summon_spirit_wolf.png | Bin 2241 -> 5638 bytes .../ebwizardry/textures/spells/vex_swarm.png | Bin 0 -> 5544 bytes .../ebwizardry/textures/spells/ward.png | Bin 0 -> 2304 bytes src/main/resources/mcmod.info | 11 +- 1564 files changed, 47652 insertions(+), 12984 deletions(-) delete mode 100644 src/main/java/electroblob/wizardry/WizardryWorldGenerator.java create mode 100644 src/main/java/electroblob/wizardry/advancement/ArcaneWorkbenchTrigger.java rename src/main/java/electroblob/wizardry/{util => advancement}/CustomAdvancementTrigger.java (96%) create mode 100644 src/main/java/electroblob/wizardry/advancement/SpellCastTrigger.java create mode 100644 src/main/java/electroblob/wizardry/advancement/SpellDiscoveryTrigger.java create mode 100644 src/main/java/electroblob/wizardry/advancement/SpellPredicate.java create mode 100644 src/main/java/electroblob/wizardry/advancement/StructureTrigger.java create mode 100644 src/main/java/electroblob/wizardry/api/WizardryEnumHelper.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockCrystal.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockDryFrostedIce.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockObsidianCrust.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockPedestal.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockRunestone.java create mode 100644 src/main/java/electroblob/wizardry/block/BlockThorns.java delete mode 100644 src/main/java/electroblob/wizardry/client/MovingSoundEntity.java create mode 100644 src/main/java/electroblob/wizardry/client/audio/MovingSoundEntity.java create mode 100644 src/main/java/electroblob/wizardry/client/audio/SoundLoop.java create mode 100644 src/main/java/electroblob/wizardry/client/audio/SoundLoopSpell.java create mode 100644 src/main/java/electroblob/wizardry/client/gui/GuiButtonResurrect.java rename src/main/java/electroblob/wizardry/client/{ => gui/config}/EntityNameEntry.java (90%) rename src/main/java/electroblob/wizardry/client/gui/{ => config}/GuiConfigWizardry.java (90%) rename src/main/java/electroblob/wizardry/client/gui/{ => config}/GuiSelectHUDSkin.java (95%) create mode 100644 src/main/java/electroblob/wizardry/client/gui/config/NamedBooleanEntry.java rename src/main/java/electroblob/wizardry/client/{ => gui/config}/SpellHUDSkinChooserEntry.java (85%) create mode 100644 src/main/java/electroblob/wizardry/client/gui/handbook/HandbookToast.java create mode 100644 src/main/java/electroblob/wizardry/client/model/BakedModelGlowingOverlay.java delete mode 100644 src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java create mode 100644 src/main/java/electroblob/wizardry/client/model/WizardryModels.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleSphere.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleSummon.java create mode 100644 src/main/java/electroblob/wizardry/client/particle/ParticleVine.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/LayerFrost.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/LayerStrayMinionClothing.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderArcaneLock.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderContainmentField.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderForcefield.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderPossessingPlayer.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderShadowWard.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderShield.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderStrayMinion.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderTransportationUI.java create mode 100644 src/main/java/electroblob/wizardry/client/renderer/RenderWings.java create mode 100644 src/main/java/electroblob/wizardry/command/SpellEmitter.java create mode 100644 src/main/java/electroblob/wizardry/data/BlockCastingData.java create mode 100644 src/main/java/electroblob/wizardry/data/DispenserCastingData.java create mode 100644 src/main/java/electroblob/wizardry/data/IStoredVariable.java create mode 100644 src/main/java/electroblob/wizardry/data/IVariable.java create mode 100644 src/main/java/electroblob/wizardry/data/Persistence.java create mode 100644 src/main/java/electroblob/wizardry/data/SpellEmitterData.java rename src/main/java/electroblob/wizardry/{ => data}/SpellGlyphData.java (85%) rename src/main/java/electroblob/wizardry/{ => data}/WizardData.java (51%) create mode 100644 src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicProtection.java create mode 100644 src/main/java/electroblob/wizardry/entity/EntityLevitatingBlock.java create mode 100644 src/main/java/electroblob/wizardry/entity/ICustomHitbox.java create mode 100644 src/main/java/electroblob/wizardry/entity/construct/EntityCombustionRune.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityHuskMinion.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityStrayMinion.java create mode 100644 src/main/java/electroblob/wizardry/entity/living/EntityVexMinion.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityEmber.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityIceball.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityLargeMagicFireball.java create mode 100644 src/main/java/electroblob/wizardry/entity/projectile/EntityMagicFireball.java create mode 100644 src/main/java/electroblob/wizardry/integration/antiqueatlas/WizardryAntiqueAtlasIntegration.java create mode 100644 src/main/java/electroblob/wizardry/integration/baubles/WizardryBaublesIntegration.java create mode 100644 src/main/java/electroblob/wizardry/item/IManaStoringItem.java create mode 100644 src/main/java/electroblob/wizardry/item/IMultiTexturedItem.java create mode 100644 src/main/java/electroblob/wizardry/item/ISpellCastingItem.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemArtefact.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemBlockMultiTexturedElemental.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemCrystal.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemLightningHammer.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemManaFlask.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemPurifyingElixir.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemSparkBomb.java create mode 100644 src/main/java/electroblob/wizardry/item/ItemWandUpgrade.java create mode 100644 src/main/java/electroblob/wizardry/misc/BehaviourSpellDispense.java create mode 100644 src/main/java/electroblob/wizardry/misc/Forfeit.java rename src/main/java/electroblob/wizardry/{util => misc}/WildcardTradeList.java (98%) rename src/main/java/electroblob/wizardry/{util => misc}/WizardryPathFinder.java (99%) create mode 100644 src/main/java/electroblob/wizardry/packet/PacketCastSpellAtPos.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketConquerShrine.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketDispenserCastSpell.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketEmitterData.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketEndSlowTime.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketPossession.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketRequestAdvancementSync.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketResurrection.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketSpellProperties.java create mode 100644 src/main/java/electroblob/wizardry/packet/PacketSyncAdvancements.java create mode 100644 src/main/java/electroblob/wizardry/potion/Curse.java create mode 100644 src/main/java/electroblob/wizardry/potion/CurseEnfeeblement.java create mode 100644 src/main/java/electroblob/wizardry/potion/CurseUndeath.java create mode 100644 src/main/java/electroblob/wizardry/potion/ISyncedPotion.java create mode 100644 src/main/java/electroblob/wizardry/potion/PotionContainment.java create mode 100644 src/main/java/electroblob/wizardry/potion/PotionFrostStep.java create mode 100644 src/main/java/electroblob/wizardry/potion/PotionSlowTime.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryEntities.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryLoot.java create mode 100644 src/main/java/electroblob/wizardry/registry/WizardryRecipes.java delete mode 100644 src/main/java/electroblob/wizardry/registry/WizardryRegistry.java create mode 100644 src/main/java/electroblob/wizardry/spell/ArcaneLock.java create mode 100644 src/main/java/electroblob/wizardry/spell/Charge.java create mode 100644 src/main/java/electroblob/wizardry/spell/ConjureBlock.java create mode 100644 src/main/java/electroblob/wizardry/spell/Containment.java create mode 100644 src/main/java/electroblob/wizardry/spell/CurseOfEnfeeblement.java create mode 100644 src/main/java/electroblob/wizardry/spell/CurseOfUndeath.java create mode 100644 src/main/java/electroblob/wizardry/spell/Disintegration.java create mode 100644 src/main/java/electroblob/wizardry/spell/Divination.java rename src/main/java/electroblob/wizardry/spell/{Fireball.java => DragonFireball.java} (54%) create mode 100644 src/main/java/electroblob/wizardry/spell/EmpoweringPresence.java create mode 100644 src/main/java/electroblob/wizardry/spell/Evade.java create mode 100644 src/main/java/electroblob/wizardry/spell/FireBreath.java delete mode 100644 src/main/java/electroblob/wizardry/spell/Firestorm.java create mode 100644 src/main/java/electroblob/wizardry/spell/ForceArrow.java create mode 100644 src/main/java/electroblob/wizardry/spell/Forcefield.java create mode 100644 src/main/java/electroblob/wizardry/spell/ForestOfThorns.java create mode 100644 src/main/java/electroblob/wizardry/spell/Grapple.java delete mode 100644 src/main/java/electroblob/wizardry/spell/GreaterFireball.java create mode 100644 src/main/java/electroblob/wizardry/spell/GreaterTelekinesis.java create mode 100644 src/main/java/electroblob/wizardry/spell/Mine.java create mode 100644 src/main/java/electroblob/wizardry/spell/Paralysis.java create mode 100644 src/main/java/electroblob/wizardry/spell/Possession.java create mode 100644 src/main/java/electroblob/wizardry/spell/RayOfPurification.java create mode 100644 src/main/java/electroblob/wizardry/spell/RemoveCurse.java create mode 100644 src/main/java/electroblob/wizardry/spell/Resurrection.java create mode 100644 src/main/java/electroblob/wizardry/spell/Reversal.java create mode 100644 src/main/java/electroblob/wizardry/spell/Satiety.java create mode 100644 src/main/java/electroblob/wizardry/spell/ShulkerBullet.java create mode 100644 src/main/java/electroblob/wizardry/spell/SlowTime.java create mode 100644 src/main/java/electroblob/wizardry/spell/SpeedTime.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java create mode 100644 src/main/java/electroblob/wizardry/spell/SummonZombie.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/SlotItemClassList.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSaveTimed.java create mode 100644 src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java create mode 100644 src/main/java/electroblob/wizardry/util/AllyDesignationSystem.java create mode 100644 src/main/java/electroblob/wizardry/util/CustomSoundCategory.java create mode 100644 src/main/java/electroblob/wizardry/util/Location.java create mode 100644 src/main/java/electroblob/wizardry/util/NBTExtras.java create mode 100644 src/main/java/electroblob/wizardry/util/RayTracer.java create mode 100644 src/main/java/electroblob/wizardry/util/RelativeFacing.java create mode 100644 src/main/java/electroblob/wizardry/util/SpellProperties.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/MossifierTemplateProcessor.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/MultiTemplateProcessor.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/WoodTypeTemplateProcessor.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/WorldGenCrystalFlower.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/WorldGenCrystalOre.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/WorldGenObelisk.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/WorldGenShrine.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/WorldGenSurfaceStructure.java create mode 100644 src/main/java/electroblob/wizardry/worldgen/WorldGenWizardTower.java create mode 100644 src/main/resources/assets/ebwizardry/advancements/advanced.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/all_artefacts.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/artefact.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/charge_creeper.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/craft_flask.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/discover_master_spell.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/discover_spell.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/element_master.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/elemental.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/enchant_scroll.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/frankenstein.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/freeze_blaze.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/arcane_workbench.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/crystal_flowers.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/elements.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/magical_creatures.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/mana_flasks.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/obelisks.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/on_subsection_unlock.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/scrolls.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/spells.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/throwables.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/handbook/tome_of_arcana.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/jam_wizard.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/pig_tornado.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/self_destruct.json delete mode 100644 src/main/resources/assets/ebwizardry/advancements/slime_skeleton.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/spell_failure.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/visit_shrine.json create mode 100644 src/main/resources/assets/ebwizardry/advancements/wizard_tower.json delete mode 100644 src/main/resources/assets/ebwizardry/blockstates/crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/dry_frosted_ice.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/earth_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/earth_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/earth_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/fire_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/fire_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/fire_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/healing_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/healing_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/healing_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/ice_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/ice_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/ice_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/lightning_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/lightning_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/lightning_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/magic_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/necromancy_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/necromancy_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/necromancy_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/obsidian_crust.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/sorcery_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/sorcery_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/sorcery_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/blockstates/thorns.json create mode 100644 src/main/resources/assets/ebwizardry/lang/fr_fr.lang create mode 100644 src/main/resources/assets/ebwizardry/lang/ko_kr.lang create mode 100644 src/main/resources/assets/ebwizardry/loot_tables/chests/jungle_dispenser_additions.json create mode 100644 src/main/resources/assets/ebwizardry/loot_tables/chests/obelisk.json create mode 100644 src/main/resources/assets/ebwizardry/loot_tables/chests/shrine.json create mode 100644 src/main/resources/assets/ebwizardry/loot_tables/subsets/elemental_crystals.json create mode 100644 src/main/resources/assets/ebwizardry/loot_tables/subsets/epic_artefacts.json delete mode 100644 src/main/resources/assets/ebwizardry/loot_tables/subsets/novice_wands.json create mode 100644 src/main/resources/assets/ebwizardry/loot_tables/subsets/rare_artefacts.json create mode 100644 src/main/resources/assets/ebwizardry/loot_tables/subsets/uncommon_artefacts.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/earth_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/earth_runestone_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/earth_runestone_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/earth_runestone_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/earth_runestone_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/earth_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/fire_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/fire_runestone_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/fire_runestone_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/fire_runestone_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/fire_runestone_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/fire_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/healing_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/healing_runestone_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/healing_runestone_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/healing_runestone_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/healing_runestone_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/healing_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/ice_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/ice_runestone_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/ice_runestone_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/ice_runestone_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/ice_runestone_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/ice_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/lightning_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/lightning_runestone_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/lightning_runestone_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/lightning_runestone_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/lightning_runestone_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/lightning_runestone_pedestal.json rename src/main/resources/assets/ebwizardry/models/block/{crystal_block.json => magic_crystal_block.json} (100%) create mode 100644 src/main/resources/assets/ebwizardry/models/block/necromancy_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/obsidian_crust_0.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/obsidian_crust_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/obsidian_crust_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/obsidian_crust_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/runestone.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/sorcery_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_lower_0.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_lower_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_lower_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_lower_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_lower_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_lower_5.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_lower_6.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_lower_7.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_upper_0.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_upper_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_upper_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_upper_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_upper_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_upper_5.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_upper_6.json create mode 100644 src/main/resources/assets/ebwizardry/models/block/thorns_upper_7.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_anchoring.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_arcane_defence.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_auto_shield.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_banishing.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_channeling.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_fire_cloaking.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_fire_protection.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_glide.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_ice_immunity.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_ice_protection.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_lich.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_potential.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_recovery.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_resurrection.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_transience.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_warding.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_wisdom.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/amulet_wither_immunity.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/astral_diamond.json delete mode 100644 src/main/resources/assets/ebwizardry/models/item/basic_lightning_wand.json delete mode 100644 src/main/resources/assets/ebwizardry/models/item/basic_necromancy_wand.json delete mode 100644 src/main/resources/assets/ebwizardry/models/item/basic_sorcery_wand.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_abseiling.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_auto_smelt.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_experience_tome.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_feeding.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_flight.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_growth.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_haggler.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_lava_walking.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_light.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_minion_health.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_minion_variants.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_silk_touch.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_stop_time.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_storm.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/charm_transportation.json delete mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_block.json rename src/main/resources/assets/ebwizardry/models/item/{magic_crystal.json => crystal_earth.json} (53%) create mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_fire.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_healing.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_ice.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_lightning.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_magic.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_necromancy.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_shard.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/crystal_sorcery.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/earth_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/earth_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/earth_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/fire_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/fire_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/fire_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_0.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_5.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_6.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_7.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_0.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_5.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_6.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_7.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/grand_crystal.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/healing_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/healing_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/healing_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ice_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ice_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ice_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/large_mana_flask.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/lightning_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/lightning_hammer.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/lightning_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/lightning_runestone_pedestal.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/magic_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/medium_mana_flask.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/melee_upgrade.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/necromancy_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/necromancy_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/necromancy_runestone_pedestal.json rename src/main/resources/assets/ebwizardry/models/item/{basic_fire_wand.json => novice_earth_wand.json} (51%) rename src/main/resources/assets/ebwizardry/models/item/{basic_earth_wand.json => novice_fire_wand.json} (52%) rename src/main/resources/assets/ebwizardry/models/item/{basic_healing_wand.json => novice_healing_wand.json} (50%) rename src/main/resources/assets/ebwizardry/models/item/{basic_ice_wand.json => novice_ice_wand.json} (52%) create mode 100644 src/main/resources/assets/ebwizardry/models/item/novice_lightning_wand.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/novice_necromancy_wand.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/novice_sorcery_wand.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/purifying_elixir.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_arcane_frost.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_battlemage.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_blockwrangler.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_combustion.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_condensing.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_conjurer.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_defender.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_disintegration.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_earth_biome.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_earth_melee.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_extraction.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_fire_biome.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_fire_melee.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_full_moon.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_hammer.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_ice_biome.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_ice_melee.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_interdiction.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_leeching.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_lightning_melee.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_mana_return.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_mind_control.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_necromancy_melee.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_paladin.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_poison.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_seeking.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_shattering.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_siphoning.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_soulbinding.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_spirit_animal.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/ring_storm.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/runestone_item.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/runestone_pedestal_item.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/small_mana_flask.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/sorcery_crystal_block.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/sorcery_runestone.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/sorcery_runestone_pedestal.json rename src/main/resources/assets/ebwizardry/models/item/{mana_flask.json => spark_bomb.json} (55%) create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_0.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_5.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_6.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_7.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_0.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_5.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_6.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_7.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_0.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_1.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_2.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_3.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_4.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_5.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_6.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_7.json create mode 100644 src/main/resources/assets/ebwizardry/models/item/thorns.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_earth.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_fire.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_healing.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_ice.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_lightning.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_necromancy.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_sorcery.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_earth.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_fire.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_healing.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_ice.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_lightning.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_necromancy.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_sorcery.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/crystal_shard.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/large_mana_flask.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/medium_mana_flask.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_earth.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_fire.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_healing.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_ice.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_lightning.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_necromancy.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_earth.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_fire.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_healing.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_ice.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_lightning.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_necromancy.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_sorcery.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/runestone_sorcery.json rename src/main/resources/assets/ebwizardry/recipes/{mana_flask.json => small_mana_flask.json} (71%) create mode 100644 src/main/resources/assets/ebwizardry/recipes/spark_bomb.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/wand_earth.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/wand_fire.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/wand_healing.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/wand_ice.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/wand_lightning.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/wand_necromancy.json create mode 100644 src/main/resources/assets/ebwizardry/recipes/wand_sorcery.json create mode 100644 src/main/resources/assets/ebwizardry/shaders/post/possession.json create mode 100644 src/main/resources/assets/ebwizardry/shaders/post/sixth_sense.json create mode 100644 src/main/resources/assets/ebwizardry/shaders/post/slow_time.json create mode 100644 src/main/resources/assets/ebwizardry/shaders/post/transience.json create mode 100644 src/main/resources/assets/ebwizardry/sounds/aura_end.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/aura_loop.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/aura_start.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/book.ogg delete mode 100644 src/main/resources/assets/ebwizardry/sounds/boom.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/buff.ogg rename src/main/resources/assets/ebwizardry/sounds/{aura.ogg => conjure.ogg} (100%) rename src/main/resources/assets/ebwizardry/sounds/{largeaura.ogg => conjure_large.ogg} (100%) create mode 100644 src/main/resources/assets/ebwizardry/sounds/dark_aura_end.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/dark_aura_loop.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/dark_aura_start.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/firebolt.ogg delete mode 100644 src/main/resources/assets/ebwizardry/sounds/flameray1.ogg delete mode 100644 src/main/resources/assets/ebwizardry/sounds/flameray2.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/flames_end.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/flames_loop.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/flames_start.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/grow.ogg rename src/main/resources/assets/ebwizardry/sounds/{electricityb.ogg => lightning_ray_end.ogg} (100%) create mode 100644 src/main/resources/assets/ebwizardry/sounds/lightning_ray_loop.ogg rename src/main/resources/assets/ebwizardry/sounds/{electricitya.ogg => lightning_ray_start.ogg} (100%) create mode 100644 src/main/resources/assets/ebwizardry/sounds/page1.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/page2.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/page3.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/pull1.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/pull2.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/shockwave.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/small_aura_end.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/small_aura_loop.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/small_aura_start.ogg create mode 100644 src/main/resources/assets/ebwizardry/sounds/spellbind.ogg rename src/main/resources/assets/ebwizardry/sounds/{darkaura1.ogg => summon1.ogg} (100%) rename src/main/resources/assets/ebwizardry/sounds/{darkaura2.ogg => summon2.ogg} (100%) create mode 100644 src/main/resources/assets/ebwizardry/spells/agility.json create mode 100644 src/main/resources/assets/ebwizardry/spells/arc.json create mode 100644 src/main/resources/assets/ebwizardry/spells/arcane_jammer.json create mode 100644 src/main/resources/assets/ebwizardry/spells/arcane_lock.json create mode 100644 src/main/resources/assets/ebwizardry/spells/arrow_rain.json create mode 100644 src/main/resources/assets/ebwizardry/spells/banish.json create mode 100644 src/main/resources/assets/ebwizardry/spells/black_hole.json create mode 100644 src/main/resources/assets/ebwizardry/spells/blink.json create mode 100644 src/main/resources/assets/ebwizardry/spells/blizzard.json create mode 100644 src/main/resources/assets/ebwizardry/spells/bubble.json create mode 100644 src/main/resources/assets/ebwizardry/spells/chain_lightning.json create mode 100644 src/main/resources/assets/ebwizardry/spells/charge.json create mode 100644 src/main/resources/assets/ebwizardry/spells/clairvoyance.json create mode 100644 src/main/resources/assets/ebwizardry/spells/cobwebs.json create mode 100644 src/main/resources/assets/ebwizardry/spells/combustion_rune.json create mode 100644 src/main/resources/assets/ebwizardry/spells/conjure_armour.json create mode 100644 src/main/resources/assets/ebwizardry/spells/conjure_block.json create mode 100644 src/main/resources/assets/ebwizardry/spells/conjure_bow.json create mode 100644 src/main/resources/assets/ebwizardry/spells/conjure_pickaxe.json create mode 100644 src/main/resources/assets/ebwizardry/spells/conjure_sword.json create mode 100644 src/main/resources/assets/ebwizardry/spells/containment.json create mode 100644 src/main/resources/assets/ebwizardry/spells/cure_effects.json create mode 100644 src/main/resources/assets/ebwizardry/spells/curse_of_enfeeblement.json create mode 100644 src/main/resources/assets/ebwizardry/spells/curse_of_soulbinding.json create mode 100644 src/main/resources/assets/ebwizardry/spells/curse_of_undeath.json create mode 100644 src/main/resources/assets/ebwizardry/spells/darkness_orb.json create mode 100644 src/main/resources/assets/ebwizardry/spells/darkvision.json create mode 100644 src/main/resources/assets/ebwizardry/spells/dart.json create mode 100644 src/main/resources/assets/ebwizardry/spells/decay.json create mode 100644 src/main/resources/assets/ebwizardry/spells/decoy.json create mode 100644 src/main/resources/assets/ebwizardry/spells/detonate.json create mode 100644 src/main/resources/assets/ebwizardry/spells/diamondflesh.json create mode 100644 src/main/resources/assets/ebwizardry/spells/disintegration.json create mode 100644 src/main/resources/assets/ebwizardry/spells/divination.json create mode 100644 src/main/resources/assets/ebwizardry/spells/dragon_fireball.json create mode 100644 src/main/resources/assets/ebwizardry/spells/earthquake.json create mode 100644 src/main/resources/assets/ebwizardry/spells/empowering_presence.json create mode 100644 src/main/resources/assets/ebwizardry/spells/entrapment.json create mode 100644 src/main/resources/assets/ebwizardry/spells/evade.json create mode 100644 src/main/resources/assets/ebwizardry/spells/fire_breath.json create mode 100644 src/main/resources/assets/ebwizardry/spells/fire_resistance.json create mode 100644 src/main/resources/assets/ebwizardry/spells/fire_sigil.json create mode 100644 src/main/resources/assets/ebwizardry/spells/fireball.json create mode 100644 src/main/resources/assets/ebwizardry/spells/firebolt.json create mode 100644 src/main/resources/assets/ebwizardry/spells/firebomb.json create mode 100644 src/main/resources/assets/ebwizardry/spells/fireskin.json create mode 100644 src/main/resources/assets/ebwizardry/spells/flame_ray.json create mode 100644 src/main/resources/assets/ebwizardry/spells/flaming_axe.json create mode 100644 src/main/resources/assets/ebwizardry/spells/flaming_weapon.json create mode 100644 src/main/resources/assets/ebwizardry/spells/flight.json create mode 100644 src/main/resources/assets/ebwizardry/spells/font_of_mana.json create mode 100644 src/main/resources/assets/ebwizardry/spells/font_of_vitality.json create mode 100644 src/main/resources/assets/ebwizardry/spells/force_arrow.json create mode 100644 src/main/resources/assets/ebwizardry/spells/force_orb.json create mode 100644 src/main/resources/assets/ebwizardry/spells/forcefield.json create mode 100644 src/main/resources/assets/ebwizardry/spells/forest_of_thorns.json create mode 100644 src/main/resources/assets/ebwizardry/spells/forests_curse.json create mode 100644 src/main/resources/assets/ebwizardry/spells/freeze.json create mode 100644 src/main/resources/assets/ebwizardry/spells/freezing_weapon.json create mode 100644 src/main/resources/assets/ebwizardry/spells/frost_axe.json create mode 100644 src/main/resources/assets/ebwizardry/spells/frost_ray.json create mode 100644 src/main/resources/assets/ebwizardry/spells/frost_sigil.json create mode 100644 src/main/resources/assets/ebwizardry/spells/frost_step.json create mode 100644 src/main/resources/assets/ebwizardry/spells/glide.json create mode 100644 src/main/resources/assets/ebwizardry/spells/grapple.json create mode 100644 src/main/resources/assets/ebwizardry/spells/greater_fireball.json create mode 100644 src/main/resources/assets/ebwizardry/spells/greater_heal.json create mode 100644 src/main/resources/assets/ebwizardry/spells/greater_telekinesis.json create mode 100644 src/main/resources/assets/ebwizardry/spells/greater_ward.json create mode 100644 src/main/resources/assets/ebwizardry/spells/group_heal.json create mode 100644 src/main/resources/assets/ebwizardry/spells/growth_aura.json create mode 100644 src/main/resources/assets/ebwizardry/spells/hailstorm.json create mode 100644 src/main/resources/assets/ebwizardry/spells/heal.json create mode 100644 src/main/resources/assets/ebwizardry/spells/heal_ally.json create mode 100644 src/main/resources/assets/ebwizardry/spells/healing_aura.json create mode 100644 src/main/resources/assets/ebwizardry/spells/homing_spark.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ice_age.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ice_charge.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ice_lance.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ice_shard.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ice_shroud.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ice_spikes.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ice_statue.json create mode 100644 src/main/resources/assets/ebwizardry/spells/iceball.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ignite.json create mode 100644 src/main/resources/assets/ebwizardry/spells/imbue_weapon.json create mode 100644 src/main/resources/assets/ebwizardry/spells/intimidate.json create mode 100644 src/main/resources/assets/ebwizardry/spells/invigorating_presence.json create mode 100644 src/main/resources/assets/ebwizardry/spells/invisibility.json create mode 100644 src/main/resources/assets/ebwizardry/spells/invoke_weather.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ironflesh.json create mode 100644 src/main/resources/assets/ebwizardry/spells/leap.json create mode 100644 src/main/resources/assets/ebwizardry/spells/levitation.json create mode 100644 src/main/resources/assets/ebwizardry/spells/life_drain.json create mode 100644 src/main/resources/assets/ebwizardry/spells/light.json create mode 100644 src/main/resources/assets/ebwizardry/spells/lightning_arrow.json create mode 100644 src/main/resources/assets/ebwizardry/spells/lightning_bolt.json create mode 100644 src/main/resources/assets/ebwizardry/spells/lightning_disc.json create mode 100644 src/main/resources/assets/ebwizardry/spells/lightning_hammer.json create mode 100644 src/main/resources/assets/ebwizardry/spells/lightning_pulse.json create mode 100644 src/main/resources/assets/ebwizardry/spells/lightning_ray.json create mode 100644 src/main/resources/assets/ebwizardry/spells/lightning_sigil.json create mode 100644 src/main/resources/assets/ebwizardry/spells/lightning_web.json create mode 100644 src/main/resources/assets/ebwizardry/spells/magic_missile.json create mode 100644 src/main/resources/assets/ebwizardry/spells/metamorphosis.json create mode 100644 src/main/resources/assets/ebwizardry/spells/meteor.json create mode 100644 src/main/resources/assets/ebwizardry/spells/mind_control.json create mode 100644 src/main/resources/assets/ebwizardry/spells/mind_trick.json create mode 100644 src/main/resources/assets/ebwizardry/spells/mine.json create mode 100644 src/main/resources/assets/ebwizardry/spells/muffle.json create mode 100644 src/main/resources/assets/ebwizardry/spells/none.json create mode 100644 src/main/resources/assets/ebwizardry/spells/oakflesh.json create mode 100644 src/main/resources/assets/ebwizardry/spells/paralysis.json create mode 100644 src/main/resources/assets/ebwizardry/spells/petrify.json create mode 100644 src/main/resources/assets/ebwizardry/spells/phase_step.json create mode 100644 src/main/resources/assets/ebwizardry/spells/plague_of_darkness.json create mode 100644 src/main/resources/assets/ebwizardry/spells/pocket_furnace.json create mode 100644 src/main/resources/assets/ebwizardry/spells/pocket_workbench.json create mode 100644 src/main/resources/assets/ebwizardry/spells/poison.json create mode 100644 src/main/resources/assets/ebwizardry/spells/poison_bomb.json create mode 100644 src/main/resources/assets/ebwizardry/spells/possession.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ray_of_purification.json create mode 100644 src/main/resources/assets/ebwizardry/spells/remove_curse.json create mode 100644 src/main/resources/assets/ebwizardry/spells/replenish_hunger.json create mode 100644 src/main/resources/assets/ebwizardry/spells/resurrection.json create mode 100644 src/main/resources/assets/ebwizardry/spells/reversal.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ring_of_fire.json create mode 100644 src/main/resources/assets/ebwizardry/spells/satiety.json create mode 100644 src/main/resources/assets/ebwizardry/spells/shadow_ward.json create mode 100644 src/main/resources/assets/ebwizardry/spells/shield.json create mode 100644 src/main/resources/assets/ebwizardry/spells/shockwave.json create mode 100644 src/main/resources/assets/ebwizardry/spells/shulker_bullet.json create mode 100644 src/main/resources/assets/ebwizardry/spells/silverfish_swarm.json create mode 100644 src/main/resources/assets/ebwizardry/spells/sixth_sense.json create mode 100644 src/main/resources/assets/ebwizardry/spells/slime.json create mode 100644 src/main/resources/assets/ebwizardry/spells/slow_time.json create mode 100644 src/main/resources/assets/ebwizardry/spells/smoke_bomb.json create mode 100644 src/main/resources/assets/ebwizardry/spells/snare.json create mode 100644 src/main/resources/assets/ebwizardry/spells/snowball.json create mode 100644 src/main/resources/assets/ebwizardry/spells/spark_bomb.json create mode 100644 src/main/resources/assets/ebwizardry/spells/spectral_pathway.json create mode 100644 src/main/resources/assets/ebwizardry/spells/speed_time.json create mode 100644 src/main/resources/assets/ebwizardry/spells/spider_swarm.json create mode 100644 src/main/resources/assets/ebwizardry/spells/static_aura.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_blaze.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_ice_giant.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_ice_wraith.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_iron_golem.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_lightning_wraith.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_phoenix.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_shadow_wraith.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_skeleton.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_skeleton_legion.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_snow_golem.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_spirit_horse.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_spirit_wolf.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_storm_elemental.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_wither_skeleton.json create mode 100644 src/main/resources/assets/ebwizardry/spells/summon_zombie.json create mode 100644 src/main/resources/assets/ebwizardry/spells/telekinesis.json create mode 100644 src/main/resources/assets/ebwizardry/spells/thunderbolt.json create mode 100644 src/main/resources/assets/ebwizardry/spells/thunderstorm.json create mode 100644 src/main/resources/assets/ebwizardry/spells/tornado.json create mode 100644 src/main/resources/assets/ebwizardry/spells/transience.json create mode 100644 src/main/resources/assets/ebwizardry/spells/transportation.json create mode 100644 src/main/resources/assets/ebwizardry/spells/vanishing_box.json create mode 100644 src/main/resources/assets/ebwizardry/spells/vex_swarm.json create mode 100644 src/main/resources/assets/ebwizardry/spells/wall_of_frost.json create mode 100644 src/main/resources/assets/ebwizardry/spells/ward.json create mode 100644 src/main/resources/assets/ebwizardry/spells/water_breathing.json create mode 100644 src/main/resources/assets/ebwizardry/spells/whirlwind.json create mode 100644 src/main/resources/assets/ebwizardry/spells/wither.json create mode 100644 src/main/resources/assets/ebwizardry/spells/wither_skull.json create mode 100644 src/main/resources/assets/ebwizardry/structures/obelisk_0.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/obelisk_1.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/obelisk_2.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/obelisk_3.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/obelisk_4.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/shrine_0.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/shrine_1.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/shrine_2.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/shrine_3.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/shrine_4.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/shrine_5.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/shrine_6.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/shrine_7.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/wizard_tower_0.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/wizard_tower_1.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/wizard_tower_2.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/wizard_tower_3.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/wizard_tower_chest_0.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/wizard_tower_chest_1.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/wizard_tower_chest_2.nbt create mode 100644 src/main/resources/assets/ebwizardry/structures/wizard_tower_chest_3.nbt delete mode 100644 src/main/resources/assets/ebwizardry/texts/handbook_en_gb.txt delete mode 100644 src/main/resources/assets/ebwizardry/texts/handbook_en_us.txt create mode 100644 src/main/resources/assets/ebwizardry/texts/handbook_ko_kr.txt delete mode 100644 src/main/resources/assets/ebwizardry/textures/armour/invisible_armour.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_earth.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_earth_legs.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_fire.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_fire_legs.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_healing.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_healing_legs.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_ice.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_ice_legs.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_legs.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_lightning.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_lightning_legs.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_necromancy.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_necromancy_legs.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_sorcery.png create mode 100644 src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_sorcery_legs.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_earth.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_fire.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_healing.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_ice.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_lightning.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_necromancy.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_sorcery.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/obsidian_crust_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/obsidian_crust_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/obsidian_crust_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/obsidian_crust_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_1_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_2_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_3_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_4_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_1_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_2_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_3_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_4_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_1_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_2_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_3_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_4_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_1_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_2_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_3_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_4_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_1_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_2_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_3_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_4_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_1_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_2_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_3_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_4_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_earth.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_earth_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_fire.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_fire_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_healing.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_healing_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_ice.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_ice_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_lightning.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_lightning_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_necromancy.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_necromancy_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_sorcery.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_sorcery_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_1_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_2_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_3_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_4_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/combustion_rune.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/containment_field_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/containment_field_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/containment_field_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/containment_field_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/containment_field_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/containment_field_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/containment_field_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/containment_field_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/ember.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/fireball.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/frost_overlay.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/iceball.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/wizard_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/wizard_8.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/wizard_female_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/wizard_female_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/entity/wizard_female_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/armour_picture.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/curse_background.png rename src/main/resources/assets/ebwizardry/textures/gui/{element_icon_simple.png => element_icon_magic.png} (100%) create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/elements_picture.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/obelisk_picture.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_arcane_jammer.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_containment.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_curse_of_enfeeblement.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_curse_of_soulbinding.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_curse_of_undeath.png rename src/main/resources/assets/ebwizardry/textures/gui/{decay_icon.png => potion_icon_decay.png} (100%) create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_empowerment.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_fear.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_fireskin.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_font_of_mana.png rename src/main/resources/assets/ebwizardry/textures/gui/{frost_icon.png => potion_icon_frost.png} (100%) create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_frost_step.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_ice_shroud.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_mind_control.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_mind_trick.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_muffle.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_paralysis.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_sixth_sense.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_slow_time.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_static_aura.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_transience.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icon_ward.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/gui/potion_icons.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/shrine_picture.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_book_basic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_book_novice.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/mahogany.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/mahogany.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/oceanic.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/oceanic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/planks.json create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spell_hud/planks.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/gui/spellbook.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/tiers_picture.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/tower_picture.png create mode 100644 src/main/resources/assets/ebwizardry/textures/gui/transportation_marker.png create mode 100644 src/main/resources/assets/ebwizardry/textures/integration/antiqueatlas/obelisk.png create mode 100644 src/main/resources/assets/ebwizardry/textures/integration/antiqueatlas/shrine.png create mode 100644 src/main/resources/assets/ebwizardry/textures/integration/antiqueatlas/wizard_tower.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_anchoring.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_arcane_defence.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_auto_shield.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_banishing.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_channeling.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_fire_cloaking.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_fire_protection.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_glide.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_ice_immunity.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_ice_protection.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_lich.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_potential.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_recovery.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_resurrection.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_transience.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_warding.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_wisdom.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/amulet_wither_immunity.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/astral_diamond.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_abseiling.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_auto_smelt.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_experience_tome.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_feeding.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_flight.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_growth.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_haggler.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_lava_walking.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_light.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_minion_health.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_minion_variants.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_silk_touch.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_stop_time.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_storm.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/charm_transportation.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_earth.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_fire.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_grand.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_healing.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_ice.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_lightning.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_magic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_necromancy.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_shard.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/crystal_sorcery.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_1.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_2.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_3.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_4.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_5.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_6.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_7.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_7.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/items/magic_crystal.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/items/mana_flask.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/mana_flask_large.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/mana_flask_medium.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/mana_flask_small.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/purifying_elixir.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_arcane_frost.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_battlemage.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_blockwrangler.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_bronze_generic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_combustion.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_combustion.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_condensing.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_conjurer.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_defender.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_defender.png.mcmeta create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_disintegration.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_earth_biome.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_earth_melee.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_extraction.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_fire_biome.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_fire_melee.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_full_moon.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_gold_generic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_hammer.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_ice_biome.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_ice_melee.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_interdiction.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_leeching.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_lightning_melee.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_mana_return.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_mind_control.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_necromancy_melee.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_paladin.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_poison.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_seeking.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_shattering.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_silver_generic.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_siphoning.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_soulbinding.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_storm.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/ring_storm.png.mcmeta rename src/main/resources/assets/ebwizardry/textures/{entity => items}/spark_bomb.png (100%) create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/upgrade_melee.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/items/wand_basic_lightning.png delete mode 100644 src/main/resources/assets/ebwizardry/textures/items/wand_basic_necromancy.png rename src/main/resources/assets/ebwizardry/textures/items/{wand_basic.png => wand_novice.png} (100%) rename src/main/resources/assets/ebwizardry/textures/items/{wand_basic_earth.png => wand_novice_earth.png} (100%) rename src/main/resources/assets/ebwizardry/textures/items/{wand_basic_fire.png => wand_novice_fire.png} (100%) rename src/main/resources/assets/ebwizardry/textures/items/{wand_basic_healing.png => wand_novice_healing.png} (100%) rename src/main/resources/assets/ebwizardry/textures/items/{wand_basic_ice.png => wand_novice_ice.png} (100%) create mode 100644 src/main/resources/assets/ebwizardry/textures/items/wand_novice_lightning.png create mode 100644 src/main/resources/assets/ebwizardry/textures/items/wand_novice_necromancy.png rename src/main/resources/assets/ebwizardry/textures/items/{wand_basic_sorcery.png => wand_novice_sorcery.png} (100%) create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_0_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_0_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_0_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_0_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_0_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_0_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_0_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_0_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_1_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_1_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_1_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_1_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_1_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_1_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_1_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_1_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_2_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_2_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_2_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_2_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_2_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_2_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_2_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_2_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_3_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_3_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_3_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_3_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_3_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_3_5.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_3_6.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/flame_3_7.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/summon.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/vine.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_0.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_1.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_2.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_3.png create mode 100644 src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_4.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/arcane_lock.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/charge.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/combustion_rune.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/conjure_axe.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/conjure_block.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/conjure_shovel.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/containment.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/curse_of_enfeeblement.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/curse_of_undeath.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/disintegration.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/divination.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/dragon_fireball.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/empowering_presence.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/evade.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/fire_breath.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/forest_of_thorns.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/frost_step.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/grapple.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/greater_telekinesis.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/greater_ward.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/guardian_angel.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/guardian_beam.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/healing_totem.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/iceball.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/mine.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/muffle.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/paralysis.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/permafrost.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/possession.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/ray_of_purification.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/remove_curse.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/resurrection.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/reversal.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/rupture.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/satiety.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/shapeshift.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/shocking_weapon.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/shulker_bullet.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/slow_time.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/speed_time.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/summon_creeper.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/vex_swarm.png create mode 100644 src/main/resources/assets/ebwizardry/textures/spells/ward.png diff --git a/.gitignore b/.gitignore index 939f55fc..d45b2340 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ build # other eclipse run -misc -libs +logs +/misc +/libs +libsfordeobf +generated Thumbs.db \ No newline at end of file diff --git a/build.gradle b/build.gradle index 775fd0d4..6bd1915b 100644 --- a/build.gradle +++ b/build.gradle @@ -11,17 +11,39 @@ apply plugin: 'net.minecraftforge.gradle.forge' //Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. -version = " 4.1.4 - MC 1.12.2" +version = "4.2.0" // There, it matches semver, happy now? (I am just gonna rename the file afterwards, you know that right?) group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = "Electroblob's Wizardry " +archivesBaseName = "ElectroblobsWizardry" sourceCompatibility = targetCompatibility = "1.8" // Need this here so eclipse task generates correctly. compileJava { sourceCompatibility = targetCompatibility = "1.8" } +repositories { + maven { + // location of the maven that hosts JEI files + name = "Progwml6 maven" + url = "http://dvs1.progwml6.com/files/maven" + } + maven { + // location of a maven mirror for JEI files, as a fallback + name = "ModMaven" + url = "modmaven.k-4u.nl" + } + flatDir { + // evErYthINg hAS tO Be a mAVeN rEPoSiTOrY... (to use deobfProvided, for some reason) + // The lack of documentation is actually quite impressive, see the following threads: + // http://www.minecraftforge.net/forum/topic/44262-solved-how-to-build-mod-with-dependencies/ + // https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2866817-setting-up-dependencies-in-minecraft-forge-with + // http://www.minecraftforge.net/forum/topic/44534-adding-dependencies-to-a-forge-project/ + dirs "libsfordeobf" // Don't use libs or forge will think you have duplicate mods + } + +} + minecraft { - version = "1.12.2-14.23.2.2611" + version = "1.12.2-14.23.5.2814" runDir = "run" // the mappings can be changed at any time, and must be in the following format. @@ -38,6 +60,17 @@ dependencies { // or you may define them like so.. //compile "some.group:artifact:version:classifier" //compile "some.group:artifact:version" + + // compile against the JEI API but do not include it at runtime + deobfProvided "mezz.jei:jei_${mc_version}:${jei_version}:api" + // at runtime, use the full JEI jar + runtime "mezz.jei:jei_${mc_version}:${jei_version}" + + //deobfProvided "baubles:baubles-1.12:1.5.2:api" // #ihavenoideawhatimdoing #itjustworks + //runtime "baubles:baubles-1.12:1.5.2" // If in doubt, copy what already works + + //deobfProvided "antiqueatlas:antiqueatlas-1.12.2:4.5.1:src" + //runtime "antiqueatlas:antiqueatlas-1.12.2:4.5.1" // real examples //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env diff --git a/gradle.properties b/gradle.properties index e9b9fd5a..b4ec0fb3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,5 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G +mc_version=1.12.2 +jei_version=4.13.1.225 \ No newline at end of file diff --git a/gradlew b/gradlew index 91a7e269..ac7df23f 100644 --- a/gradlew +++ b/gradlew @@ -79,14 +79,14 @@ if [ -n "$JAVA_HOME" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." +locations of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." +locations of your Java installation." fi # Increase the maximum file descriptors if we can. diff --git a/gradlew.bat b/gradlew.bat index 8a0b282a..5bb5d8ea 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -27,7 +27,7 @@ echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo locations of your Java installation. goto fail @@ -41,7 +41,7 @@ echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo locations of your Java installation. goto fail diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index 7e45ebe8..71165cc2 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -1,33 +1,32 @@ package electroblob.wizardry; -import electroblob.wizardry.client.particle.ParticleWizardry; import electroblob.wizardry.item.ItemSpectralBow; -import electroblob.wizardry.packet.PacketCastContinuousSpell; -import electroblob.wizardry.packet.PacketCastSpell; -import electroblob.wizardry.packet.PacketClairvoyance; -import electroblob.wizardry.packet.PacketGlyphData; -import electroblob.wizardry.packet.PacketNPCCastSpell.Message; -import electroblob.wizardry.packet.PacketPlayerSync; -import electroblob.wizardry.packet.PacketTransportation; -import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.packet.*; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.translation.I18n; import net.minecraft.world.World; import net.minecraftforge.common.config.Property; +import java.util.List; +import java.util.Set; + /** * The common proxy for wizardry, serving the usual purpose of dealing with all things that need to be handled * differently on the client and the server. A lot of the methods here appear to do absolutely nothing; this is because * they do client-only things which are only handled in the client proxy. * - * @see {@link electroblob.wizardry.client.ClientProxy} + * @see electroblob.wizardry.client.ClientProxy ClientProxy * @author Electroblob * @since Wizardry 1.0 */ @@ -51,15 +50,19 @@ public class CommonProxy { public void registerResourceReloadListeners(){} + public void registerSoundEventListener(){} + + public void registerAtlasMarkers(){} + // SECTION Particles // =============================================================================================================== /** Called from init() in the main mod class to initialise the particle factories. */ - public void initParticleFactories(){} // Does nothing since particles are client-side only + public void registerParticles(){} // Does nothing since particles are client-side only /** Creates a new particle of the specified type from the appropriate particle factory. Does not actually spawn the * particle; use {@link electroblob.wizardry.util.ParticleBuilder ParticleBuilder} to spawn particles. */ - public ParticleWizardry createParticle(Type type, World world, double x, double y, double z){ + public electroblob.wizardry.client.particle.ParticleWizardry createParticle(ResourceLocation type, World world, double x, double y, double z){ return null; } @@ -70,19 +73,23 @@ public class CommonProxy { // SECTION Items // =============================================================================================================== + public boolean shouldDisplayDiscovered(Spell spell, ItemStack stack){ + return false; + } + public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack){ return null; } /** * Returns the translated name of the scroll, taking spell discovery into account. If, for some reason, this gets - * called server-side, it uses the deprecated server version of I18n, with a warning. Since any likely server-side - * use of this method will be for text-based logic purposes (like Bibliocraft's book checking system), and since no - * particular player instance can be accessed, spell discovery is ignored. + * called server-side, it uses the deprecated server version of I18n. Since any likely server-side + * use of this method will be for text-based logic purposes (like Bibliocraft's book checking system), and since + * no particular player instance can be accessed, spell discovery is ignored. */ public String getScrollDisplayName(ItemStack scroll){ - Spell spell = Spell.get(scroll.getItemDamage()); + Spell spell = Spell.byMetadata(scroll.getItemDamage()); return I18n.translateToLocalFormatted("item." + Wizardry.MODID + ":scroll.name", I18n.translateToLocal("spell." + spell.getUnlocalisedName())).trim(); @@ -92,29 +99,53 @@ public class CommonProxy { return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack); } + /** Like {@link CommonProxy#addMultiLineDescription(List, String, Style)}, but style defaults to light grey. */ + public void addMultiLineDescription(List tooltip, String key){ + this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY)); + } + + /** + * Adds a multi-line description to the given tooltip list. The description is first translated using the given + * translation key, then the formatting code for the given style is appended, and finally the string is word-wrapped + * to the standard width (100). + * @param tooltip The tooltip list to add to + * @param key The translation key for the description + * @param style A style to apply + */ + public void addMultiLineDescription(List tooltip, String key, Style style){} + // SECTION Packet Handlers // =============================================================================================================== - public void handlePlayerSyncPacket(PacketPlayerSync.Message message){ - } + public void handlePlayerSyncPacket(PacketPlayerSync.Message message){} - public void handleGlyphDataPacket(PacketGlyphData.Message message){ - } + public void handleGlyphDataPacket(PacketGlyphData.Message message){} - public void handleCastSpellPacket(PacketCastSpell.Message message){ - } + public void handleEmitterDataPacket(PacketEmitterData.Message message){} - public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){ - } + public void handleCastSpellPacket(PacketCastSpell.Message message){} - public void handleNPCCastSpellPacket(Message message){ - } + public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){} - public void handleTransportationPacket(PacketTransportation.Message message){ - } + public void handleNPCCastSpellPacket(PacketNPCCastSpell.Message message){} - public void handleClairvoyancePacket(PacketClairvoyance.Message message){ - } + public void handleDispenserCastSpellPacket(PacketDispenserCastSpell.Message message){} + + public void handleCastSpellAtPosPacket(PacketCastSpellAtPos.Message message){} + + public void handleTransportationPacket(PacketTransportation.Message message){} + + public void handleClairvoyancePacket(PacketClairvoyance.Message message){} + + public void handleAdvancementSyncPacket(PacketSyncAdvancements.Message message){} + + public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){} + + public void handleResurrectionPacket(PacketResurrection.Message message){} + + public void handlePossessionPacket(PacketPossession.Message message){} + + public void handleConquerShrinePacket(PacketConquerShrine.Message message){} // SECTION Misc // =============================================================================================================== @@ -122,6 +153,8 @@ public class CommonProxy { public void setToNumberSliderEntry(Property property){} public void setToHUDChooserEntry(Property property){} + + public void setToNamedBooleanEntry(Property property){} // public void setToEntityNameEntry(Property property){} @@ -137,6 +170,75 @@ public class CommonProxy { */ public void playMovingSound(Entity entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){} + /** + * Plays a continuous spell sound which moves with the given entity. + * + * @param entity The source of the sound + * @param spell The spell this sound is associated with + * @param start The starting SoundEvent to play + * @param loop The main looped SoundEvent to play + * @param end The ending SoundEvent to play + * @param category The SoundCategory to use + * @param volume Volume relative to 1 + * @param pitch Pitch relative to 1 + */ + public void playSpellSoundLoop(EntityLivingBase entity, Spell spell, SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, float pitch){} + + /** + * Plays a continuous spell sound which moves with the given entity. + * + * @param entity The source of the sound + * @param spell The spell this sound is associated with + * @param sounds An array of the sound events to play, which must have three elements in the order: start, loop, end + * @param category The SoundCategory to use + * @param volume Volume relative to 1 + * @param pitch Pitch relative to 1 + * @throws IllegalArgumentException if the given array contains less than 3 sound events + */ + public void playSpellSoundLoop(EntityLivingBase entity, Spell spell, SoundEvent[] sounds, SoundCategory category, float volume, float pitch){ + if(sounds.length < 3) throw new IllegalArgumentException("Tried to play a continuous spell sound using an array " + + "of sound events, but the given array contained less than 3 sound events!"); + playSpellSoundLoop(entity, spell, sounds[0], sounds[1], sounds[2], category, volume, pitch); + } + + /** + * Plays a continuous spell sound at the given position. + * @param world The world in which to play the sound + * @param x The x coordinate to play the sound at + * @param y The y coordinate to play the sound at + * @param z The z coordinate to play the sound at + * @param spell The spell this sound is associated with + * @param start The starting SoundEvent to play + * @param loop The main looped SoundEvent to play + * @param end The ending SoundEvent to play + * @param category The SoundCategory to use + * @param volume Volume relative to 1 + * @param pitch Pitch relative to 1 + * @param duration The duration of the sound, or -1 to link it to a dispenser at the given coordinates + */ + public void playSpellSoundLoop(World world, double x, double y, double z, Spell spell, SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, float pitch, int duration){} + + /** + * Plays a continuous spell sound at the given position. + * + * @param world The world in which to play the sound + * @param x The x coordinate to play the sound at + * @param y The y coordinate to play the sound at + * @param z The z coordinate to play the sound at + * @param spell The spell this sound is associated with + * @param sounds An array of the sound events to play, which must have three elements in the order: start, loop, end + * @param category The SoundCategory to use + * @param volume Volume relative to 1 + * @param pitch Pitch relative to 1 + * @param duration The duration of the sound, or -1 to link it to a dispenser at the given coordinates + * @throws IllegalArgumentException if the given array contains less than 3 sound events + */ + public void playSpellSoundLoop(World world, double x, double y, double z, Spell spell, SoundEvent[] sounds, SoundCategory category, float volume, float pitch, int duration){ + if(sounds.length < 3) throw new IllegalArgumentException("Tried to play a continuous spell sound using an array " + + "of sound events, but the given array contained less than 3 sound events!"); + playSpellSoundLoop(world, x, y, z, spell, sounds[0], sounds[1], sounds[2], category, volume, pitch, duration); + } + /** * Gets the client side world using Minecraft.getMinecraft().world. Only to be called client side! Returns * null on the server side. diff --git a/src/main/java/electroblob/wizardry/Settings.java b/src/main/java/electroblob/wizardry/Settings.java index c8bc5585..8692cc0b 100644 --- a/src/main/java/electroblob/wizardry/Settings.java +++ b/src/main/java/electroblob/wizardry/Settings.java @@ -1,13 +1,9 @@ package electroblob.wizardry; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - import electroblob.wizardry.packet.PacketSyncSettings; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.AllyDesignationSystem.FriendlyFire; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import net.minecraft.entity.EntityList; @@ -19,14 +15,18 @@ import net.minecraftforge.common.config.Configuration; import net.minecraftforge.common.config.Property; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.relauncher.Side; + +import java.util.*; +import java.util.regex.Pattern; /** * Singleton class which deals with everything related to wizardry's config file. To access individual settings, use * {@link Wizardry#settings}. Also stores a few string constants for easy access. - *

    - * As part of the 1.2 update and code overhaul, the way the config settings work in multiplayer has been tightened up. + *

    + * As part of the 2.1 update and code overhaul, the way the config settings work in multiplayer has been tightened up. * Importantly, there are three different types of config options: - *

    + *

    *

    0<0;pS0?>t5S0d8)tIPdjBg~!G9~{>MJFkCLgJP@bOekszTS! zm+zv@?0Chq1%H35via_o8!Fy)O~m_f=O)J5oVAS_2lGwBLVJR=D&?csc;>lyp5>4F zAi70c@SW%UXEi&IPCI!gv?-;){m%C5%nyFduHDcSzfx6PRJG$0=Zu4AJzO??RTFAi zy>w5K1oyQWrCa9fZ@*@spuPREsLTAT5sZ&w{yy3)_n%dD&Rac+oxYI_3=9mOu6{1- HoD!Mj1;c-4tq3g!1_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmPd2cwv= z;LIn>dKnm4UU|AWhD01bI{kKjNT^8r{;l8bo}clFu4;73;N^V8nlHe)!gb}b1P()q z#WopCiY!;ydmkPR|Ia4$xLM7G)2oO77(0)lqFc1`iKq39`Klf!nHs*WmtK~nSrzM5 z|2BBKi!VCDwUr+9kn|9=HOws*&MxEEH^#!Xdl}x?&S@`xXO?jEplFXYe z|1nPG%jX!qzg`}UtCQ~4?wowFQ>p&dF{QUQHq#Yf@5=D5;(W0qS1f&Up3%diqKjO= znzoi~+O)E`Vg6$MlSgdtT-_+<%vShWYYBs$<+KxCROxj$;cZ%v0bxuTOsddCj;sKh^4p;VO3mXP2w&$%{KYB52rEI9CtiWbV|-Ex8A_TAv&3ZC2>;$Z{V(_pVTLr+?o~I z*s;JhP)9t9OCT_H@prFZ)mv>mb(Xp@h^V+IaQ1)7@}6VA@Y|y=It%p*`Ok0YVm#$z zq}`gvWf8Eo{_LT|XyyHzR8BQ@b*>aTX%edWV96zp1yh{7-x_9_lLIg50TuE<%;Jm%;ldfq~$%I z%Ng(PD4FS!Cb>Q)WtvTss(S32RBiD)oh5IX?-h$kK3^-|wQL|o6|2m{%}E}a^0d20W3Oi-zaVqR5A-yh@auI__>|FlaP*|l8%@g-ZV7M)ln`nH#==c#Np8!N}piWOap&P;u&DWo&$nD4@8UGBCnLCcl& zY?moEO`S2p$SagHaL?w&&$3Du-KfxG2wG%qn%6L6Hg9>=A71IVPc}r~zkh>)fq}u( L)z4*}Q$iB}ZR}oB delta 1255 zcmcc1)yOqLtDcd8fq^+z>u@Op0|RG)M`SSr1Gg{;GcwGYBf-GHz+U3%>&pIsi;r7V zh2_0hHUk4opQnpsNW|fz({J~SgbEz14_#iJR(6Be`d9}OlM;uJp5n*0iQbDo3Ypsc zU>8_i&!E5W*ZK~Aq4-Y2i3tJ|GhC*)1n6}gA_MbIWE3^7?Fu zQwv`1zi<8i;ODEeD$CDL_-yaSWMEhN-*S!A)Myrlb^c-uYjRZ9NQv^z_X`x>Fy#T~ zqoz*5lZHiHTni2uxUht>PDyzf9xDE+pg67V`nK?01!cKe24;rU-3$jV_b;vaGFM4X zfSYCY#9IQKp+}hOpRuw^N)}7_a`6bd3mB++IOsa6IQm$zG#vA2UTlBw$kEF5@}=G% zCmlHDcIcroV_|@>(E7=@3{2%8&YG`lz9vQ8i{U`w8Ce&OS(5^sZB-Q=O%^a+RBpN` z!Rd3(=i|Zf+h zX!XRP8(F3Jm~j`)*S`KmtdUDpe&H+S5DB%9uVgu6Hl5!o ziJB3TzwC39C%`0 zIN`?3B`V5ZY?t0WZdtXWWSPXogLjx5Ipzr%zvaS#RJN*mRc-Sev8Kshy`eeDck0hiJ-^Ox+vLK@&A)Hg ziZCpDt`-@`-*I5^F43s8cgE4@^>^Pt SXl7twVDNPHb6Mw<&;$TM+byO5 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/earthquake.png b/src/main/resources/assets/ebwizardry/textures/spells/earthquake.png index 5cddf1e784ab979d9d62045ee5aa2892573d7252..fe034c510a9c9e93412699b5b6676099bf00c571 100644 GIT binary patch delta 2689 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 delta 2546 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 delta 1850 zcmca5^o?&qVEqF|0UaXzum7IDtfFw`)zD#-reQ;4(0y+ zhj<>Tb_fcoItt5sKIsg<|8W0j-=@xwCnXf!1Ua&f6wEAKmiXfKoXc0Ahs?cItt-E3 z+01#F@f#<3UA?({)xP}t?6vvpb@TruJ^3Tw&r$IGpZWQRzn0b1`!YOuV8Xazzv#|= zntT3Euf5|KBM?5N;j*CUmi=Y&f`Lnmmb!=>nHg>z_wV6D)j8q&_8)y)ef2sE zLtWM82XFVsJ!THSBU{M&o`IS5W-z~2ioZsq!b0T~J|?CW9PjvSAHKZBR{yWs{oU93 zvavxi@^{|kyVm`_XZK}6RKV@j`#;|894KgS%z;lEJh>)A|tD>xc&+!YQG@i{p4V?wVHpM#9x@@-vH^&@XiIyNoEyF)v# zDP7M=UE?70qmN28{enO4R-YHp6nq~S@II|c(@`l<`SY)qRdY9bdC%Ij<(A=Bq8-C{h}aEO#J ziMx2o95&dr-s7Iok^_wk{SU}?HtpE3ao@o=Z?*(~4P?68FLXHIkn;oWJ3ZH=lvrDN zZcd5aRysdnV&IHRRnAY3&-uZaJ|{s%YPG@n`YAjTuOtFpV>qU$ygJUw(ezk@Q9wzR zd-Z|2$Hb=?C208<2FE7_mq$!jU-_lw?2gN4CpB%ZIimY}Li9Jmt>HSkerYZjnlzYI ztlaiZVV^F-aVfP%>Ef*}pTnoJ+k9?JoNXgsf2i+X!m;oPp;>3eWu^>Z#Gx^@!;v?`Ic3`9zMhi2`*6^+ zkfKwkrt4TNUFs$vwLW7>ebUooV%0shr=+6ayxN@OvAl10^XdO)N{#{x*T1;(d!NzO z=-R1Gfrx+V5%s2(=h$znJEyr5vzv@3HqE{k@NEaB5~{cpQCQ@W@APXU+B znug-CI=5*o5&j16piMi?i-LB|Z~QcwCn} z%~t(OCc3JZ_h#}Lw)fA=Ex$5vQs@Zlp|aJ#YE7dW*@L6`Hj@ZGO5O;jIhw zUBm0|$V_eUQm8(?{HN`;%BJ)~+&U?43KuRtNV*cXP{Y3^KhS9531%+YPl^9**}oaC zHD7bmZ1M)jq^nyis#*niN+c*Wd8M3SDPH_ZxZp?nKV`Sm#1bF95$aZc>I zg0r^i`!#iE>;EWAof8yfvr_VET>bco+-ojYxpf^9^;~RrN`{H4-h4Zc8lAP|D!=hj z+9vi-$Dz}D^OEjtSN7X+c`*0-1@r9i>+do zl7{!}cRM-5;mDB{Z(6#N)5R%R_Xp$ zzFqBiI1CM@m73JME^^6=E?d1o-S5qVMb2!;kDi?Oi*-%PqG*>S{aW@{Px2;(Ykv6C zd;aH>YoAqS?bBrB@MxImCvj`W1V4@3hTWGp9I<&=D=nAmaIm4#$G|8#mi=YX>w}#Q z6DvP&oxECl(&JYX&Th?Jz|CB;jHR!wDR73tR`txBlShK}O`n(ro~WOoqsuItm@>)4 zMb}VB%WGQC#KMoO#TPeUKC(Ve&T#cR|Aid zxowx*O6EmkwQF|IoW13)pC^xFq2awhPdT^04-MD;aPntv-2cjOzWl$L^5V&1bCvei zmhE2Pnjh8G@P`SanuB!a4^xZjj3PSR-KbH0X aXZl~cCRv`XA(?@Jfx*+&&t;ucLK6UUe{JOe diff --git a/src/main/resources/assets/ebwizardry/textures/spells/fire_resistance.png b/src/main/resources/assets/ebwizardry/textures/spells/fire_resistance.png index 5fd495a6d618548cf60c57312e0b59d561e420c7..76761a04d078ceb2f61f3305b020e2f699fa4424 100644 GIT binary patch delta 2364 zcmew?bXI7BR{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_#Kq2U zDSf`lIEsOR$B$`uRS-}FEjlVkLX1Wtz|43E0~TQF%a=E zIOy^*y4P@q!ZC?`847|IB7B!#WKo*R(xf;m!cIYIBFEJF1!2mUn3jtDo^kH?xzFeJ z7Qfs3e9qoK1?T4at+u{-^ZC8nqJRJY#%Hf@uX*}x5@UxXlg5KcJ4ShdO?%&6sqxpX zj%QGRz!Ri!HOJRwlc)zPPeF>d(uDf?D^uH_Jzx}IV(oGIS8Y6lt0FC8`kYjrGe$z1 z0^Ju3Uvyk#yTxHBz+CU?SF*!i`C)P!Q?WLuVnOQu^XKF&KCQdZytqfO>tS-mq((NT zM7zCnrYIg^+o+*ytTd&KlXuF?t)*qPD;!wP=%}h3c*oCgV0it&^cY_G8@6H}mM0sm z?-MMIS>`rh%GJ>6z~O)G4f;)77Cj;hb2W8^XQf^7jWk;EWopImkRy}oh2QPjcVOqP z)KiXb2aF|NfB*ToFwrA;TXmo8zKx->{5%r-S82Pp9{8@&Hgj65KpA^MiEQ2qrqCbJ zyjDzMMLJh|uS#UC3@nqY%a;s~f8M${_ua0I4Ia;|_dPR{d)w++nDaI9i1D$S3zO07wT0`8ol|X`0t!VPGH$us~`6=_q4Y?{Jnf)^tKPL z<*#!HxpV1MUohj~x$@Mn_Wts&Z9B5&%n4{SeX4c;q(|11lDfV^cl()97S*vx!<~+QqCj7%8aG{dh zdZ(-5YgAOsdoRw@yznL``Pn!1n-Y&>Y|5UlX12One^<8i-LZAjj`=f^zsuiy@@LCp z_ns~%$4}b154sz>1QkSBx(>vOdMt7H^}geU@cfizzf{=e{;3u2b`^1*Q9MIZsi|Xu z)(VZa7Ry3(ghae*eos6cGx3eG#2Cv^`p)s zOLLjm&PfxWy*Dih=Wc&~A z0cV+aJo7v*W6>TtYyGsJOM?P6@$m0YonMzk=JHi2{U~x|{Pd^TQ9#g# zwfMn4tDfSv)?E+Z%=W(%yW4qJ{leVK$5}nr-(ou~5T^2ZqqoR~Zo7sDJTix#_%FYB z-CsE{JvrXy=x3WhzT4glWnOuGb90sWy5+?c%am*T5b6_efr{(}0cVn%+&*Lp4LRLRN)xExp9nsaLTuWKqmop=qZx@}&Hu zUYPzpv8iwgqinN?;#t{y3|nos9Ouv#p0>#B{JN$y+d1WI9TRJ3PE3FIWHU{Rg>ecTlTB@u5{{6zs6S(f%hx!W#(b1Myy;tQLzVTwgul)*jwdrL0FDEyg|{N-bzT=k>yABl|y8jWpJs(-Ec z^5x>~{jI0jwqLq!f8w8WyX4=K7Dsb8w|q9PcyCgfEIBW(P{%sLSg~m4qjLw!Ctb}E zJS25$k?}L(dX3+GxA)&@{(Y_RNpka+{a*^*zTZD~F#g}X{5#ft;%rl-QeCEaZJnN# zZ_hrjcH%|m?Sge`OMfKwKDZ-ve6iTpKBM^ulC;(=*^uY7E3ql2(d^VLP41NjlevsH ze!SEF%%W&p@Avbnf4*_GR@=DA@9aH3|F>+j^YqQNDLrowFXrK?&wYAev;L;XbE`FZ z^e@%C6S=p4n#I4W*|E9Dk5sk444F}WsB7{ZhqS7}T1b z)su7m?)?`#nEYPg&O^hhiaCGV`7WDVxZHmrU|;jfyvNSeZ()Ax1DD>l>C-BTHy*yy z^!UM?WTm#1EMh?m^PIR3KCP>NQ11OyLec5NnG07Gl_HcH5|;$z3!l+@cuoAmqU7Tj z_u72>5kswN=XqjhD@hMbwn+jlVZy<+>}%Cc;_@VC1$k1kBy+N<-FJ0m{dO{xE;Y|E{v_J5@s zdIzLuxo!`wSJzpx;e}Cpbg5H|5aUa=5A5H=X3WSosH*%b#M-b@H2MBnRR%uUPJ`xK zS#z5X%sSA;&Mo()I-oQl;9$@Ti-m~+<_q6#3U=qnWnZb4H~Eclac}pl$d_fuW8I{c z{ii40?Yqe#!;;2w?!#F#sbF>$ts|4px|~#s-FJLh-VWS`r^jT8bY7!q;#==8{(n5(kK>Yv}KeqI&UpT0+B+s3&q0+TFGT@vVMoDk$N zfsG>|RLi4wL1pIeAWn@(D@FC!UTI&|t);cKfkmrQ(`iw??m`n^FR@Jm>6)FwkB@lD zSU;B3-+cbg+c|bUb6bDR{I_(q_TB04ci;c{@BaV#Bj-mnM^VqG+NjaIhHVJvIcQokXq}QykLqON8=@h78XSTry!l_ z6-mCAbuDIxZz)LKR8!x~aKP4E=bp8mK*o}s1`Y=%j!u_E4+GxDOs_W+7^5Cna-F}< z(x`T!K|o_|=7sAf#~;11i*@oi+0B1ryGGqyhxG1~>l{0$NI7TdXd0-x=r$^{M6pYF z98wfkG}#!@!9HJVLD@T{biF4t^mgx9cc@U5Q6QsW>w&MLUb9qY3qPsvR=sEQ;KL*4 zZ*N(4O=40!ut_EHwn|dwA+;~2w{I*{5Hj*8)lXiKZ}_`UKK16@?ux48#Xh|ApWN8z z>?1u_V)J4dDXGP#a*H3a^`xwx66A88ri*2?o zn>%^>r=F*=r}_>|V2VE+%`RK_E$2-blT(98LPtYU-Zb_2e`Y5++x@KFzCKP&yJmWE z-sg)eGppv;_1(InQ05W%-eXh6eD~|0U!SP|#5ntw^@`)V)7C_Je!EfG#PDdM)$(Jf zm()+&U}xq)}bYF$6BgFEB@_HL7BiC8@^vHsaDgUi+Zld2vnS}n?~`+V*8 z6Rpx4)l)PsL|x11ycmYx*&lX(955w+8AZhW)d zrN)<>&l6ZtJ>_(Jy}tmzq{&P<#rQ;trUzjO5wE!e!_FasSq|exTXNrlYBGwL2ni>Y;tHZ#?dwuBvCfc!)}H1ednC-Cw9+TrCzXAAz*=^hGHOBR$ueA zSxM`TJZVkbm8=+~>1t6v_1!v=`ly|Ac3U+IANZ>+r8dRfN81r+M{qa!LdxG0$b~j#$+DD`RSjnrF0;+rki~3%$v^eHnQ} zyj0C{Ua7^gt==oYxLWwD@!}mfypO7hjB&bkCXsxN$h3(o5QvL_`@7rJHz7MjG?2dxIW-vD-4uUH+z< zmXuPSx6-sD+f=q@v0fI5a58D|^}J)|(ZZrz*}vkx)Azmo8@6m0_nwiV8{lLT^xll= z(1GxPwe{>ZKaa8+y??u?;DN>t+bt{Pru`NbQ`b4P%B{nyB6QIMZ!K-RP=OZ?(KUya3#%a1y_FK|@+FlE`wca!V#8lsLZO^R}f%95BY z$NYM?N4SZxcJLfqQ@5?}9cMx7HT_>d)WwZRv8()dt${Jty|ASJ_i(%X)tK-fHGNqmxIZcXz5Pv3S={3)&O% zbZvS4=?hCU)4cWi__>nTJ^%5_N$En=gG#BjNA6sDU|jJ>}Qes?v zufF|j`F+QmzDdhpi`ZE>{(k*k@XtGy&DPT<)F<1AZ|m8#tC;t+czMx_{gGOwt?OAF z7v#Tedd;%L(2V%Pe_qo*de%D{32H+HJ7d4By#^K_@) z1p!=&CT$`SLT@G<*~Ze@(W$7AbFgcjSk&!Vk-L_)^WV2`lI%*FX*TnW#L8zH&yR6m zsadgmR{gHkA4Fg5{Q2?LH;V&rzc(dq^iZ1UAaU%D8~;4Ew~gx$aEdGoXwf}#X;+?=i=%vr-5 z#aXj`p;z9r4ny;sEg20=8m8$5vJ0Lwlqy#`m>h_|EB5eIbjr+meK+1-F0fgDbEhiL zf%)IBGir!t(&Eu hRQL7p_1OQ+J^HpQHr-gx#lXP8;OXk;vd$@?2>`1_YQF#g diff --git a/src/main/resources/assets/ebwizardry/textures/spells/fire_sigil.png b/src/main/resources/assets/ebwizardry/textures/spells/fire_sigil.png index 63b0993dd8d2ef496ae7d360fdb045b3ed5acff3..dc892b01984e7f9edb3aad1addc3bb783738a93e 100644 GIT binary patch delta 2066 zcmeAXSSm0*n2KEw9Usv`=Ts(rh z+_p-81sE9EH+i}^hD01bI=!|huvz%(#g*>`OwujWd#%x>1m z(wj4PZ{EGxxcL5M`*&|P#Q(j%@8ntQ;^O-@=PS=upZmRMQ&rW{kM%Nk2X1~jem>F5 zOHYWw;(9DgLebjuQ>I+_rCx9@F>OXMM;nu2;|`b2JbGe^BC7cUU5^-C1VclnDsb$0 ztKFGsaXl{b^vrW_Tw=;)KJ(ekYSVUiVM$GHW|I&}1c{s=Uj6ku<5sxmzgUwQ= zS*-K&=5kahL`CH$9BcZecS()qoX6rX4=%o!nK8jfjkBp?nLW=1i?vDhCXJdaHHsJv zmDBpPT9-&n|9wo`|4LIhV;t-4>+_x;+&e%0`>9}tHP!{9{QCAsCvH36c-qn8fbQ4K zbL|2v-0j`=P4N?y+{@Wm^u@wGre})O^i|1|q|R@TJ9X@RT8FoM+Ociw>k`BNdR~*C z#dttpZ0>`H&gL5mFRt$3sB9LGR;xE&|Buy(d9;A3Y*C0 zoQRr9i*ayqHzppt+Pc{l;CJsh(07*hS_nWHJlmGEin) zVza}i_j#0FV(j6{ng{8!=8iTeH{JCA6nJo=p(2Ok`mPRxbHVH8-}G6te|qP>f)_{G zG+6Ff|JV3#w(t05_GJaPyZnl@Vi-O-i(E*&sO?i9^7!dAsdv$T1$SGoTjtdmG0FOw z%+uKC#jEU}$TJ_?8SrBPhkV^_3!z!)5QMJf2l7b36XD zi>Z)QVsDT`V~fKj@e3A)jDND~ew|?wyL;>0{o;ak9JOjQq!ulhr@+>FL4)H<>jY+j z2%}>Ax5uYB@2lsI=lSDxEPGaq!~F>|Q$#yBd#+RE)jE96lZ%VFSI)lZa%~C|lhD^PLCy2do*f+L7BpOV+_GzS-Pyi$=^H!0u*~L* z;}u#Q^}n4-%gIMM^ZT00_Ufp7hL0SAMI3%xc#JsgzLcv?))dy1dLrP&a^&$m=i z+NaG;`rG*W#-0b7QT^+cUUGB#e{`Q9pU3cFD#rr z;l!Mf3a_o|SAH2B6fdaF`Fr+_hN+(Wt(KhnmD78a8nh|{H!Vx}`C{>g>A#vjj8V(IjUd2Jny)%Urzl= z&x-v$K8=bz5-|o3pFPct%i7!XwflaD)*^`yyQhZ*nLlO_cj5?WGSD&=RBW8s#p!9N z_RHz?$NJEK6BqIi-7SuPuyLFAj>3bxODt0lq~tIy^6Hpac&xI;QrqsqcHQ8}>p$ep z&Q!N)we~$OZ;I!QQ!TxJ%ahT$VFy>Petts%!y&tEXKuRh=e!xyXZtoj?b@OJg?1uF zejK5K7Y+H8Lk*G-$Vh&CVbr{#{jTr)BD|Fr2|xtDYI zA94Qi@nK|6?(TWJpU+M3|2=)dglEp`C9@}pAC+8j>IRDvH{V}}^cOR>ZJO@AqIHA!%9xs( zrl!B)OpT6P?ba)$X?Sb4TGO#bN z@Fs0bRh4RWJh$E{<|UI%Mb5l1U8rQT>gtZPi#J~+1^v=vsnTUSYn9mWLUNDlOO6l5 zb0e44Evnk0X*=62%zr&g!u|Kf3`?5lozUf8ye`cu!cWL_`kp`|ouF0xj<&L@zgO5Y pOp&aONuJPQ|LN#)+kf0vjuB4LEoGA#xEUB2JYD@<);T3K0RRDHz?uL6 delta 2040 zcmZ1~&?7KGt6r5sl|i-jfwwyY0|RG)M`SSr1Gg{;GcwGYBf-GHz+U3%>&kwgM?lb! z`c=kI?Ry^IS))c%nB|zw?h~13=EFHImeXlwD7n>_at|XT^v^yuUy$#Vs-XeIaf)~T1k%uYc03!sW0!aoW$gt z#Pg{~_;wZ}d(`Py$GKz5`?P<`Fnnd=)q3+Lt2Ib$Pt>t9dk>`=U#bv!5gy{g#-?~7 zeXnKvti@N2+ba9stu?&;-j41P^JWzH zY^_djQu`J2;mmt+Mn!M6(vP3st2tK4E_z*3^R<>QSMp2?Yxsvb%G13HbtkV3y0u@@ zCLlx5VwdW{J+78c%}2SN@)QP+1^IaT*y?))V%k{&g|bDObL(Im3>mnu`uXgDO~>H zJkuPl11Fn4)Or4l4*X$|@!;M0{YOr>PoG%);Z~!*FvIM6<5^4Z|7fw#$y4&|acpIZ zTIrxL;nRa3V)Ik)YdKx;SbONv&AT~P2J_j~@}HN~>phCOSg6_JEf~|+;;mRC!kON6 z!LH0Uy5Htx)5_`;RO2)+uQ=vLF6r;Jz50FkPq5os>bXtm z?h$fo5s(t${lr(rbFS6k9k+er>G|^x=re!sOEb)RqPE)l_GGinkhP{)uiuRA^_+cW zlELlUIb|>8>Z7eZ&i0+(+S!|=oONWD&Bm7HVl0hUuUv^Rnz`lIud3{fj13`LsZ7_N zboQF!rHcs(y|b(`uLzPf8|zapHD&YNv|!|L|rYvL`v`;2^?`2Gd` ze3%@mRNeoT{n>{TN8bKX57DzY!MuWR$LYQ2*-~QHG_5fB`)~S<`sxbJ^M3aZe7071 z_$9yPR{%%;ME05m=Y#|LWdzT1c{B*C^0!DVYRb@AaL>iX<px_Z8*ecDo%sHDOVx-fE=;rkk(L z85YMqbl=R+)RwuXXL;8@{s%LTzCSjVxnNCYg|Pmcc}!^$H+`8oT$G*&8nlON9Lav} zvEtGLZPR(j*uymnwNKlIGBsBDbC}pE+i5e&Sc)g}DhPBq@oLX7=h`^V4rOXKN}Z6uwCJ(YU26qA{!B z=oDksMgwopmhf-3M<)HgR`}$CP@DMXB}JK1dv~z$bg(NdJoJIVO|7TA&-QrvG5f>6 z{uU=Q-K;mRdd418=5#SHlsiPT^HOuuwPW@Fdh!Gm&q(i|_U^H^q#TEHt>Q~gQz`E^ z+*eivJl8%u?}FHYhspXEEZ?!WFgz^%w9|&gH^z8j!be_72L~4p!A;BV7(Y+GmM_PZ zIE~5ax^(dj`#j!!`RJ4BSuNXIj4TA&SWZn)h}+I~Xt{8~kMpZv=G4#f&DUAh;4ouh zh}xvWdPBF+e=lND!zTPbzl z@2@@-(QA8mb)?n5m-~w5oP7F`b=zC1qdR8SKTiqNT)5!Wsm$K1zAL90$7puFFnqYL za(cz<@UfgEYmGeHn-7lv;!Q%S=FWZAF%PyT? zaWtav!R&-Xv)bz%|PWQ=GosC8zRtPw*W6*44{)a5=N@V0duXxN~2ALzSW3 zQ_0+UACIqXK9J84o^rK*5r5>~-;NU+MB^^S#D??VTa^^C4B_ee+BW&^R?2MVa;`7cve$#Hr5!6%n zgXQ|12^)7POcmg9v|aE2a=F^|uYxOn8NJH!-}Lfr$yArKD@8KXpP2fEDDN-)$I1JX z$Ft-1>Y`I;m6s?#s`it4>v8kBsOXoKCrjt-o$>UXwG^A#(&y_W=f3r1hK{J? P0|SGntDnm{r-UW|hpot~ diff --git a/src/main/resources/assets/ebwizardry/textures/spells/firebomb.png b/src/main/resources/assets/ebwizardry/textures/spells/firebomb.png index bad4d72863c2f303302f0da86d77c701fbcbede4..2d7e475d3948e8a492f4a6d9e327cfee49f23aac 100644 GIT binary patch delta 2015 zcmcb_|CxV+Ry_j<{B+(8VsI9CL>4nJa0`PlBg3pY5)2Fs>?NMQuI!IE<%Ahz!(S+~ zFfgz;c)B=-L>xXkJ-a6~T=aN-_Wa^^*>dIYEI!TJ#uKnWlSLrMbEyJv7N^;@O94x> zx)!N%?GqC2zBuCryXTkg^VigtF1fMDZKa#Srz!Og+`7yX8WY@H6HlEnIDEk1yW#iJ zb8&SR&+pAlbhCftSN3jS`uxq`>i=H9^?&cSnmX5@pY~?r3w~dld;G#ZC1nPNDz;jN zWvMZ@qFchPMYoCtvWB{dGWvYk$DnlOe`jY}kK^Kamje=;Zp!rQdGtg+U$|3p*RM~? z3=DEJ9)5hKS??ga=4b}Tp+=5|BqfEfdQBY-p&=|=1vx@}n;7THbqhC%xgT(8OLDmWOmLgsAFr-@>7R*GJX@*~HpcL` zFtN!mTr;hU)sQbtl+{J~mfKb<=KY;})|av$WnnB_5W3*?=?%}Os?5JB*}nf!qd%{) z_1qNC>?V1iHr@BFt(>XbR^NFYrDi=rM2XE=%tvI>+x#iVnO9Wig%pMqDz6V_GQOnA zU^S;f_VwwS>I2LV?(I1Lr+&%#+QJAM(P<_J)}`yz*QqVI8!YAW@ya8nKCPK0#XA#xihFRkd;Ru; zyW!VNqlJ!b+IinVghMoxC*i*|bDzfyW`|3LZ+@=fKi+bBbMP7~IkkJ&X4W#Sv0irP z&Suu)GW+}X(-U(a3S_4rYC58#XC}E!MA!Y(p`Trfi3fO{cBhp*>z9*GHc(RJcB{x< zeE!$;df7UQ2Nyzl3hnmQB-VcXx1RG`>)IRVjK6$~Nxu5#f?v7X!Jaa4fqU~q_I*lm zSRE+E64SXQ!HGdhLQtkL;)_XMi>^N#%Tt3~IVr0no!>&d;-w=P|NtKvb5w7qwX zgZ{x&t{;9q)tlrvXAQTneA64pA1~FlmiT&nzhRsr(@-yvdW%#3e6RNN?_B*ldWFAU zicER1J3ivjdGXkUoAYl~)ckakn`1h2srW69b!Za&J=d;7fQDo@-Wx;SoZE@5&^R`V6>kl2@CM_kq^kATky8kgzqm>PtEe|q> zrA?_9ZQb5(8zsB6c=_qRuc{3HA{%$lYvyX|a;(oj`pSagm_ox=vF-%kDIq&E565^! zbo>+$UwHAr{%*ci6AV6F(tVh8bb_-+7!Rx9Gdp(I1*-x?6%Ew7?1haL0#&;WBNPH$ zT{KpyI%uqZ#5m81@8IS{jo8-JstdaU99MJ|JPvEz)S&N_pwhFqrR;U;@3#!o&VI10 zyU8sac$lkR?MiO@suoF^1tE(*Y1!=JRSTNVAaO=?(Fegz8p_?-CGHyzZ0({3{#ybmbnD1_% z(yKj*A;&sQCeml|q$s!8vnn=@uZ`q-ogF9t+P1DTZt>pL`u1&%EARGYcf1Q(%~+UU dU$FdkJ;UMtpzxSa52k~va!*%3mvv4FO#r3$n-c&4 delta 1982 zcmey&e~EvBR{bP~$qbtBlLAjMFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*KI9YfY zS^WDvEEpKr<2_v*Ln00zou1tj8ZLUgK6`%gbGw<=#y$&eZZWboDXv}nz*uQ%Q1Ze6 zX#s)NnWCm)vjv2ETyrm-U^ji(?X{w=p>NxiAn93Qa)I@3?IE{3G(#n?DDkzg~2#AG}&K zaY^GejtHG_riBd)y8?o|Z#GHrukK=6q?o&SofWfw%f;(?{6|?B0~fe1_%6L6seF$9 zyG|!@nYtY(_LR(V)ivDa*Q&eyK&)Zvy!B_k>IU0(a4RAB8VKMGx$P$3Ys-sOnvM4_i2>JImvpK4hcFhg`JLrq=S)G3X7*gtC3yj6T* z$1=C_;ZpsOpDyk#n>ZG*IE0D@8XT%%C}ndJ5Nx!VAmq{U>DLDLO8YzWH|YFIIk0qc zy@BegDW9E!nQu(ld^x-|e{HGYy=T!JEsUXE*OF}c`8g7j*nA}Rt`}gH;=Lo)c=Th# z$$3dqEct3YdpYB`7rU+DIjns)UGx9JssB2e3&LgW1VV*EpZc)=3f;I$g7Im+!GmrA zK}9~FPL9t>r*wlB9(Ax`nlD+ql zi&fKf`s2-b*qkConQ#0*)}a2Vh@qppjX8dmllY#=O>XjX+Gi7Q&$9ISocQ!wUSCdL z`pa#`e=@#Rmeonj;@a>mKQ|}e;=BoWY~{m{n*zoU*w3w#oclAGLE`Z#SJC?%$IZfS ze9-P^HB7B{yjbKf)NwGpd_Lm?kMEXjW}Nmj^>V7V_lnEENIm=QHe*IU>)UqzV^gcc zS?An*JyAr%=K}YugdPqz7XJl`HPWVsCcoBEI&|!YOx#Vo?eA&|PW$x9wtTbnyI6WV ze|i1_hx-nV)_&V3iOwjIPqBWu{PpQ2z1?MR%y7ft@+Pr+76~0vA9_D43VTjCo0jRR`q8$3 z2}{X4^PEU&F&}XrFNb$){rXC@z2DDawK&euZa-_`d;JYBFG$XdV%o$0KTlxR?kU&X zY|l-b`?yB$y-=Lm4epS7h3VQ8e3ol;K78ub^5r0x=i)D+yh|QbU%&O>Tx98STmO_3 zbDLJ@A37Ah@O@01Z$9tGSF0*@ zerHS1+R=aZd32@P)P?xCRYP(d-kNwdxO z@y7O3Q|kHMFH4H?Z#%?kVX=5}Y~+s<_1vs{Thk-%UFPC^k$G-|esV-@{o1=4`zr!h zv~0T~F@>|pp@%UvB<3_vz#5J7wyR?P$Ub43v0r9hm8Ekr^O}mSTk}#X{k8Y!?D1Ns zvS*5M%{NEx*bm<}C@yz8zDw~|JzrzTYCdIQ;{^>$D>Op0H5pf1x77CU%FvT%%Wmy< zzEE#$d3c^9qw*S$2&;CU@5gfPetV`JxNWWW#{+sh*d@Z)9S&E^Fl2Q<)Co6jn{+_6 zmED?0)8DhhdsZ5M-!t9i?X7IeQyv$T-MC=;`s(usGpkn>~erxfMG^% zge?0336>4lk_6W@CWf-DIo&#=m923FhbDJzGh1kVhh)XGT_3)0QfxN}F%xl_@!y1p zQM9#-qtS5TKc6!VEt7SQB{VvS3MP8!GCFxq6_Qv|h?V)n)@ zPzexKG;aP~csb$G^6@yT-7wYdkI3Qxv`ZV9Q-qhILQ5 z7S>pZr5@SYR-ewoZL_iH5{nSS&78iH$0{K#<{p-6CNk9zWz`Ajc^Ufk+Ug`RWfu77&0C;er~;>pY6R10ipua)=7%H6Y1&MIulx=P(5 z!?yQpJTBdy|NPs^l^=OxcC5>Z5n@lcF5m7pC(|P6^oqqZcgSurzjy3#`t=J-;;wBy zk-g>nx97(V6t-S2G(TuUfZ8c^xx&N?otc`0|SGntDnm{r-UW|^~Zui diff --git a/src/main/resources/assets/ebwizardry/textures/spells/firestorm.png b/src/main/resources/assets/ebwizardry/textures/spells/firestorm.png index 161cf1444cf9c895bdce7a452b319680ae9098a0..faffc5c9bfc131c364ea755ab3835ae67da35922 100644 GIT binary patch delta 2297 zcmew*)GahYtNt6qS%%-e`Ub2F3=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgf_PB|fU z;q35hfeZ{BGdx`!Ln00zot~K!dsXmw{qwx{`>wvXyq9#mOhMCgR_g|rHB2j4=x$k} zq>`g6uxgWssP5Vf`>9GQA)HIR)~@op(0X*CXY>M37M7Lu3qk@GePKS*xp8&f;^&ty-dSzD-}v+OGm@pxMLi$>-=WhW96aCN**$J98-v8G z9)=A4h>|Cwwe3nWs#~m_Ze1wZG2v>$&kHj*8t6Ry5YnTf&~q@ntBPgm2?e7CYeePP z_8HAsRbir2l>T#PN@RUwvhvi+3=FT&ZF*@da@kzVLTN{v+Ts>H;cKY})^O_bPVmhB zGikzk?y}j3e6<#NNW5y^bS*^p=tP08MJu%oj6Bu)symuWwI^>@vSYpwx51*uWwHUQ zwvd#MV*dq^L#$^H{SGvrcsgt3(P?{An)i!0O?TWL%*j{0%=Pt( znaY<9Z1HW!+^%G=Ka|mW%st;#Xu&tz=D+Ta_pXOzt2L^Yq=-1?Tr@Y7K47!|cHN4Y z_K>p)g$J4Jm)sQF)wp!og}?^Y@P_)!>n7}f=l=dz!-h8rJu=R-xi_raDZcfU(U*6& zN9u2N-~6r@vwh~9so59yz8AhZL8x_hk)`Fsi!+)ZA2#f^3ib(aHg>U)d%TP(%v9Cz zbg7lFVXp6nXEUn}a$Mhbs%yv^6za0CzNp~$^yJ+tbB3k%Uj+E2S1dXt8@z&jTfq4P zUG?qe7x(sOp1nnAj@5~iQreT*;@_A=RB>xWUuZPg zVehDV+hMJ;x9W7YbIa5CE=IEJ&vi)GU8dD_%5mWr!z=&3+4zdzJy6+QbM0A6g;Pf0 z1j8A#n~KlOP*u`#e{n8rnoXJUx#-_3_ivk??En67eeT%}Pd>^|-u)^mC5d69;?5#o zhIgN?wjAEOKxWnD(q%Tj5sh!AbQxSHG`zXw~EmipV zf^#b*JGIRdqSQXl)<1V+lKEYavQS~}@X~~BW=2L@70n9!@3qyj-`e-v)asHT_qi2z z#tg^ZY}mZ)-rZC?c7U&kWyU_G+2u3(n0k6zFHe{i>UY-r+G3xM?|bSElD+R13I7Z| zd&Rf^M%00b{mvhCJJ#=O6t=(ZSiSkeyEDuSjxN~BU1YygQt*Sjqq>aH*~(eBVrNa; zGI3Yg|L`tiyvdip=H0P&yKuh z$?xFB`I6z$^=%5_xeLsAo^sf@CyV6V$&abO^>beAk)r~CfAKNA>0YNc?{3%u(HbWu zk)+1Ue8(E^8~zR8pZckWVJkzmNRxTv^708;Ot)E5XG*-h*`95G=+~!GkD4}}t2zHq z*8B7wo2JvsY8ECH!t`a|gHl zYIk{J-AgNmruuzN63^DezY-SRbMk}m?o>rPiMH+;YKIShX6RrpV{~bs;a=^b!|JYC zqPfh-;^>#+X#ds!A7vLxDOCIxZQ8qjQIOcVo#FLoYrea-6!G+#&9r|N-w1|z4F z-H&g{GIK(TcRzGk@#FgLLr?i_TyGzqJ#nq=jIA?@VhuKj&T%!BIv4W3HU9Wd{q=KC zO*A|tY$~R~EPSx^;ID^wk1U$`VL{3{;l?DMcCW6Df&qR^t2u)*PbgTJHb>R>e!7soU|;gjdb`6R(8#96i(P(BK%D>6X-55qid~AY9{8 zd(NuTg;oZweN3yI`zJ=<^UC`Bb+b%({15J_%C4*aUY^2!dd6kNG@Tog3w$r^p5J0^ zX7u4#nU|nRofyMX1DT^QSf`$Pw}4;X|ap>{QN_n zYAgGCghiNFWGwsTy<(++x=;vT4|nSiZi8*o_bN)Pk6K+xmE*n9m!xE%arDE(`-vwD zeIJLnTzRS}Yb|<@v7^@4;EAE-iir>7)-36Lx=W!BvSwOteU#kA&{5B{JOm9%gt>#Y4+PwIC`M*j8X`*NUha@XXjz|Mp7^_h~ixDx?kg%0_0zfU zY!rO?Ht~;Z#s3+P7F&skUOA#-u{r-vrE8F%?d0%fyvL3uA9B#pNL;DC=0v8RUAV{H zQd_r7>rE-l2bHZk+gqO`85GYCJ8mSwDZo;!%d)p1L;j8BsvGu<$%{T5IdZw+<M1!#zv z1+G1EQvU0NS#6DRNAD^AFlY!|`(a9_zCh9$*|UDWIdy4D%Yn>PT5>a1mAf?%5SdkQT zeZIy1Peqqxj=O1RPJ;r3Kk z4|U@=`eByYf;ARQ?%Dy|qFW_wc$@-b%G_=+?us&&kzQHDRB-A;<+@;nYw5i6zyIRb Yp8T|O`HN5<1_lNOPgg&ebxsLQ02z`ya{vGU delta 2409 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 DT+&}t diff --git a/src/main/resources/assets/ebwizardry/textures/spells/glide.png b/src/main/resources/assets/ebwizardry/textures/spells/glide.png index d4890ccb220f1a9310f9b0110ccc1cfef364e1b1..57f6b99451c828d140a06773a2d9c9d23a924908 100644 GIT binary patch delta 2381 zcmaDNa8GE0R{ej5bqqW&%N;f`FfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#xOfDu z4JK?{_?Ur##P9`9tG>T`>z<{cWL=f~e@!EuvFBy05g=tHlU8dPSXRb?9)Fn&hFl zFD+O9+r8`e=FYs_K6CC}UoZElxyFw_{#k#&eBb^b?{pbE1sFKWT{Wgwe^)Q~{&aN} zzrxb(UMX+)PI+KAIrKbZNK1m2W^A&k`l)04PjLo5ZTKAcur8#6&*S#8N8JVYCZGHL zHt>1v);}AyJ-J&J=sv4oZo6#5dtp{h)l1xAL33FYS8Y;o4AhF8ye(GPLu=}z=w_(} z273csyiOL>Px&}gC(E*^CBeD>*uKklJKne{vK-nPHd*k;DN%=yKUWzsPxNRhKesHP z;duVFnK2t|p6}(^a`exir@>dxE^!GI$+tYt?l}C%f0*xb!0=KL5G0)7omaV~< zG0V-{o11CI?Aedo7An?#c(a*9@y6#v+zfhq1vV;*L$VSCTNRz zq#8wRJNxL8P?rFQt0RY_ju^ATqD=tjXeB)ex1~kC-Ut4MgRL`*X(_%RxtPU z)6a7(>gL$XMn6*j&gC$r+94)5|FD6_ne)P(Zadel?VXf4X~ukY37(?Lq(j<`N-P`O z*qjb3e7{pF?%UhT@nGKW_i8eH#%6YW4i++L&z<={9$o6~H#RnJU!-y7%sHhNg}J9co?5+r z(c9bYxwj*hy?k)Kd2vc%;l!IRiS{O{SXg*y%~g}@H@3Cz-cqlVbNY~xZ_a6_TiZULDLrIz zRw`s=YSGJguZrsK-sMot$jv=^p_HK{_W7}eiu=AF5&rY&=krc=p(RC@BJ=wvO<`eX z%)7a%wZi7y^7L~F)4b*hW=2K?EvlHKv?I@*V@;9pE}rmp)&Aw*O?T*7U%Yqi*s9Rg zD^{;ppL#awrdbe2P<<=Y=a(jRzKd&*axKX;GPLYeRh>5FM~$71=F8pdUCPuBwEkt? z5xxF{gX#MC+#SENBKOUaxBDvc(WPm>yxo~QhnR}FxkaW=>o|XY@|^k06=l-CzPj4O z!~gmD^*Cp*&eYpF_a~`aGv9RC*kvCh!PL{+tGF)B>ia$(YyP^49N+KM*I94o=9aOj znzGZSY0~-jG>Mv-K1DxX1kS5_WBBgYzPaXnG7fT51yO&dqY+^{WeaLydVp{M5K*HY-sfSNiJv<6nMn^qo9;evMOn zxVZ9c^Uwb-F6NtjYa4szs!ooCnwolb-LxtNVZY`0}#p)2pVvZ4o>t!oM<1IG57l zqV%K2F6`U6OIMaK7JR$p)&KX;DlY?p1$H8f*6y5HV9}$*GWYZ}K{K8zYb%d*BZ*mV z^@{V4Z_{zJ|K0QGkH;jWwXqm^vDT2l$poC8xgPHP5$in^vvoKl}dsrF-{odAV2b zZeH{(tt9sOpP!%aDK494-t~xMf^++UsMJ27SHwveKS4DF>S8{pP>; zt4gl!0b|(On3F%d#eaV96h3k&@m$?M%eT3?cPek^?kRo3vHtD-e*OvD-Ubw`Y{{JE zar%(X)H%gU#qxT zPNZ)3@$oDAbVXAt$xv?Jdpi-u8#|NPXJ23c{Lj(uoZFjN=T8ygW<8T6xH{yJneX`> zxsgkPSI#=T!cEh=vuXCeOe<%spBH=H#@TMZdc4Mmr+;ji|NgD{d@XvVG0(dj z+j^Vx_a6Omgr(o^heF!M7nT80QAxo%?>59~Jxw`c8WVSV>AD3DVL|)L7981G{9Hq< zyQHM-(RGt)re;D0JiDx{HK%&b*|A|fW8qxyV79$FlYC~n zC~NKi`Bkpzph8>Xgp(;JmRy#xuAAeu(7|ka^6L{E^~#42_w@A@rImMRDoL z?cuBU{N1@=$Cf86Q=`4=YSJ%+dT$G6IgxART5lhJEP47qNa@t&!t~-5HXlOSf>ya5-}v8HHeR@p z^?5*V?d{wB$BjdeZ=BL|J|)||=!mIuRis<()e61UJ%y#mcOQEidgOaNi)!J+#gfa@ R7#J8BJYD@<);T3K0RT?Hkum@P delta 2129 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 D2bJQt diff --git a/src/main/resources/assets/ebwizardry/textures/spells/group_heal.png b/src/main/resources/assets/ebwizardry/textures/spells/group_heal.png index 3c99c0335bd27eac9ad2618f388027af966fec9f..0ce1f0ee5331340d1a8524bd843d1b8c8b2ebb4c 100644 GIT binary patch delta 2460 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 delta 2429 zcmZ1@+$TIit9}&&1H=D!*DfDrU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifGKz_C zD8+j;n=mkNN_)CEhD01bI^DBh_Ij=RdD*PG&(&w=%}%+zMD5fk1?!?D4ub^!Ii(FX zjWrW$dKu!5cjxpla0)3f=2-Tr-sDpC5>qj|sxsSl&%64%VP>$H8_tmP)%3RQ!Tf%mS+^208<#qGZkXbb z-6-oenCh=zzHsG6l#*+6n7>?kPUq4CVF?pIUn~D6X>axDS@w0$MVyP* zwZ7I2TRrRT-&~)GMalK-iL5#GA1@Xko6nT<)pWmoVL?grG^YFEU#!G3=OkxO2zqc! zNUA`maVbmV`VBslU%I?@iU4ym>;&w~j#fji;QC)ju{?V%k={ zdOG8_>ZZ>=0xVL&S9z+<7B4)%MQ_6v2TqAEw>&N`NICrVue6R@`;}B*!L}Dwr)J-; zYd*jqa4KQ9(A@jakKML^{%`vH2_jhqlG{gVmhYxQ(xGA(y`qsK7ZzHcX z9^1&W_JDH-n|GspMoMjCe)g}|jH?U<>iZ<$zEkYnutv9OYc@}L{h>EsjIHVpym_K$ zU7eekUpxE$|LgJ%S3ff}eqOR}nn6q?zd$Ho<)ICWUv7!{wYXuG&W9TAwYr-$5-kco z%1Xyi&xyZ(__L_v|MeH9bzAT9E&AuK!?Sp8_LuE(kGKE-=Kb%>!}lvbN$nBmv6!~x zDVL3OeU4Ytv}d>ev0Z#>xz@q>)z-+ExC@0ge-5P2T))BPY)10r-np+^`2Trm-&nS} zPT00a`t)n%Cfh$3r_0p+;MVh(yPRcNvdeC!XXB$vhWmnBY&`d`-57fK-ZuvA`5*7T z-{)sm@3Z^;!!R?){f8fYnlnv1K72~L`Z+QECV{ZGIJY(tqoQYCX zCUxvua<0fHu=#5fke&Y*&VHG6?SaF+oIIm**+~6aVK9qvzt8Gc~|418Ek7= z=Q{G=FP+ePBt_v9d&tf02EMbc=05nT`{$qD-r4rbzrNaU3d{ZwCeW%cQJ^|c_vMeS zZDwy`Z#zmlUwD@ss=TCr5=(P_;v(a&O%4{hQ-r2udRl;68yXP7u7vk+^UVrM-hx?j`48?eRnNEK$tbRS? zi_l7*yW#g!Yre-{+`M~=tKU4Gi*M~7diumkJ-ghZQhSa0Rdx8<{ryH9Hoa?te>E<+ z{7vvD%l`e{o4<+8jpNtUX<=B&a!W5jtDZe;%k4B%OV_Bbl$i$AUnI90gs7!&?U~_| zCeoTDrRK7_D>Y`qleUTMr$Zb6+&b`fd;HU0`8xUCSCfB#i(kBlF}0>G$7s^kE~VH> z@iiV>XKl2yUc%u#m4mWMmnd$eu>f?z`6O8;h z`{fm;Iw)Q|b;yL5-~MmD*4qgxriGJ&uC=j!G&=C`U@}{7@2coMUmx#JHMyh4@4V)m z-t_YSj9pyYcRSksY}h3zQptEyCYfiMAWOEc4`0yji25kw{V`1}D@FURA1pGu-$0TKGV#QZB`MuxeTLM|4ioYDxkCjm>>W6V=i@gHYcKrINX2oZ_ro8++gW3ugA8UGV*yp2CUAEl=M}(wTF~ zg!TCMd&}2pvzgcbn>6|SKjDXLE{Q&e=Wm}aa3d-)T55f{XztA)cUNmn3>K60Tiv`R zy5`?W#lvfTc_wvttA@wr96ElSd(xhVPf`wDJ8RzgY0j;(nNP*~j~T9Bl(K2finnHA zyPNO6YTEXpI(EypKtFcH1G({wPYL;4El91NZxt!%tNbl~uj{U^NWJ=`mI?aOE4F&? z@Y(V67Te>;mf5qJ`}p2nyf9%+(3Z6)K8r@}R4Hr;654-t(cRlFQMz*yI`)@MzIM)< z<*#hZw-cMa?_6UGlo3)hJZ+G???i|2;jrJGjmsG(OSCCZpS)Q0?K6L-!s z(Jhdjt+MvSC8q65H8;;uJHJt9`n&pT-#@yqPhR_%)#?W0ZvIpkDczZKf;EZTG$!~q-!5|S4vRdTGclRVc}|qZRRLAaOqt8?qi!^+ zb&8#MZ2jfiJ;jLk54W>DaqW}5cc@ow%V*2ee;79;8O<~7%}Pr=nlb(Pas_RvXQ!p! zM%CZhZ~yd5j$_aPC9TNRwrck8J2#a#FSxCKQu@-R3E>Nx7#2r~td?B1u48hKk^YH8 z$(uqCJxXeneUn(t+?3b;uxk3lsSlpoChWHJ@@g^ih%PQLI9#lfdiTN2re&EwUOg~g zrfz&|-?1pu3Nsyb<7?~V)V-(em|lM3Ld$Xagzxc*^;O?2Q}-&Z)M`n+ykgeJ$C|Bz z5B4x@czj0ky7HnM3NEgJjRL&O7?bBQoDtLXv*JA(v&T!uJo^;lw6OI%f7ZexElq)LxAnhlAM_pU0Z{LrGcJ}ud@BL-myg^Aj z!Ae)-^>g7%mo+WshW~jo?FoN7XJ*ud=d7-Ak1Y6>F$!EUHQ`{(j-9mR$-}?StK5`a z{I<;a^y5SEw8W0Q+cL7gGu>FzpC4cIcHgnZ?#tJFYLkC!CNuYVNp#t_&%qx`-Tuse zf0N*n2KEw9Usv`=oN|KZ z94ohN-pathvB%TJF(l&f(dp4Wv7xfZ>a*AG{eJVg)$=oJjpvrlc-cDbnpogYk=BeB zhk(UuQum*<9uZejjPmX2T%XhNOEob>c7`*!NzweNrT|NkHTXy5J6ZT}x{VtBP$-o9<)sviOj z2V%4t6N=9!tAz^Oq%;+pvtwhMR5ws~?Gu(dcaxn(b5Sj;QLd`zM7+byZ` zysvt{&o#!HE)(A^&%{u_qwvzRlbe|@1W9NzG%~gXaV&N4TI1EK!KKeA&=A3{)WbMe z>5@qD7ps&NU%q}kw8lZ|?Dp?JryJ_&|GOEpx#HI!gF~A(^?S8W6nbd!z=A`aJ&*C_ z69G%{htDRiE~`tcc?;>6#)Gx^|*jn1gnU;S7yK9E}r%mM|?g zbW(is^lMpX<8u9;lv!S!+j>`o81^-5Or2mk{nG^nrRR&@$}F82=(5lyHD$`FWr8Ui zdoIU2KZ#lM&v8S}lGjSbdaGg_pK&j!H+5nN`gr5!!CoE?&CN-{T!}Y1CMV_3RfvmT zdL^D&`9!Xy^O9MoPH@QT?OxX zMfDuQtxwpqDn5VqIId=H#C2=JJX_|4^`dM#ttXyNY!%8BNpYQW`r_QV$-mcbzmQx0 za;vRdxsO6qhyRF_eJB6cR~v3jtNE<4`?%TXQxgyCTz@`M zC~fxgpO<>eKYm;0JE!Wo#knIEy6e5~y$-syx&5fHx?Xn|9Skc`Nv$n`lz^ve<$buDQb_K@#z4wy#hzI&8O$?KkwW-UsO@p$>Dh; zXJM`V=IxJDzDV!A*mfz%!@Ds=L-XUI34W_425l<;zV%MwVLKNI#n$?V@{VU7I=ff= z_?BI1+Pd*^p!QLcm&DgvLBB{t-^oMSzGtipEB zPS!IA6n54$rpNz~Zr}Gm`QN?`CpLc5`FmJdCMxUGpVR6eP6*0bGhm9_Tc%03Wb2lQIL=B7JDxMAt$w&6(g^39glwr(DUnagq*9(=8u@|ktXi3}r8 zFPR@DR&sFyLdRyMADY2mrK`2I&g&?HZqPjbs*Ht|Keqk7VR_KsPtN)3uNimjP9{yN zzmT==fvHr>TDG+}D_!=ne7qXdaPYIusXV#HgL>07`*M;}ikki{tP_iI-LITEC-+kB z*-x{pzZKt)k4t*A?5v7o)9y<4^=Ey8?d62bW|?U5YIy}oyinJAmMQ*OL-S)d>!C2t zjF>=XjuwXXw_QD3UzNO&+HrwfgR|Q@|G(7!iuxzvHs2rcPmKDs<@&?#_xDVGZ}(kl zYpm(L%yY({e=%LYtY7?~?fmCQ((ajSb(9TM;-;^-nzA*{z5JF%>mxUDjuUKbY?CAu zSzGsbzo|3{kCs`hpRjyZ`?T~QH{Vp|Bv$OX{pfo6{TBPVM*r^#8L6L~`gzXE^TmJv z*?#$c{ezg;hk9|b$hm8iA91v(elZt|Od zXT&R?b{;pZ>-swPcgA|N$_MtrJ~dfA^>)8l`a<5^s^!j~YkB&jdHGckG3 zUW4<$kKa!&I<4{f{rsaWb}fqacf+_RA6YZciZ!q$bX5X>FVkCXh89INU%_q6mg1pW zk9~a=KeP6TNbn?AmkEBed8X%cSxzb?wRGxcW4+`4a}J!n$r3lc{JzDh3(FM6{O2#c zos+U_Ij0Keiz!PsvSe}zhhJ;(6I{tK)k$R1IvwR4>(eC?UCqo_mM`o0%P{r)<@%{i zk2-{(>nrped-eYC62o237cRD&Wa7qdr`Bg!IH&ZG$uhg=k&_sJ~WR&0Im43A1-*)Nlm5^??S zr5WzT%z60ro<+voTqd5#E8E!FU(Va#uwm_)`c;7r608wIKHHsFZt7J%fB3k7xzr4m zWrc4fj(+6a6|8Q|dC7!(wbj!HjQ?M4Ua^mMe<+JWQi+6?{+IxNN$M(sQ4x(O- zK_PAC6V2+wCrsnjlD>X7j=#l$RWP%9YSL!Tz=m&ob#hz;UraIiAXwN^(k+qCo5*wD z`hoG@8>uzHnaa#xLl5u0zLxRBjh9jhFLcf|hj65(?hHJ|zkH^^j04NJZ|LDX>|?js zm~G3sE$`MO>U1}or-yHTdGuW>Pe=Fm$K4%v>q-SXN}o3Oi&y{U58rOpyF}}Y4FdxM NgQu&X%Q~loCII`eSls{s delta 2263 zcmZ24^iptwR{b%CgAD(bD!2Y)U|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFbars zvhr(~+A%P2lzF;1hD01bI{kEa%yG%1^`WKt`{OSg>-M@`J99$WJL24p8%GSi91JZO zANz{kQ(<`|u!oza$)M4q`w#QYquCE7ntRO~b#w&W1SZ!fXm5I)p>uPR>gieT=T}!R z`@L^|Xyl!VEheX~X=Y^T#l}9L_qq0YjcS~2tmz;5>8u;fetk2PdDl_R!0>CgB!jWA zSi5yo`Tlo_49YAVjfwe(kEq-#?(%hNFjQa>GKf-UmB^hSVZg>|@z~Jb?$Q17b1Q{~ zb@HpeGcedxUwL-7UV8F|)doQfOw1fh1-u%kM64C_6uQrZn53tO;eDk@-qfk4PMTqHMfo{hEs}$~fJVT_z<=now3d%Q;1vGs*2UMRmb};&YG`$exY%7 zOQU>Zsrp8~vkB$PEiCNaUpw$OJ5AMI;WqiCu=m(c7Iaq)@UT#art>F8Ny&1c!F zw(6onactJ+%@S)pjeFNzlhFA-^Y6LGJyDFy>SI!W{V=Kj`}B1A|0l~{7aZ%B2+6kC zzVG3MJA!u%7QCu9@tc?O`IM;7Jn_3JHz%a?PgLMLS?c%pgv`>g?i>6T8w^gr`^INj zkexdD+``Or|DT03#CUKg|7@G{v+L0r|9R=kT$SJd)(fO+_8v%=Xth|^zUrC>`|Vc! zHhqq>od5mD<@J>84-uiJZe1zpx@Oe+I|9vwG)GHa87 zjBVMJqQ$%iY`PZgKkK{N)xNl*Hm`B^y2DPJkKVlUFyg^Rn`*0O8 z-uf&sE%wC5^&F`e>o&zOo<8=2v96w3y{E9}N$+&OVzbhBc`+H=Rvgik&-?bXn$_;k zo6Fy2^k&VtzxR*wt-G2oD}AP^yijSh(T|$@KhcHZ(2Knch9`<+;zBQWl^5gT*?~BuZX_(jV;{7%6@Y928#=T-&pV~-wWEI?WC|oqsaBt zU!fn44x6K#xwvL+nq$IM7~8+&8q0&r55=bBrb+2m{A1r!`1Jl9o4Pp*_MgpI=58V* zWNYSLm)UuAxws^6+mFYwe;!V#C_nM;mDQqK4PO#t8xDT2oi$a9srhbB(0scSPwMZ; zyp7{;SdsI2iEy!G`{m9jMg?DgmB!79eQ@WK?-KcdmDdd#%q1>u6q$Qc&vS2A@cKnd zRMuSYD3?C)p;6C4f#t`%_DNh%cU7=C*}LdJ`Sb9O`=2+zk4Ju!nYZL<>iLI9Z?ZDn zJ1J9VwfjKPQiB=y_y5$+U{b{nUUzwx1fHc;bAy&QJ5Fd*Y&2GL+_Z1cA>sSg)6DIE@bCE`5~~=wDzfBn zL&h@qv-~IOkMq6#$Ch7TB|UR_j72@;+nqACSrbnb{`k~f>JjWRO)U6IGtZ5!QdT^k zQ;)1N^O$28IqjltBoraHEk3TyxSMX;= z%gG?0X`jBj%RkP`zg+i4V(3+142* zN0($iY^m(q8T{h+CI$mH@yR_thSj;53~No*&O1bATtAv3x$$Czn)`3P;QGt#5_f*F zrE2;Jeg1m1+s9^G!~RW7kx_eU=ZW&X?|uK9!6rQZ;o}6cEqZ2*ZAn+QEnoH_@2=a8 zu#2laUFNt%2=zR_lwo^n+I!(7k9KFDX-0qE7{A*5x#Idh4V4q0lOnEKuAj>#|E%Rf zpKR3JvX75#-yhp_LY94Un!wCM*QYwE*BfpW%D8{HSLx1MU6++Do{O9w>nKOX9h)~p z>28GXJ03UX-kbHNyNi=6pMEsVuM6Z^;iMVRb*-`ai8b?*)Ml+mx44-Em_${doa^{? zj!#9<>PvT`vZurICxIOv!YNDpJ|5>twkXz0sl1&0Eg{*SIa~R#c7H!(#p_=z2?gfY z9RsvlHVIsdn{?OHSkWNRW5dSY&c{x6i@Djh=xr%GE^+$N*5_TES(TS}_cIngFRNj{ lxP9w8hK+JHA9C0KXPS1`xRn1rBdF=Z;OXk;vd$@?2>@p-B+dW; diff --git a/src/main/resources/assets/ebwizardry/textures/spells/ice_spikes.png b/src/main/resources/assets/ebwizardry/textures/spells/ice_spikes.png index 87f5e23e644fb654f06c406369b4d107abb6c982..378eb5d537c2dc3ccc676345d13c7e97499e259e 100644 GIT binary patch literal 4930 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 delta 2182 zcmX@4wpwt4vH$~HlDE4H!+nO|3|~Gj|9N<_HIH2VLsn5yU5>8rKV=vgI4nF}977@w zADw=CvP`J#ar^znyV93crAVFknE;&_|3UeQQK1_Q&{3>y}{+PG2a&!@?Hb2zee zwAf6=rY-w=Kth07qe)@Wgk=(?6VxP1C7v6+ikLC`Y4q*Kp@sXlZ9a8l>rqh#2KH^g z{=9muWR+Kt6p&nStm$ju>xJ|7Gdb``H0$hL!)11GDd(}O45`PHBH^^VTp8v$P{9+zlxYq70q-)xsvJ7>D{UYWz{ZWn51oL$h;mKqaqs5P~3ZxxSj zONQNvdEY-z(0@?{j#2E!$zeQh6y$s>b4c1cej;4`}AVXiOz}Q z9M!)#f3a~?U3c7g=)?)`jE%Fy>*H(Kbf;W&66A87GyQPn{ONUHxUzK4MG4FfEI%Ew zuj=vSPe#|XbaqW?jA1NdO!Svusj{P{gL`+uQmxjnvn@Wpd3<5&-{pyxryJ%s*KpL$ zd%T|KvDNHDp92m5JgTj>ZcuGpX}IF+fzyV64o}pn*g9Q&|96wioyor!)@E#!zJAxc zKI)Cy)Ryr1^-V92Z2bKp{9=+hi|U8Z8S5OhP8K~VTFP|I`RE$f18X?eDDMzH9?zuT z{*3wC{c7{{#a7O@%^rD$ZV7q%yI(%Zs_@OO@(IOfJF36kW&Npid|tiKbnSvSH_CSk zF3+*85%?q1m15HI=RMDbhjD*u+V(jgjI}nu>>^qJLUZv?0r6=s-@SX5qx@*`$<;3B z0y&EWru;Zq-sfcZ;O27q$2F@D-o0xZ_a>DXg)#??`Q<>g}+|W{I2~bYZ zP0Bs?f8+BX$Lk;ISbu-#_N!dD>-=x=>^ZYPYVzhSn0n}+^)Ac%d4~F@ZZFR-NHltM z{Cw?fN%q}xyV~Rbzs!Ag&A_<2x%BpS<+Uu{#@ z_04nlJ#~`XRPX+W4AoN?W0@^@dP6!3dSdq+Xw^1ke<$-KCnWuO{q$|0uGOF0y!F!I zshcN1(Z1SutR{h%SK_?06@SNb!JSi@40R$Zo;}#>qu%FKGIQnW$4AbZ`MQkAGZjo|EnN=4Q~c`U}_HZ`?nB@}t!2oO$JTa~@sx=5-VQ^rTzyYSzR9 zQBtjIz6E<4{d+r!BYgHnE{0@-V+|brvX*B`ugBesbxwYj>E)<1i~D4F)sMRoE?S(+ zj|m@p#^v+G-0;(hIGM7U)27e2J5=)M#>Wr)biR5Yy#A@NHHw!(yX~N?v(6IDT=B>C z?3S-Gof35Q8p^cO@{%SkXRBQ%eEeBK-_Dhq&(_C2-*w@I(MZj_y5Nx!Aq_b%#uhH}!1 z<3+1PgX69rw@%(1v-bSuF!!}){*UL)IAK{;y?RCcR_%lNCmXg0F$hhWU&%Zk|o|`>m;+Kd#Te+Nb zVfxAZ6=_W3Cs&TR2D~s7bdNFQP)#9=|8C87{$9pQZbOX zGm9s8)utCQYEPW_3OJZv^&(!*`>9tvH%{OE1kK!Hz>i>~qMq&=s+B+(WK2E$HwL6!d6$ zX`KG!tbe^*>20%Hg$Sxye>DC*vo&07JuBnXMaTPm+b(`KZYX#&(fJ6|Lc^Rw zIr;0#bGBxz?tCCHeVw8cW5675j3?A*9GhAE zq>1TK^r_kGGsCxM6>i@rzthm`q}I`UdjCFc|K7QXBdXLZX~v9wen~v#HI?R@pX*OD zS#+DRrnY!)`TA)AfmfDJ*dq9P^O0+P%+)Kei&cE?&!1Q!xAvAyV@1p^OJ5nb8CBiK zzKF;f{{Qn@r}t*0jdI3n$EEwludgV6e5PLGbNI1}w+Xep>Thlo?p&RHRO{-)IZUV0 z^Y?lF|Mqsz=iBxI-@Z&xd0E6QzBOu#wC^r0Q8oJ?=AN59S4KI;bS=?5yOLANe0isM zmc;Ws`&qhkBiiIYRQ`QZ^X;ipcEB#J(3s52nsGb zY2_vwljRjGyF=u$jD4j+(wkdK(QIDZ(-Ug^B<*J0t@`_3(_+QhvunP5K5hKDxKOS` zVI8xB(d?;yp$qklrKW$n)hziw`MOwms>3wD1@UKhTd R&%nUI;OXk;vd$@?2>?`*GF1Qo diff --git a/src/main/resources/assets/ebwizardry/textures/spells/invigorating_presence.png b/src/main/resources/assets/ebwizardry/textures/spells/invigorating_presence.png index 950c64cc1e4ed9308cf93e79453490973f1c4122..fe7735dc0bf58625e8ab8a43ac67d2df7f38a061 100644 GIT binary patch delta 2305 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 Pz`)??>gTe~DWM4f(EncG diff --git a/src/main/resources/assets/ebwizardry/textures/spells/lightning_disc.png b/src/main/resources/assets/ebwizardry/textures/spells/lightning_disc.png index 1052aaa177814c6a155b959199a8aa613a4aa281..a71d399aa5dc934c6ba8509d6877cd0152918f56 100644 GIT binary patch delta 2376 zcmaDT*dRP1u>KJjkDv&$F-XZIx25+xKC z>`*B@%<+z^aFN4G3Bjo=3^y7)>d@%WXh~&hG(085Z7SB)knt#rYf+$>xKD@*o4H8% z1_#fGw8ovreWZ2V>2 z1ZD(iC+(2Qh}*A^>;4{9kibvY`sDC}v|Qex5w6E$2A(Zd+Z ztSYlU5nd;SBhZfHkin(uJt>N&V%W?Li44uAXr#Fb&R;It) z%OhjWy_M0Wt3zFALbh{}+*qjKC`!`z{ z{PW*-_PShrWVB_G`mL?zM^#lbz6L6^`F`(H4t!GZ=tgD7<(`VlN3N;~%tbeSI5-u$ zwu%Y=5U5C~UGx6Yf`wgNr_H7tu5P!La9Hdb5YnY~sm-mPY^hw$b8w&+J}Zy;c`i=Jfx)aqaSs^YcXCoUW9qbdfiSKKHK8?T(Y2^bZMj zrhTr;fdUbxKeO~!#W!VUyIt1x*e4p}$jm658}B-oahL45Uq_224c5u!IOs?%4X;11 zRrS@XXX@m2iv%1P_Ex~`d>44>)Fk`>D-t6O8WkWj31o8x&4p7&s|^R zm5})MMf^ie7BRiZFH+6&Rdbis{{9d>%iv;C$J7P;xcx*nv@_Kd{;!x6Ii0cG?$oVa z6Mu-klc+MP-+b@Jp*M=h4a!fPxA?yCd*-PfiAygxyzA6hf1OVyBRuJm_k0D7*T?4e z=O^AcboGs<*tZ{%dz{QzG`t)ivNO~bo_)K*Wr2m`+r!$C|DQ+C{P)TI%=VE==?C3akDQMoGyE8?sAAWwe=J%ZX`a4yEN(KM!q*v5W zZeK4}bn|`Yjlcs8%YRz?oUS*_J!@k2?%AZD=M7#q1+S=m$D9}Ok<-7&qH|wpVV4TS z{ni7E12jIo-6sOI=QwMB{*r%x_W9KR^_FQYy}WK&{e9t%vbAk` zcNct8Z`V?|Y38$s+w8*!o6~dZPqQ0*(bwOY_NPEA$sqNt_!@cR369>^E>Ai2aF?9* z%_C$8DG+uKuU(wAj8gr?>MYKl`a}Q2F)w8o96DGK}@^ z2`7~EFV864`RXQr=82yR4lO-x&um(=SO5H0{hDLK%D;51D%t_F74g) z=73*RwD9%0o~dWoy$cBPTXeqgMxJ}p?vRBWlNN1M+Eu=GL3t?a`TG@$jfd8Rn+pr3 zKKwBGgYFJ4XZhOc%bJeP(%_FN;3;2!|KM!p-@^693+nEQE#tRpo5H^Q-o_bktBue2 zolkUkmdeV0Wc6i9($u{6)n8t&{<7P_yk?)T{f%wz$&2N$eBW;Vs%`D=txuk{e|<6Y zbm`@DOY$;xS9yFZbSmbEW>5_NuMh)YeU8&I?)dUMX)D;LuWT~Umu_R-^X-;V>esYc#d5Ka4do=tls3oxp0w-WapS}Qd$#NLZo!}9 z&doBIANlc|T1YpijmiARZF_TKYQzJTC*&?(VD^T2ljgZ~(JeaE7&)8Q+vcB z7HRE;yY@^Gcjs5rdJyeVW$iiw@x3aE)2rNp1e~ zH6M#7lyFImBk!0WNcT$nfo$|iTU9oqv|L03R(w1*`ot$ya&1akF^7yMq6&Xm{N0-$Bn2+ z`K@wKf_ipTDjn-=o858ZpVqF#gKv3e7>H}82)uqQ&NXA1>>R^F#`otWyI=3(kueqY z+^&$vwvln!goV#e1xmbj{Hn;X!0dnodrreHz51-%hjz`^a9@0MO+=iM0EuZQh?MF7h!(<%5Bgg4CAu_J&=vWDYFc zsc?1H67R}-%SA$M0$U@#9ynWcbw;$|s*d-Hi!_>6G-Q2gBF>YtZH*? zJ#cBB9^cmk>%`{YVho&?my!Md8dH+S>NSV5xE??I);=*r>#kjMOO`|?zlMU)yzZgTe~ HDWM4fyxw)l delta 2216 zcmZn=ekeF0u>JunJHMcHnr8PS1_q8iPZ!6Kh{H#xR~Lj{6+Kp;J-_&!_Vhi>LJ9&L z3Qb)5CbTOo;Mf+il~3fN5m)J!xtZ469&bLn?Nx;CV%depO|IFZtFA4)6}H7FByfR} zT|>r3jY%IoI3^U_KVSUqoxHjEN!~B67dX&5|_nTbaw0S?s>MJuh6JoF!^m)_0Q{#Vtp=)Y_>m=bGs5&yymsY>wnui z&qm*GO_7NapX}#k*L_jyyoAUC7cYjd{?77jA{Kl?I?2!L_oX~;woiWd)Of+7Y1{37 zH`(SM-&s&1%)EN_flZ!ShkftQ@c-Ho_~Mn76Yt@Ld!(G04~R3|X5SW@5Vo>u!SAR0 zr_?htsLm<97Wu}uX3EFKQjuogi{$>kb6W7bok`-uO*7@!Ss!k8oxf&tP@SFc)1_(U z5x@Ubd9WDHw3u{S{ENcflIpmJdxKOR)^N93@9#)oU@Cav2Xl{<^|Y2vkyh1gy<1K9 ze0!LuxBtK5wLLpqKOS!T@W%S~j>@lAyM#RbjtI}WT_13MV@A*GFv#YVhc@ zqe8=vW)Fpq8)i4SmbS#0wM)z})pIbJsh#T3vtj>Nf&D*E_W%5_TI`wK7Z$a-E|)wv zh@=>su>AFr5qPjOJnmtCU%!5|*oOBR)@R%MHe^3tA7S;LYv11khfS`8To&yNc(%E7 z&YMNAZwUHmv3|6ue{x>IiB)2;=klO6_cu)yHP?6QVZX&}?yolQ*|gtb1{+rjUX-%D z*Y~4V#;&5_sImUzebQnZK0V#P;maz^E&pCd&bz;BZh^vqBgfb-&E%PV@Ak3e)phI> z0~SvD#;$No;h1w~|NAp@j{V!lr0sVtlzOi z+DGu+;@nX8yxpemxRK8M!;`n)J5g%9>=AeCkBs|uA$q;1QUh+9I1lzJT6+LraU)=ah@X<|~^?7&Mrd{}+`DQJ%gwS#&554wNX*+&3x*Hq_?%sbi z*xIgMX=b^n#KN)+W}X!ePKg@a#^2@?D@eHfsXOA3?#`|)7k~8NwJ?>*&(`ru|6KCa z;QoB`_RQz=yE{Uo>by)E+!uXTS-DQwL(RA1=G>a19li6<%{%o^c&^Dc{$;_D0kO=Y zrYfNgk(<*uzh1xIDE*s^ihx57Yuq&P`xU~UB4_b$t2aoDu+`74p1&?*%B)pIT)OMz z8J3D<^k(?xMs|E;UY$|*LoV#^V_CMl-!(3~nH6|m=9qS7uJf&UH!Tx}S8PG{IT8;U z6PNkT<9S%5647>pFJs4wOcis#-7VK1t4CJ6bbYY1WA#FR{TG4{!{^@hbB|mS)Bmkv z(jNU2{LjuGyr@?{v1Hokwrj@uk67gPWD350DYN^w)r~(dpV!oFnd_N6Ylh9ontOl0 z|8ufpQna(XbnIlvG;8rQ$#>44zPW$yD|i z%W@dJ*UvfJ=U#X2T#m6=jo#ajVRH@~xSSFW|cxAz@xGvs5pC8-C6dvcF7$M@RE^u8} zWXEN$i5#amjv2EaR=jjKDOln(W4+*p+_Lhy3FptnO6>2S)yO>4AkAcI=+!lQN;#9+ z_@6X0>*o9|kv~~6XRCgGOA1e?`$QL(lPLk~y62qa7m@8r=UG&`Flwis+Vq!iwx>KcGhPY~d zQ5wTBi8b%$CD<^}V>G{hw6MVQl zRVUW4Jiv>-n-x2cCQX?>eR_SwvVH&7y6ZO>%2lvkbkeyP%CIu$ z$R+{9yJycT+)}tCy=Q%-?c201HEt8`@0Zs8>2&e@cUI9}H*Z1BP=RUB71yf>B2{e?xPpyj3+!Vl4xNK*6uE5KGXJ*V37SFW5 wGEpOSbA`2@qSCKjZh{?m>mR?C`_KAa@atB$xlJ1x7#J8lUHx3vIVCg!0EMqDJOBUy diff --git a/src/main/resources/assets/ebwizardry/textures/spells/lightning_hammer.png b/src/main/resources/assets/ebwizardry/textures/spells/lightning_hammer.png index 913323318debbce0c21f573cd699de6c536f1253..7c058594f185b513984fbd2b886c0c581569e5a6 100644 GIT binary patch delta 2409 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 delta 2344 zcmew*v{Pt;R=pg927`{0=u3451_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmP~kARq! zzD`?{8Uq8zF;5rAkch)ar&kt)UX?v=|NKt%{aN2DI1Lq7E2!kSX={ZYWN?ddu-5e! zEfJZ*l)6E=Lv(u7)UYMnN^=Uc)&|WHlvwV%e74xcK(YE<&5K$ZE{7LQc%nMtiK>2n z{r7p7?d3S_Chvcn|Lok|v~%x^_dWkp_r3b)q^kAL{!6GiWS=)bA0R07oPpt%k{QF( zRy9$@gWB>lG?rfc$1uZjk*+U`yRXxY!VQ-j93t{sOdM}|ShH$%Gi)&sXyZKOz~Q*& zw~6_+WuHIASZvEe3+gtDUb=c#B`bY(t^(?ev5=(|CAOieaN%;yNI@b;m!KMxQtCpcg}J- zUMS-)@KCbNEJi_PfyS%||KAJma>R3Rc^NnN#1=%%g-4&^g7cn?K)n8k1?UO2_Lbb`|18NYVU zx$&Q^)Lj4Y({C4c{M~-$_rvBZz3W{yW*4OE>)LwSRsL1wVN9Kz@8%_}sN&ISz*BJL zfiK5~uNMrq96uHw?Vo=+uFZE&Bw@633U zA=c5(P_gsJ@|?Z(tm5b6o#Xvk5_cUm3A}WoQ9>*#+wAS>4>#_t*Jae|p1`+4r;qKS zWZMUE<))=Sx=#ztW8x8?A+$_q$MiUBZw-+Ji*i_!k3DN!xn_;ZY8JhEj?3aK)A`?W z)i+pol!*%HXu9v%lW|yT4Z|(RC6^OaB|*5Rh??Sebbi7wLZD_d(MG^NRQL?&9@&Pm*@Dj+x~6B+uZA$3uE&- z-p87^s{i{S)jQuzm~Z>!p5p=AoIl^YzH(<7>oeeRFYX`fG>D$6#rd)(~il8+%Mo4Kev~E{qY4! z6%B@}jO$itE-%VgJ#8P;`TxPfJ&}j=7~Uwi8=iNvsX2dl&*%BgI3Sz={$v-#;A8u-KYFpu&ug7>w?r2=8Pqo6TDO_EB|W!+fn;mVP-7v<&$r! z${*a3|102KA2020Bb6BTH`T;vrwrqjJ3C~oud#0Q6L9{)sK`1)EkbX~!-tdS-k!1j zQ{keE^K51|Ha>~x4L@8G!+ZJjl!|XpukU=^xZFU+;wH}mL8m8c|5!2{?tS=4`L1Kj zQ)jLhuirj>vQkVg=DW*1p5Kc5q-Msx=d-aczRD-2w|DyDvu9oEt)gZYymj*1^VNof zIk&3FH(#LPspIaNgi6cW2l{jDOXYTNw>{k%d^|J9=FsBTW>2hQ-+xk^dSiP!KfnFf ziAPt2ii=$`O|6hM|SE8x;-K||NYx-T>CSDWMvDUai+WY@JtymQ>sqO~mn_de zOkvcPfADIR-M6`46t}o#&o$<~cYXo#Bsth>21Td zgC`dmWd_trFg==^JHgi=v4}atS7+iup#{OQ6MB?3c@`LPyj2KzV8LM$mC57G_qOY{ zl9~4_+dVt#)qhRB-jr~$pde?%QdHb(Tukjbyj|7`f%x<2*X7W^BIO8R5+&1<9AY! zkq%+oa_X+Pa=C`I%|5$K>R{ej5{|x^Z>|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_#Kj}V zssFX@-6IADjsi~?$B>A_N2g~OOt~s~y#9Qp{_l5B@7_(>%p&ACqi#i1cdzKdZ9%#T z3*)kv%PzaR@di(>FK^s}t{AQ@T@PBj9z77)Vs$TS?nNW3dJPGESFMOe7hksbg{{?W zWND5xn|(H|yx7lv&q=k+7vaCp&AC~AZjSB$|DXTcpD#YA-CKOP?f>Is=90916?|Vk zB~=*;mTc#7h@I+N8&vTqf5Fyc62X!TYz~nR+75OXet&;$bJAI>5JUc>j3R7|Q-V4; zyfio6)ag#EdR%bscTv5l?A@J#ObnaTENm)04332y*m{le1Bc*&4pt70*}r~SZF!m? zz`|(Tvh<2ZVsgjv$8YNFyMwy2_lrs`-yv1Ga`mRlRldEeCbIm! z^=Mgd^ueNw+qy;A0~Q&~XlS^mvGl^R1#MRaCKm1t2ux7bWDU+sBpQseV0`Gc;eq97p9)b1-*H!WGk7`$g4Xkb)ebrthct&8s!Hg{zBYIXD9&F73{W_GFH+tF1a^7NdU%RhfS{Ms@#$W(38lPM)# z{AFuW&qby?6mk79eGtC!(Xlj+;|IPnsp_ttR6j%A*JGkauTz^F7JvTHJJzgrq!M;Cub*;^LX8VZE&yJ~?+3(~Q_H??zZ?$|=JLif{mMN*q ziySnkJXTDU7xiB_X{*PgX}tdL6Q7>1$`r`;xT-_yo|{NTVBX#`L+N?Cbz=>gH5ET)!gNPg=N< zMN}amMG?a?AQ-kiY+Xd0yOJxi&UOk>phcA&i2pL5=RGxRzw?Ti*J{ zVWQ>ovkShSdv@UVhVu`7?3+_%8CE}tk~|n^LV0GO?c86tUqI<1OpHiw3nuYgeytj1cWE+jp|D@3F`!DM8nT zAA2R3A5dcK;j0u?!Yxz1iGMA+J(G8ESXd3AEne(-Luv z;V*PLv;Vi{Eo);FpVbTNzqWZROiK8-xZR?{!uw`~%#ZSE-13$z6Is^ZEzsl*zPv^L zUFyAM>4K--bj&r5K0J5oB&Ws(*`ijZpOg5kX2+ksw(O`tr}6$&`?s-{=VnIvW3 z!JLQ3gc}RyFmi5u($&4vTQxKKtFw>BnLWqvFMgZRSG?@UmVZxtJgzv{@OGNKH=F0{ zoZI8SDOIoLjcmc;Jv-h6rOp4S+Oh1#b-tFx4=fy=XH96C*Z*mC^CizE2mLqh-P(Is z{(F(hi2_XH}`!P;FiC0`X9e_<)g1< zWqLEb?u34s%G1lvt~hJK$ArdxlhmGZMC-3{=K3r1 za(`2QVa4a(;={{~lPgjm_?YEKIBQ5f5AT0-tin((riyi*__NFRY+je`W$k0HGhP3` zMvr%L@}BBFXIQH@?Wqf#(>CR-wR`cI?3?XhzA8DZUW+rEy<~Mp-51ppsT1xgubAf_ zxYs?R_?@BEuHwZkQJ>=vE?J(qYT1VizTOfhPM06Ab*!J;Kc~m-!1_Zf*_A(MSzd98 zt>T&`<$rOq{>B#sjUp0Ysfyo{1ZMt^zORhZJJWp=g-F>X3dz!DNm-g(RvZ{zN z_{`=%r?`I{{p+8&N8*tS2Vd#YuGaYU&-2WdL^RY)Ywh1FTjF@y@r(e^)Wi+^l3GbT zIeTiv=DjZXJ30Ttm--uVOD^=E`daY%YIxE0+VB2b9_Sx`ec@tO$sRVLtvPYqT6TG6 zIw^|hwrFpE%cQKczk;v){qG69)6b^8)s}DIc&%sETv~lE{c+P}&fsO0&$$=(aqr&xx`u%&H+)4b?^JNQ4T?c*cUY1Q0{eJ_Qq`sXjm{Jq)ZU9n1iJ(H%m;Npc54x*bp>e)h1Z2a`6uHhq>%uC(N z73(e(ZIIq0lj85NWqS4Y_XmRbZkSmJmSi?K#kYOBSYP;C{-0#br#k|3V~=Ot`nP-m z(=U7XBJ}`gSB>cbyCiB%r?N#_n)|z#_hoL~2sSd@?leQxty+%O=1aoTGU85h6<&oM zN8I#_q>dCepY~bV@Fjhs6QAa@g(e+FQm2~N%$mL4h1X!MnORhuvT*zpW2Ynk-goN% b`pLhNqeemQ^Q|ci3=9mOu6{1-oD!MELn00zogO_QBwVy@|JL(Mcc)iXRqb$NYdh_r;Zy18I$6T7Ra961 zDeGE~E*C8kHNhDSOpPrmLK*^|fu0k*n}mEkjDiAJU#VX;%hrtzQ3ief{6pZ%R{+9-8v0eosw9@%22rwrgvy zFfe@iGL>=0rAL=%iQcndyA~C)wW@#5o7~Tx|9pyo4x3|9QX0A77VBk(;E7_~PBJ1kTtzrox9HG(D=YMK^yW;7S$dRpkY{sjo zP}RvNKYZI?B#|6Z7rv;kFj&$j^W)2^^9iAyYg`Z7CJSu))RSNPU**%?rwlIc{K>cT zRlBZ-ehb{lm@;ej##MX%Oi!BnZiBZ7cXe?IBO}_ z@qBmfDv|b275i4_-@ec>*J>}@gK1$ISx%puHyRr^g}%CE+{PwzH>u{x=esw)3)(-Z z+E;(zKtSU`C&51qrgqylc4j=ZoznM)RUu+O^WV4H1;_7ZSTWZz%TjEY$Ai;5e^fRr2QK@UVIg2la;rbYlA2!}Z_u6<+l)`^<0s zHm5mBuERU>NbjC1hOHt$7=JJdsT?Tw=XCO!;qZr{iNz%K;X2pQ=l>4-C;Y49=~a63 zB{JhWW6EK_oa^2vrkG9FvuCj{F|(O2W>as%{D^()iK7cFeuZQ$x;V4ABd&Jgw5g}3 z$1Y^|?5caA_WyT1x3)i_f8LXPqufE=g5d8vm}TL@fXD=e) zO@EGU$Ge*$+B=V~Uih6$=-4Vf_l*4Yzc;4{c4q0Hd1Nr@d~n^lx6^a?7c4rHc5!vM zVPGZ?+q$@8yX$SOs`YkN&lUDK&i7(BThhb}?e#7E*PKGiw%)1c-2A0*$$tKgf{P~3 z_HVf`!RgwYlIQ>Doi)8^d#7`rg&iC7Pn#!2F6V7pBDbIZ%FfK((R(3Bta^cP@%{c- zPTr?;-G2SPs6E|KS5jh2Mw-nErENYxr>4)nyVZIk@9u*VDHRgc1=9bn*BMAPq{)tv~O?Q8@+`GiP?tgW%`Mt%~ops-K6#w#2 z-?W5T&Bx_?>9ri4e}ezarzuXaQmAEaa4qVw=dWXv{KeqA^uzwo&gI+AXQ-P0qp37!G`gU@`+RGaMR(3x)*gGRw{i2UpZq~Ar68(GA_PSVGaqR!j zv9wV5!u!X;soy(MzErfuXg-`abOKjUATL0vU-@H z=)SVl8w+-vtAF#Vs;+Vo^SR`6%8G|$7^WwlTYKM}cZP+J?ZwJP7K<#-u%1beIMI18 zS+RMI+ZV|ehw9&a9~$THo3i%w{zR^_a+Y%}6I2#Px}4c?lc!rQ$#eJadfk-)%XqF` zt5RTkWbpo=<|C#@GHP9x?W>lQ&r+;xT)}X8EyMn*w@fFPIT{>#B1}FA_OhOh;_X&d z}NlCz4?yr9@d)YU0CXZ_e=CD5(6cz|5 zjED?6Z|k!>!t!X>%_`n04OafyJL``oSU7E#;k1-udd2j}W`)|+HA}9>q+Ez^O=8Po zT5!+BiBFGtej|U!`3;*Ku5@H;-$>z6OxoxWa72BjD$5n~OEYxXO9NIbEBb43c=Q;^ zE?g$S{b21`25yhNtyiQjWH^VluQ@hx_PPfj*7q|u?NChB5jY@lM7{GU`>eY?7uPt{ z*E)Q*nsoibGo@KqFK^+iHjrF6>tM;It!!KN@4MEhD<@vP7{(s^;?oClz2zES?|!}IHh8u8QG(SiE`_W@YUNHVb0R^x-KeLd$fd#Y9g1dKfqqH@G!r9 zJ?D1&|7Ie=B`<4o*7kiiozb^&J8J^_y3J?G^LF%D$JfZuIo#FMp1(t4&692F@k(a5 z657&C`|1kiFFtr@|3~`bmOPo8+q<2Q$NMvEW$U$heDSqjQfW-V^N;2m*R-9NzEQD5 z)M0kF%)W0z@9OJ+)-Ji`GDqF-_??f3GIOjRvYWqu`fd3?&I9H4+uN<@SIcrr-g@l$)Gg0B#yR>uGhdFP*YMi`U`AEHHcV%0LL1$Bk zpn=uS=W8GK?E3ztyTfYfQx=|SS%(UuK3%`ee6Qk#6*%jB*gf6-`4;KA-=|MY&%Stm zUR7J!?z5F|+1^GS)7Ey5I%urR{p)d4-d*E)(_%KjS6?Hdd8{hsVTJ!gK|Khi*S+}Pxy!Yh9KU*2Ae{4r4 z9S(o zy(;Cgw(*JXl8X+Xtd4j*W0~C}s5F@)D0|`C+#TP!h!JIww;(b2j+WL3um5u?K{5K=;(IoALX{sKcK8cFwHZyv< zENGe{mnMAV_mrD=N_>P?ghcYWEza`URACW2UudrN8(s#NGxZK!Yim-96J_vOMG!2b|H*Yfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_$STgG zZL~Q4dJF>t`%+IA$B>A_N2h1^%t;kJUjMxEetDkt=G~k3mMeQGYnrWW`R!}a(o(_6 zVj`j&h z&BmYYp8t4QnZEt@+w_`AC-;2bXI%X6dHuih#sA#5#Rr-E>(^$Jm|6SUkca=25JSVo znIa9nS7$tQd^o+nd_@(H0kbi)pu(RG-`NzDED9Mc1P>IPQ*0=9S{(PhHv04FM==|A zo|^danGi!mv7cwfi~6HR-{g-f@t;e)m%L1(DN_GKP>Ev0C7uo@KN(xUvkNZSACUhS z$y}IIU!EuVcwPC%jZ&XaoL;SPN{~0Ca3|9HSsJbN9B0#vQ+A$c zc<90;yey${>VcRryNRh$5h)4pXV0Fvq~S|l6w@2|RsV_k-9;L7=>(c2#B9uhsZBSx+> z>D1Lwf#-(e&Ot7VB}xtBWS%`@s6TX6;OLC*1Fa9*7N`kW`p8Ue%(`$j=*ChZk@jl~ z0{i|gH1(OLcBAB#8lS99$JW~(la4Queziu*Wu@HnJBwa;e43%TVv$Btm#_fO9A=)$ z2Y4=WGK5^?Q?6|`d1n2j{hE=HW%q0815-ufW7|#B7FY^rgt%J2U9*HwSc5Ml)AUvS z4DN%0{7E;z@mdK!Kj3=0WCO?2U3tt?7nbTAshx6tevfE)pygYgh`(i7{q`+u>ZEJ4 z&69R2X$el!U$|2!O5^ckrX!Xfp9G#?usB%cS`*{2m}RQK4V5+x#_4NP5*}+VFHEyM zzxlu2nHMKCq|e**HkaRHIk0m64NuMYGiJU@2&@;>eY!!zX_3H{DBp+-hbwJ26vAD8 zud)!4njEpZ^LW8ep(C{y=CVJV&ivy6>vH3pIhW6b-Yh?UoWbJpx%kNu?aubUq{Qn! zvdg@RcHMi?Ws=PfiC&>g?d6lI-Sd{Xq_M12uMdVbX5H#Mhp#pj*T?caB7mc`RAzK6dYO+0N=dtH5J-Sy->R<`HO z?LIMH6O+mQ)R%GGew=m!IYTN8XVu{EJ`o8p{27H#g_! zhvka#aaNw&Sxb*__Wii{@0zU zB_SSrKTiEEpL$>1?ue=VAKl&MF&p35uiN`PyvNu4L$PVp=E*U!`=={EKC8;GzkcD? zA5V|}zx`Q2Luoy>2ea6}8JpctJnS&@?(K6C zVjpI`f1g^itZ#|tVdqr2pKnS}*U!7ZG577Kv?Z&2wm$r59>jNk%ZH;|=j=`8-CzAE zv+m>5**k0YKGuIc&;DKgywAtfEHV#QmEAA67JRLmAud(AulBL%oUdp1ihS7e?75|h)yc`_cfI@`#9qJGWBs0MiOGT0)pb6LUt2y8 zF5mF{_4dN6-()YWDE#{DvB`#~(fUOdi%z}@I&$TVivHin3TGE9mq?k`EN}I|LtjFz+_X=-W zRo*^Ik-MI&baru0?fKsa^c&tQ>BUtF?EQGDIAizWd*OTmTA~uwPfH)w9JzDFWZAqe zclm1VvX3?;q;+`IGd$RB;X83l_ln~SJG9n4UU<9pr!-a$XJ3XU%=P8PYgrnx0karm|MB#w%Zja0pkGPwlgLv^D7+;nZH^X8~Cq(d9L16`e4TjrAGpv z7e>nRAK3mXVPW;ks!3jgx6Z!l*UdgCWf#qsv{9zzH%o)xfy6UcrBlwCWSkT+Y+n)2 zc_4~$<##!Qw0@J5)3tT3q#1r)F!S>17sAiQ&aUiWF-)@HF`SWYGA(Dd)FYO5W^X~; zM)?J|k8SeNIUQu}8L*9Q@x{e{^+$B4DljX|CK8tt7rMYvt9tEF$HS4O)Y{9C%&PIV|(!C#YE^hdpz&de*vWvsRZ{EAr6Bt(b z%P+ljf4=5D0p6+;e|(@a1S`FMD$)siSqRmXgP|npF?atY~OQ+(+68Q!6k$-`D)v~}H=AK`M9WHp;``@| zzrT}De>Yb$?cX+QOUwS0`S6%2lA`z!btKf097@L+Qud&5Ld z{>6_Do!j4hO)8n^mP8MS2J1BOJ$B!9-g&bG?Bep1OkK6Wlq*0DTZ6r?_s#wT$Eo3~~0yULXJQM_|)IKL-V#X$ndUcz4ZkFVZYg zY+p6S(2p~AZG)l9;=phF=DTSgjh+1GZ^w1s9-oSehaHC`-n!{Ei5;x?Gs8nh=&->< zmK%nAf2yqIR9DRV!K=5_b8}tOlS?yV%)?&kO!8i=?aI<|G-=7@%x&@-^@Z0}{yQ)) zew6p5K|8NfQQ*)GLyw*ZYt8?4_;bbyu8Z5*T7GS-LE<|vhJRnLoR`?2!TkPjnsuLH zNKfLW?fct3%aWd6ni0hKc8cM#9Y=oggzhd_Ts~2{pI_K_f%NeMD>m-=JKes}`Lk3` z|IyHFs~_Kwx%$NH=xb1A(Rp}j_w`TpC#R*>lpYOJk~?bpd0KJB{nIlhCSUALUUAFt z!!O5}-gN$H>_Q9%4T7zlEeS6?zP+#SU6A_m?C$U;Ly$TBx5EvWr3(MA-6X2o^yN(V z+4>phZ--y7C^rpSTU2@Z@1D=6{JKKVKGD2v=+~N|@9fZUWK~vKH^YgKo3riY+xyP-PqvBK-QCz}Sg!Z%#QXWrPf73Z zw@7{Q?wG|=$7v3lAJ_~wCcdeEo4Ri1cA19m`U?42{jJ8YqK!Y4%~h&@W-=|T7#DIO6ATpX6Nq-5~Q+$%na2v63mAQ<&-*I@LaC zK5Tv~J;9^Ncz6AF!zaIHpRBK%bEmUkp;BzJuj9%GvsO$oJZkgg@&p_1*yRu3XdVjA zQ`}sweWS21FTOvX^H^WA{evuCgM>=O9A}kA|CZBXIgeA0NA2-iFvFcIb4iTDD!x+^ zSw~fr@{F>0uNsMbp5X6j*dD&%_4I6s-D_mm3vFNGylr*qI>x8m^$l|q{(tr___^t< zO!bzTpJ!ix9LyDZVv$y=2%Gmx#;q~?%^TJ^t?YPmDME=SazkIR^z4}%w)8q%&o3ws zT%SKd=0nBA1PO1>_qj1gcChjnE=%T}xN>vAO_60mW#9kE)x45XR@#~ysXWzalJCRa z|Ja{=dwVP|>*?f@FSPt9Pv-s3AEfPtp3^;J4`kIs7>qTeNCj`l*mc%YmyZ7B{ zs@K;`E37;;-=AYWk-oFyUzW%twOskfrOY#ZmZh;yoY!&3e9@Fu^0ltn&r7Ug%|p~L z8gDlbXN%la$I_!X|7?@tp4*`c)@AQ1~+L$d%&YA|CQM@HNqh-~r1)J~2*cS82zp0#dvAh1<%(LDXk10HqU}0KO z)L3$TX4F5PBYI5{a!2Hkv?xg^+}+o7*9wmj{TOn_JyI(@ComeEw0PnD9Fh_`nbdM_GXcehSY^Mbt(dF1w5R$GI%ytX8)}C z%cLcBV(A2@dZtzHTUSj9+^HhEc;^#$?}<5+PMl#Cxp#+|S2^)T<%A4}HxgPBZZ&lu zegzyf&=PX5f5dB0!g9%A(xH8KZ*1SDa8u>^*}R2|OecBnsy>onsc=kTs*qOgwCrW) z9-O%R+Og&Tn_EsVwuyDMe_wbkrfJuQ(%DCrR%PIeREGl#Vr$zGe zdp#xd-Hbe^lm#?TT^Pj0s@EDLHTB)1h^u>cmx?ZaAJM|_ZBAI%uCDxlho9W9=sa|A zuL$2e)&IY`f7Jcrn7T^Mq};Tg;p5Ej1$&ZpTUWUSrN)Y zROGuq|5e^Ezm2nI$vk>^*?N3{E z?!es`tyCB5JkReYx?9he$G>4NVpw7QYmwX8j^}sS53PmURTY6hH*Xq{R2X;xxnM!H6C>R&?c+&+Yo^@7z58M(_V4U$vPtpZwc*zxv$w-?q^uMH{BB>1&vwxd{?_07q`}y*bF<96%GjU-Y!!1<5_qz#SL8aYaR;Y0ymn-EF?DQ~ zS{9_HDQZ~gBjnzpwa6KwPNe5A~xr+?#(b#{QS)B}Ol%MQ%cc@lN8 zM*GR9KS}=+Wt1Z_83Po&rm(+@X^(l)x=?7DRZC0hBaI_Y8Tt9gzt`56?UUM2=UArH zI8*lJWd8V021)U+pE9D^{pbAR{_1ivvaP!Q4~K34zZOw`8&YTd_o-fAyi_SHm!sEdlAE^c5>M_;52O6g^J?ku&z`8l*{Q`jL1fuPk!73y?i6OQ zDfs_)PSvaJI(I7gCAcR^7_v1is1IXK{`hX6Yz&9ev$cCC=ic5vd9#k0etg@P?}_23 zr~I;WV@T$)kE%QA!pk!~_$`mm%yaAeWzs*}&aO=S&KEMZb^BW8t0Z`mO&%9LpSJdm zMa>l7)6*0GFdi$&Q(Lf#w|i$sHKS`~;rGiv=Wm_4xkGeq*owI}9meI1%ih~u$A$;rJ-~X~{61A}#T6gV@3sE1Kx)CyZ6e7%!fu=r%@%r3 zK0VPr++=O0cudKvmgV{B&l3(ZE_tK;mBIKKgP^DVgh`sBi4TFt^Bsnyt|VkpGoA+RK@S2%6`eV=0z1<^rkKC&E<=*dmy)~WsQaEm|F zBF;seZY;@5IBVW~Puh6nMg5Y7S0`$u?4s>vPsm>RZc)7k~$xa8Z zCPU?aroD1}&A<2AuVS5O$k4kXtKz;?@wX#l8X>1r8R9DbEay;|)z%YXc5KrG&nN@A z7}1{8rG>UWQBzOn?YCwPZ#A?uxYeZM*d(=4Yi{&A=F>}b3u1k|xsRPpSTm*mfO=y$ z$1$UXn;p*;^L89R~uU{?ORWE+|+P$;&+KfS(&L*A$o+3%7 zT%S1UHz)ek+qP}!+g%_je!r%-=y=GV9`5=$Z><|2^8_5{TuHO~Y|OLgvs&v??TH)w z40|dbU3C9(kC%JmB?Ti%M&+hX3cc?b)Boh?^ACA3o?qvhPh2@&Nj7-G znr;ieq}vIR9gh=Y_)l&vOFCF?FYx7>FG0xbBp9QcEj;zN-22)tU3Nx0XE3I>Y?Y=EPQ`f^Y9dcI^_} z&g%W3+5TP9E#K@9hb2}{xy&)Yr@>I|F6%4CWhN)qOw$Q3z2BG?x8$Yrz zWeO@SF*>5#EnfKLisrO?Ut@p05)5CrPc%?eAm}0xd3g7&EK67uCu2S1)cm9H# zv%YRw7jb>dq=j7(W>f1ApAYCxF7ggHPQ9rW_x9&sjUN;ESNZzi-y+O3r&8be6W@YJ z@!VW@?#mVhe^^?3&Pq2s>+D{0;7X70!)?ASzvnR>czw^M@crZ+cV~klEW%*v)Pn}k zX3w2_!a;u78|B2g4>>;^R;^^X_g>dr*y3kc@3w8*CLU}Pyt3)?TZ`%L^`CS9{CQ9u zbM@83j)YEyNqlP~rf&c1m9=%#e6DqJ3WY5i5!W(m>?@p4yD-V~x}2H&^uw3aSCgwpn*n2KEw9Usv`=TM$^HI(WJ`hD01bIz4kj$W_tf_22g`{r%PKvWf8-gEtEryd8xCFKRfg*|2g! z+sYLS1f#ld=%}*w1WKwI3U*A3hnp?s-?vxSf1mUJ=lyDzPf6Y%>v?1stbKkveTAlYJTt?V^4$zPJ+H4! z;g%^d~H5aBCa&ut-|gF z(^;NLTVt1nZ<$|k?nwQ`LcY?J3CDwdCGtKzVw~)Lum6EJZ~XQh<)_We?p11Q#hulE z7RUN@>WWhfS9Be;+3+ar%7Tq6Dn#83TDVv~eq~^3`r*he+V%M8FJT$8Sz^UPy0=`^ zc+4dvuKVj8+&J5Q+ieElN6Z|J`i?KzHWqZWPe1$oSNlJ<&R3Vt3iim{sFz=3Q2KdY z%Ew>F1u_<}7qDJf&z8x;(5mD8;Z3Y2pX@t@(s<^RpJdgUuT0^dlGe0Lxr8~M<3o(b zttl1mrc0yjjv~J!>)=gpL%!g zXTxU4p#Jv^+Dv@v%sKxIy5u<)l?d0zU;kJttIB(T`Svjlah-d=xbDp;&WN;-mFbt9 zU8c}i$M%znN1FL=yhFUY*L03hm&n9_6_0iD>b_WZxMc1r6f5&r-+uM&;<^I|g&8@b z65Ik88h9By7%L_?DmW>K9lu`kr!I6wVY>0PNpDP9PHma+Qzq?u;vD~btp%2=iX@ck z@3*g#?A)ZJ^6Tiw$D$|hE!K(NFS+}x@CNR9+230^oKsb=-rpo3WV+&2qCo*mxz3z^ z>jIX#Jwi{dCWzY1|30J4p#8;L2Tlc%);iG!{`)&w>JORxS@qE1Mai!zjVID4zVu76 zW4>u3;?KBXjf9Kvo$Y@^!M}oFnITt?84a zm)~`kGLMG2_30;A`8tP8Pm3kBDCykY#GEP>(&Dorm*JU7e*3Jz z2`iQrUg8MSmuI-la=Gc>)d$*1VH0jWw_`ZGWaXu#H_Ib0*esE3*(Z16TjOhHrT}$j zo&0-UTx~mkw^?4?gn4&E^Aq{- zKKGw?WqSPeH`_A)OYjI!^jGG#Y?;iwonsf<4t1uEMZH?y*dl8){mMVPS#<`pxV)KTokeY>^yLnUt}k=kCvImSu&UIq|HL3=jWrA?QLwasA-;}GOd(x!mHNni^@7VM!I=2;EDf7&|&DwVIXY=oiW+G9als)b4vBpjO z^_eaBdzkjw>GS7P3mfnS1lU29Yim%p_JiLn8PIs&Df)@sVXMPtve6HmjpGSGKpp7N-53ZPY>*YPk zj-P{HY^?inktM_GlK!TM%YkV#c6GaLezlnC%}bVr#-;0zFTUSvkpDdKg4F)|IB&g6>g?SIimYe9j%@agEsW^8JF@JK9)xIxCoN z@eoOjxKn#j~LbwNSx#%5z5*$4$EIvlzr@9X}p%;g3p5 zS;6uCv<<)bd6$1^{C$0qQlX1Mla_Zwa`WWY1+CM?uhhpDiIx8UCDAsI@pswOsB^a5 zI;@>s7F+hGY@Dim;H2WVw=9gC-fL{U#eJakp#G*`=c6aAD>iC4@%#YC)G2FbCp-^m zROr3#!>s7}_6NhFryt&Ft9EZ&^x*0q zY<8GvRK8rKFj+p&wM=HoyF-C@KEJmM;JU6i;a9Bi>UDeP{OaXbp2KtKyWcm)huSSy zA|kEls-E>P4t*TYC?BZfVA%g6%lVPAD2Jwl)Y2{Qa?{tZ-e4_MfcV*=uGL zGUn})Ui8<&;qNZBx;Sg$vw8}14y|P9TC?L_*1MZqSZBU>PN~YYzSMbQx!_B=mf(b^ zSM6P1TD6>BsMGi2cT*^H@tKMTo@r}pr?qJ=SL~N@N!#`F?6mX+zYU&T3Ygb$Pp|Iw z4!I)9l#6z*oHo;co0}}2DR!f>&a6J4&%1uVU`v}wlj!wx&!$`7OME)#<)5tIuT5gi z7#og8|LY8~(~4<(;Im}%@sp_sKYPu)zis`N_Q|??`CZxjgco|m<*ZC@K6!fP!;Xel zBb}PNE;AVonpYG^YQ?p39TgBVJ2U&_p=Zk#=WCwjJj(P!&CkT~@tw>CH9^wz9a5?k z>+d$7C{x~TJ;Cqg-kq;6T?!~#p)-D?V`@CpQ*EZtq-WQb@LsqiZ4x48BF440 zp*4AJSfifKR<3(}N>0-=1Z{T&rZoNnqvIBShpr8lc72ACqMgnnZ6l+Vtr=LVJy~rv{_M{SM=bY&DxH={%05%B)XnV zbl4id_}KCfIq8~VnGN+1_H^&~Hu?0;eZ}HRMqN7G8yD1yZoj)>lCflG^pl_OocA9p z{G`C}^z-c= zkC#te$GPO)k_DEIn;Wy1PdM*na%Q5k?4Db<4%KftdwiM42bK%5c^ir*%L&yhlq^}M z_}MIGs-lthz9WZr`d+d5%gVO6=+@*@R~}xi7hNo>*1Ib&u;yko>OG zoh3WE*e(}73DB>vcqsa=`lo=Wv45#S!{xU}6Spg~E?DKUoBNF(*Dl$Y8jj_=7*7g! ze)If(T9V=D42?gZ`t=``?%eTkmG*{JvlQ#Ew8Tjrd8_F zU(pkzcYLb2N%Bf5L*w%wT;{BDkYx3joVH);CAX5ST!3g_NiECEA2(+<8BLY4u3jbJ zY+Lhw;@c_KCUpgmrQ~jG=?m?S&RoS+@c-G@h^f3He>P7j(-+~ovD87h>GP`76S@?- zxt4jF)X#kOIy+ps`K*Z3T9G}Dc~SdXuHS#>AZ0kuW{HxT2UAe$B&=Swm-dYcYf+!W`AX)!hjr+lBtuG1@$;8KD>~cn8SCeup z4&L&wo%G=a%iH2rmCx$GKR$KTQ+2V&=~>TOcI}9}pEaYPe$^vkkI>d0#*c<6IWj_l zDOPQIs`b`?qTVxvH4=XZpBIvrR?JgzOgs2aW#P_<+h+40 zJ15So&D3X>mvfYqR}z2z)V`Z;IUhU+b@zVaX;T>oT5ONJKrEVdUNIby~$A00j@_^n)~dE@1d zjgAJw3oI9`;j)Yjp0e`QhYQ*6J1Y*_G!>t7-m#aXo!O@D*7_YxFZmrkEtT>={^9UZYN$R{eSq~lfNYKddR1HTpDX#el(pB(!Y_j!pXs`ahAE`<%xdv`cv8!Zd8cz zx=!4lUSt(FU*5T};WoD!`=O@`Z9-1BnO;x$mDOSGz0tZvW?7(*v`$o((~m!?BB!zz zt`m*C&-Ju7ge^PrR#5vhorMopFATWZ!L!XFLCpTotz}8CI2+BLb~WFR?w&G9cI#$~ z!e#P_qCfxqY2>f?)3?;ZyY@@p(R$08AF@q)?8U49OtH)<;dTFcp}{HCn14-VQ>>`T z)SZE%2Lnt_ZogjJ|k?T0|vjnb5ztKNvhtUXG7ET>Saf z&CTiN6K6P@*d07}{M&|_lQlVd{MOrY9zBYZ|9@RNInY^k`6A9kPuJS)$dl}~W0$V4 z|7H=U)i`nEh8(>KVhe-Bi=9(tY;PWZ{rj78QeuY1YDqJ_ZZt^&J`7H0hU@rGK;zq*Zv*v}z zrYyMi<5}DJ&yQ^5ADs*9m5-NVI@TRj~f$9 zt?%!uV^!?$O6qaeV!HXIL^VX*^u~6nWeIj`>e! z#(Ag)a98ThPCo82t0Q_^^^=5{hwDRMJBIFDVCVAVj6r7zpN!v-{Ts8y>QCH$4jd3IWJk2l$i+LYz~!YXfh_p@J8d6B!@^mQ_qJa&;^?xsBDn#rbr7wsqd zEsuO=xO2tAN$2h{9@;39eLd#5_V)G5)bAXd_5PoTmb8LlGH|hkwwcq74wA(EH!lN3k9c3&EHqTslETdcG~YZZ|tufeky)W^}*K-@89zM za#NCd@n%_iLdTCA9JaBsZ))D=X1$WWSrTi_SKqMfChwIirUu#{`93b`+_mH2wyOq- zzpE{M_O@)}KA-;D_xi@)&6i*7>e_syIkntqRb}Lc0>j$HfoB%V@hBg=H+k`yRjZZj z#r!W+e()`FW0}~oU`dk5rp%neF(Ea54fn>8)? zk@Fkts-8CPoGGlwcGf>m&)}@^e5%7YUn*_d{+4$O1?S!Rt7NV>*EhX>Mu*&?O*;R6 z_v=5@ObMJUEK(HdqQ@SwATwm@jvcT5M4A0BVy~A-?g-&IdS=7Yl@e9CRdT^44j(q3 z*I8Vxa!mf7#i@yng8TM-68cxPqWixJIAsy$w@>(s_ZgZaPzJg@kA#9%j{OuA?Cgz3MScj&MxiWWp9Eb~kY zTEfQ8SsBw}Q|9(7NaLl1lC1j!mx5{Rbp@Y!@BBO=d?H3jb+TU2`KQVgPc~&X&2-Xy z@^RX)$X$=Lg2Y^s3wQaI374En{Jq`$!?n)KU-CcPX?tgrm zeXH`%UginsMSq`p;;~3?-Sur!k~a!7BqmDeFA5f2vVGEN`$9uIf6c$ifs@)8cg;;G z?Qq{;rp*8Et3dvqS_V}sr~468IIN1Zo9Bc}r{tBYnubm-`O+q6)ZgJ>u;j6Vl3`rQ z{;7{QS(+tz3g>$L);YiTWc|KFOiPwCyAkd+s{3FFF*I;tyJy`8zI+48~(O$ z4}M*~dHrYQkYpZJvnG?vCG}UFi+8rq-}8ZMm0_c5h}`dUZrg14PfupQ@3Q2PMjF=| zoATJl^TNDO-AvM1`jc~;-lK>A?;JU_EUIqP>(p=itEU94oc(K8R9Ve)w|kNjsrC8S z6%L(JZs`grxpXn`*RI{1mZkeDyI%gu)xPhUyHg~?&txkEzI=4I{63?0 z*NK@^UM#ZMAoW<|r_SS68UBB2?UOnj&DxdfADj#I`*oP}RkP}IFJr@%g4uQT!fZ^x zq7_7yZC^c^S6%H8D*2|MVSU%q($qhH&i~$7=cv3oFY>tU{u_KdMef!za~QWyG8Xh? zKBMx!|EuyQ$#-!R+24F=7k*n2KEw9Usv`=TpZ%8 zdJCrHNH8#P$a}gthD02mIz4v1N~+-T`q1;2?;59{J9Ex5y*#p<@un+tnxjHPC+8x= zK;f^)ez5jDw3ZOI@2W~%bf@a^)Q4^dA8;RGSTyl^ZDL~m`FY!C8XMm={%aE&cjipu zbXCUrOD@l?+qL^&?AP_H>Q5G*FPnRQ_Z>lo^vZuv%o^65|FqLilF`oM(|HrEhBb1R zuTH!3ZPw}I3Ni&BC%^V*E>6^tXJ*(@ID^4rzvxZ_k-FdI6L?yuv+%QoGkJL)2o$mX z*wmq*B+<8Wp+s@%rnLHi#QzoZ-`8#3aroSI`CE@(ojrM+fnnahh!4B#Io|c9tk|Oz zr63d#zKGpQ(b<|wY|9>wkO)}%#od> zGx2Dr#7*;z+_p|-u9G|>TKWbXcYAVt_@mt=#lr8>FCwR@6J(@Nad^S)<(r>XtLC!b_`oU4Jw@cpl1FErN&4}h-*ENy=eh3tkKfCfe*J!J>)pu1 zb+ye>i@!~4Rjm^8P~$P%e&Vw7oxgefF8$t{6kQgm1Q;q9rM?i3y1h)F*Hvtn*bEtY z1&;c&IY;X6)y%9ieE!kfKS`+K>)ZXG?j008BJDNBWsz#|4q@91s}6A;;cRH~h?wX; zA(ijf6g}$_+XAyRl{skv{ufS8*}vycb=AhCiAGV^Q$p{}kTbj?Q}pvtsteb;H~WtY zvT`r@VA#3ECsp4s%OgfyI(6pr>`Sgw_*iFO3KDg0tADB%bbW<&=BO2wMkLunAclF_mo6Iw)eO>Y=d9;LW=a7yj~ZuKt@l zYs$?-GcF}crOOz)=@dFk`3QY)uP;BNdpRXJO?Fdm;CZbn z=VX(V=6xyRG`Za5SKc9bLgG}<&ze&+-|@LG7Brr{d2OuU(kAJRPt|ii`p+~fPOpE* zDsFpeyYIFR7TE=>-pIuqzh!t(nu+^BAxnIv({;T;CkLANSldo(Io5JiBJfvoALlb_$wYSonz1>zj_j)k%ILTV55EZaJ-SwPHo4r6oG1OE?vl3hZ|fiE)jYlDeuGzZZqMYt=L&c;p`cwn-=dncEr<2dE&-WNs*sBBvntk@Q51}-!T?^=pp_krXszB z_j=QExf&tSiuZf#6B+02`lD-BUF&w7z2?Vu`wjJbyyx9d;;P?aB4d^;c4^X)lSwyT zMNIy{a-d4N(k*0KX@kQ<$;GNqHN*MtC7IZ#EZ=^1vH1Li8}}c+xmmrktE(sYxPx+W z*82%gr{j#5O?6Sbd`WNp)f1EaedaSvP*Cyj;Ov@oBw|9L_@?bMBrX~qzdUX4uZF!h z6`TLr)k0H~;jxg` zD2{B??|%45p>OqOg^4B;j|PO+ef!J1uHxRDg8#O&%c~zWD?i_vzMJ9CtMj~Vg|934 zOP4N)C_UZKwdUF4rPEF*sYHfVipQr;xjd;L_FnYvzpu`ol$D$CwPcUmm&nT>WhZ}p zYrOW3rDFZHl09rf_LYzSOJ02+HNRM8f9+rX=+*u|*J)h6%D}+D;OXk;vd$@?2>=w% B`pp0U delta 1990 zcmbOvc#D66R(%Nr1H)N?BhIx93=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgg~9x*Oi z>E{a$+A%P&r+d0MhD02mI^Dlt<#^%IdVQnKt9DhVm8DIeCbmRnQWL}P1c`44*?2g< zoMm^GcQW`P%Tg=u$<8>*u2pYR%_dd}p$E;05^9cXT?*@u&U|Zs`EKY;LA#LiZ}_G& ztYi@iJ@MvUg{+|dqt<)%`GPe!MH?BKe*V0f&2ZQD>(V+S=0ES$_FY)PFxM_^x%S>q zTQ7JEFt$AU_xJOGJ*6wBGce4H4QIHw=hU83&ALzT7qF>X1*rr{a4uFBlxVwK?I<*< zfXV!LL7$jOcETh7+4c4x&({ab-S~NY|DH#O`?u>eGW_|wyLJA*_709K3;O51>GU~t z=)^<`gIn4R?|7mm79OyDA)+DmPEx(1=wHkH|Iga8rq=&0`+wkZ`MoD+SD!gwm+Qi^ zQGv)w1u9*3Z{Hc=Qh!|fdB5hw zpBLBneScRk(6n9edHp?C#mOh;d8lyB>~rFJoK)$@x46H>VA)}ZhpfkgH_UG8xtw(J z$@U#gk|E^=FBU)e#J;oOedGMUw+zHJg)EI!x%QUx6nb_ZdHSfSRXpro@inWki^Xwr zAKkup6u14hH85~lrXK9^r9|Ysj(>W6?Uz44!oQaCGnAA}IZD4>;t9$p;&zlqtTdQ1@Ak`%-$&w}&&fP};((o++xj(AR_N)STbHq0TIo?KgXO0= zIUPJDDph(X-t6enoot^bYW>UO%PAFpE@5qPPg(9G(-v?XdvPMq!>v7VrH_dhi>1(H z$vO27cbGL&E@@V_r12f=WA&Ffw4*2bSj49jbMF~d-~TA8n$^+$Y|c`qvz{ttjM1e_ zZfp!pWbscNoi$=G*YUpjE*@Z9`&eL7Es}J!Bgkfk=s!pmURn7pZjxy z{i|gDB#Avn8IGOIa??vL7Ro(6GS5d%dG4vyBX1ZP>owEz)NgjO&Ww|FPHDRq(RO3= z!t{d`7r!(CeL>#5;<=O}tsSVEa7rYcG^GUq9mW z#;21lgyTf{$qDsmJn~NTE^*G?Yod-r_uVUL-*etF}aBi!pM zvhF_#?%^#?mD#FrRC1>5G2M)sR#qVak6F@PjC@AQmS4_nO>F#pqH12!pKWoU?Qeaa zE%B4(xpv)?`9T{Vb*W3p|71TPy2-f9N{lOooi9pRO7o2!iyKQ<{ceFJmTpEmEu53) z#9c^EaZEgT`z7anA8xzEby@W)KjP>A(C2&e@`sfF&P!c>i!OI$w!dyT8TY#9yUCp# z^DnE_Rg9lB`p87_^BwF{t`56+`C-iK6Rqm|x;`47Q#}^H`GF0u&f%Z=|2t&r9lxqd zpT1MIaAQjSj$;^(uQSlmD-_~QpW3(PN}-^4TiA}JpKgfRtZGfKe6%~} z-n%`!bAE?XvQ_fh1&>d7JYeh;1&?y=OmBkcPUzo<&TmZ&)6_Mv^oj4KPbEWS1I@Rs^x zoB_MU^?$~BNt)#E;Bwq>cYUMkIycR5ks~*x-hY_V`~Ii)Z?V}s)ZA6Csz$5b+h#n^ za*D{Cq@;;V+fP}Yi+C@sxMEdEpStR2E{5sCY;u0x2|)!*iWU?}*qAR?$GAg`-pML527f*CZOGhd?y<}NeH08x%i9#`>Zy`>+n;UJXPSj;T%_6;yKikbWgw?li{x?%gELLe z9y851Pftm@#G=K|I73pd@o|V$k>Y{QNLI${oLqLb)Y$GbWoDvdW0& ze7A0z_rQaRZ-yt>T9$uXHlwcf{F%`&uD0dQ>-G}b4e^Zq{9y=;L%lc-T zn8dNV-N#-C@N!I(a6kJnyU2-=>rm4~udQB_lhbP6$4{&I@o`#y&DS@j{D0o5Rs7$} z%3%NJDdX{3QvSL6^?%0TzdyUUESifL7#J8l MUHx3vIVCg!0F^kMo&W#< diff --git a/src/main/resources/assets/ebwizardry/textures/spells/plague_of_darkness.png b/src/main/resources/assets/ebwizardry/textures/spells/plague_of_darkness.png index eeb386b6e34360400ed0f02c78407d461e0eab45..e9f7d1cf8f08f6b0e1e8a0896c798433e156c82f 100644 GIT binary patch delta 2518 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 Q0|Nttr>mdKI;Vst0K*b;L;wH) diff --git a/src/main/resources/assets/ebwizardry/textures/spells/poison_bomb.png b/src/main/resources/assets/ebwizardry/textures/spells/poison_bomb.png index 116b079e148303f57e4fdab713d61ecd8eca4d07..51de80fd6631054b909e0ac7cb20d5b52b6be5dd 100644 GIT binary patch delta 2066 zcmbO(uvB1zRy_j<{B+(8VsI9CL>4nJa0`PlBg3pY5)2Fs>?NMQuI!IEUotFQmAeI5ILQhxoy6@TR8?GCJ5=`VMsivQ+%b#uF=3vUsw6thq?0-LpmfY*^ zu|2bA9t+ri{#-2=Q&(xT)KLl6jSn>I967n1LX21z9^`Lbpui%?qRQd)fyvdTTf#uD zBhaO#XerAgn{QFY)Bdd!;rZS7I8lKC~D#=ke!769Zm+(AVZ%1-yAft*hM~l$&+doRsp zI(h%t3!U0|>J_XD^Xn&a@2h;O#wTlYKA^T?1J_c=7dv^X+HJf}*IZj0e_(g}`OmB6 zbD#d3pLmxt^vUZ#_ZOW{9@aPCcpcD)XqLE;Bgf!Y zB*xPrXydOb(z@b&@4RTNh{F_+jLu9<+_YEoJs$f)xSZ9Wuk)I&Q<4_9aR2TB-AK&@YGGn zuH9EMFY=$-eVO|Q*6-gu_1}U6?)EyL@5LV4xx2r<*!86H4&FGMTP>YEX^XC$PYGeO z`88dNYobNxK98O>#ve%&_OKn=w6LUeVfn`6%fr7K#jM-#@SH&A!QbDnR(@4~T(U1b z<@AZDb$hcWDBo7r^R=-Pm0mS-sY$GpZV0>Wn~M`pvun+8C`whmex#e>%A~g4i9B_V zJ3jqt5ItSZ5njKYGkp8Wuq`h(%iXd((p1y1@$%!IxvQBch)(ss?&6U!bH^gj$9pEp za^BoiB>Y}>X4>o6=@)$_>ACG@h-gi_R8lpUbGpaOD3Q&Eds};7>R##FW%WXa(=s#q zN}0(`bE|`$C)uvv*FJc@-LfdUah~7Ai}75Z{oI=#%b(v==6z*uMg7&ET>>JCc`82s zR!bIFTQS&tJXY)yn)qO9-MxFF$-T#?*Y9pQ${)S1)@8>kAz{0~2Vc%U)~Q*_-|*5w z!Z!N(vGe@KA@T{&`zB{RQ#)0|(;*QO`*eA3d%>%c?rQnkS!csxE{AOP<@oJxQBOhn3C5QfG~T2?zM6XM>hoFm zIgWqZe$wgz_mX+i*50DojHa=t54^v{dvvD$9L=Qfm*qG8efM;oGgJPaVlIsh`6W#C zZr(b3R=S?w(7%%H#m5fE2lijB=1PR!3rP4>;dQO;*iW^{S3&Dn#Rge$I|!z;uW1N0 z3Em{~@5>9ruw1U0R`Uv@L4 zUau6(8=lSoDUon&^NJl!FD2?HX#@k!{MM8%%$aYt#F-Mw)Ugu z=gs00vjW}zt~tt}Cg8SL$~;e|>|EAyPAlCEAJrwYs;?W)I$TY7X7Q}jTsgeqoZ*Vn zzcQug0#f8E>i11DyIW?vdF!!s<9`(&m~)=-cmx$6T+6z(X_fc-t(7vX<=G1k7p0zG zG1)7$oNq&z!KCHQcZ`QxqV j86U;hJf2+lSKJ~Zd*dyWpl$|k1_lOCS3j3^P6U zc=X}pGZTh}P;cgWRrS}I#Ev@2-IKV^bYREoiJ1a=6H0B@9F$w36qxh_j%@B= zeB3DE>Y_2VTj7*&{J^Mres}+1<@i){l&nfD_|NU|M6HxK;qwt>>2UR;9b_SifIk%b7C+-2$BTKO!{yK#ptluvjzWwja zByHyKh{bYCxp`Zg7G4WGbm41c&CK8b8_(7&y-RC{*_v)?%M-6@32dKdu&Cqx zr+PV&1KbarZG~$}?>aGjTXuZrcUOMXru>BgLRMl*3hN^OnSD|Et1OqPKRb$3f;C%! zdDdCR10Ls^7!8}AYbMSQkoY1I`A~3bYdN3H;!lk6(GQJL*Im42{r>m#l@X?C?1^EXq)UQ)qqmd|?!|^g- zdr3q2{Do!y{io$$U#eVu>fHU5D~&JOtfuq#J8`dCow(oDZ(-7lZALlEEKe6NbvUxt zYH^3)ABPUFwovn_lJ>Kl=0C8v^!WLWYwA(nZ+9*){uMF3{5=onwfBdAZ@Un0GUt}b ziT!!D$C_51zsO%-b>+BD9LF(Xo5{;7*_hL;Seq*RuKL`&7!_Tq-E%eRSbdhE_50ScMJE0! zQ`&9Yrb!%XvgovP?pen0BWc1OwndW`R`ex4i0SVR;|b8Uytw1Z+RqF>KHgqD#oBQB zKf5DG7GG`*zrT0J)BCS>DTrxt+q`M)a6O#rqp)++r0hqM3{swN@+6w&xx`~c3m$H& zTQoIx(bQPK?Z$m|yXL>$&9~`s{kaLw`{(o3T#S{Re(%!L1M>a_DkYDPE}xnce*}~? zH|IA=@83M3Y?6;*RhVE@YuTk`LZTOaEZn_JxOA^Aea-k|LcPF#lM}P1PcsNBPFTG^ zj7=!jqU}M=eA%rtOmlDWsr+@Smo?k>%_cq~zTp|qz0l`cP5~`pa|{BDJ-+Y1SI_+5 z&DhZ>?IsD$BmR|3xR#|An++&()-9ao3+65{}i|egFB3HY4%* z=JO9nE9>oDdira*Wv8+HGM3%dJvyduY^r*m*U$So!%er)s^QFDt^mh7^IBJZxPJC{ z#OJSqYn;5g^b0=gKl^-f8`Ey{iaq;ZtIXeB*|fHN{*z1cOWxcN`ZS$a?z)Z2j9o`x zH|po{JGAPAu3^3MVB0O@sRE8iX6nz;d~`M4{$aI!KO|@>{Z(*(2k^@azQqz4wVUN%-Kz46;iT-dSJ#*xQG^>F>iy_&tsV&~b}5*}-x zzx-Om``W=HhTh8=Kf270i}tkcI(vfo^cp1_W(U1sE-j~P#p~2wYdvay-YhP0tF`Bu zXE&pd!kh0>F}ruYnsfD-VU=vhYtBsnlT``E0j4t~`zp_!zCwikM+-6yLPf<{f$bA`q`GulT2a?vK`lIXPpe6aXaNp4ny`d&GqlggI2ye$9Rp) z?NiBw=wnwHJi^9^%3+owrlr&hM>U?fvG@(-QWqyHi*y&)~mj z;sUqM$6<9}PU+t6i83|rOSAfVTr!*|V(y~av;u~iHnQ{gFZeT4&QHDZNBX@VYvTX2 Zo-9xJS6jAp69WSSgQu&X%Q~loCIA{b%Vz)p diff --git a/src/main/resources/assets/ebwizardry/textures/spells/shield.png b/src/main/resources/assets/ebwizardry/textures/spells/shield.png index 0b1588b4e2604498b7c2676290dcb6e3341b5dcc..f760a416e9ebf58e9a73aef026c1436b8487f700 100644 GIT binary patch delta 2021 zcmX>k^pk&rR{ehl28IuPv-;jMFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#xOjxP zS*4lYW-&0Zw|TlahD01bI^DY?&0Vr>{`=LdieLVJ|MJ~S9^=c&iwY;VY8x`@dmaeg zBp9x=!`Cd&h2^Y{$Q{oUtOs3Pl9F76T`#ck2$e1uFzBpLP{`m>G_rX7rNsYx{r~f8 zUlkYrd%5$=j$YQIjl~vMe(!xB{XSf^-!4Mx|M7>6dVO{^JkQOZS}`24(@vs<_#&WL6vxI-;YfR3UF*d}U2NJI4YgpJT~#|6F!t&OLu;^U>D3H%l29 zzTcIt_~@%RGd4bkrG9?ulgd6TcdyQl2Q>=EIK%=4=bSHKQex7)c*QjKI@6(F$Jq8) zr}xbGc;fF*-yV6!8#h1g`7&*iPNGtW7N2hS_#+^q~Y#tr2Usw60{@)*thI=bK zjhyE=hZqX7H8b8`?)P!-`@apYffMH6Yq_*=sr!`<-zBjsyDGW6U1CgHl#(q4&e{KE zQQy8@v)%bfbpUJVk)5;m6tFxvy8Vksa$(=WUslV{zxnX@dA;x6I3o+wB`ejAd=!!_ zJrcQy!?|lKV{Up$X^SS0p0@n$+ehlpKj@6NIX-i<^^|7DSGFGek9}TWew?u*%YJTh zu0cY2di(r+-@@HqTOKW2AT9quZ|jlFq+2E-(>(4?u4ynzzjMVW>2zYWVYYI4-@6BQ z?z8>*)4#sx+nLN$TTQq5&3iLbz>@Dl)YGT8q|(pNd%83H-UIpH@*C#FCjENH9`e3# zhfTdzLb+YqoscclJTA<>)Z!U!{3=V&kH6yotNoSFA264tC%<{h99Q);^xPav=Z#@X zuc`#L&k6_;d>?6F*z~;atJ?dxf8wWi96xA(e{pU8nRhjZ9QP(%y6VzcR^MM%FCN%9 zA@I$d#fy?d{1dfQM9)~>5PDbT`}3`Q-TCMCzb(Igum9GWyUUh&mDfD+0EX90I+6E3 zm#A$~`f-qmni5(;Ra*jX-Ea=4PHnK+H1yqjg!3axXM0Uu;7if4S=U4Qr~V-&w{v(B^~ zPdrxJC2A&qwp?4a=d{F;CIOM~DvjTZW@Q`QclfU>^yOo=gvOJt2^@>~-rFj2|9BuM zsuG*;v!l*0ee=Kl0ujZka*oCA&-gT3#6Cneax+f6U6EilSMj>fj0GooMGy3(xcRhs z#`jvex&(+G;r#qmX3m3wYrR(y6W<<=?xSnc9a~ilR!U9F_1^v>WB0Ta!KygVjjdDq2A=yvZ?I&Gx0RJ!|U{Uq6w zwKkkf%_mP-&^U!@@@3sm@A>)#cuwW?9z6a&@$kXl^_8*#M_Lxi6g}TNf7!{RIowNj zspV;VAUE-<~oqIjnc7ZvQg6gYX5Bqp>vJAwnzMe6Qn$odNHqt05 z*3oDWSDdJKXO`8%Xg!0>&PfyamKZ+Tb9no)Z?Xa5qBFj_-s5YSX*l2a=OOX;$&1%! zuG7=}V^yD++mOp;7w**aLr*X)L~Hef9Bn1jldfLzlO`|BT_CA@^WKWe2j1U}X8To( zK8qJL!GyGH3uT3y=cvvXSI(Lgjs}ECa zTE^?lW87_#N5l93P1SqpUmH|f4_fh=#m?rcY zy?}Ae>lM?z-P+mzytt`8G1b*P`$OQxYYRF#_`DN1o7iGZZk?Qz7InFA+K#f5#`cw6 z7hg=+wr}C5DHi_=3THFda~eqYS5M|xA-VGP3Nh}w&!4zct~rEGR-LfxXgTL~wHlLI zFXvQQ9WEEloW>IQ;gEj)i4v=&t7k7h`g_jK$`gzErbP0l+XkK^&-IR delta 2353 zcmey#e@JM8R{b%CgAD(bD!2Y)U|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifFbat2 z%D%}{`^mt-ao*F#F(l&f(doDIMXt*pw|{=-%)Pzh)wwkfladdxFey&(R^;Sd8dRKp zYso4n`Ay?FsJQR*>l+BSjknrZ~ z)UD;^WpD4^oI5jKKFzSrV*N{hE2)B3yYm!8`HKCV0@?#Qy>XDF8{*AzF?@D2JItV(uK%^eH2Ix$9RpDLTV{9F6` z9nU{Fw5@DCmCL}u|1Gk9Pod*u;RV57%v}#c1Vp^Drx;zlb;RV*kA@$-HHCqXl(zp1 zvr}r)Sg1Pn$y`C{wW9j=Qu~@enljv#oNR7y+{Aq`a`jUsB^8= z^^s*%=5m{oQKo&1Cpkj!*Y+(JOWzCHRsXlOvMT%ZSJ*z`#VH|q{<({Hr_RjoX4|QM zUg&hmgX`fd?#ywxBl;ox!F53sg?L`41wX5L6I))sz2%(!IxWqH`|AGQ9M8wDNng^; zJ|CLgpIr8B(JI|FdhR>FCz$`ddG}4d^}LkdrDva?)XQ3S^vTikmogT9g=I6MGTEMn z2Haw}|8%|l)t_Ja-!n0AIX?b5>t|4>y#43mBEiW|run5U?mn?pYSPJ|eeXX0sl6@v zCrPwNBXecao3k7CZ=S#1+x(?n0mtH)=kxa29Xs8*7uq_c8U)&Rw$o%ZF?7b?#edJQrRYFj2zIovmI<@8(-s8S86@?@Z_8?>-n* zE4A_p(^C!MDa%&AwPs}5WfpkL>ALKas73lWk1ahVarC=+VTFHNaQ@uK+t>f?{hNC` zV&1Nf_g5JVoD|RP|LQ(xnt}SSdFdZ==3YtSo^H+EBd(X!`uNHkgGaM8QW^e9F+6@? z_S*cZl+W}<8Olx;v+7gtuX`+GUDOnEUhPk#$n!S;!e3W7CeN>TDEw!1eR+H46|Rb2 zuDWE_^J|03b58xV3D@&;Ts-;4Je|*6d{Mh4ZtR@zJ^kFntE(-paw*sp`p>xJC0ong z8OF9uQgz;&MFO24cSbH>J(JXY4H!TWxT5dsNb!Tay(xA3o5v{Nh8484nNemKz%cdkSsmaA^4%z#YRBi<7BT?UTy2tqKTW{PRRWpF(WRi(2#$7Q^8`FB?1ETPySqeB7O0b zvwl^=b9K~=pM37#5vS~NTq$FzK-2nbQmu#drUtZ08Ynp_&02ES>w?CtmYnG;AC|Aw z^RIujyVp8o1KaYH=>j%e!g9J&JtsXVGHsumrTBHO@{ENBx2|a1-4n8MYwGmV8loDW z+03btN6NQco|n5&YW<{&6>}qY3GWVJ`Dm8L&~nPFRrfc)qO9k)Z&62_a-aOs66SW& z5ISzUSYvhH4ioJq3AfF>G%v8-+Hj%G^+eC5ox5gEsP{53On&V9+%tl6iqI6Hl({@# zs~8^bz9UgL{mUiZq`c0JH#RJnDYqIJoizo-&#yJADs8&C&ekMJa9-_! zMM+x>i%P{8x~M;`50boJ{6Xd*hifzQR;SknVLMs_Y@AhYp8WT_Y~z*(0%e!Jyj}C@ zK+T+qmm8C=wI0|N)v(~G`yRGlk16@;w>E~dK9fzk=WyL-*KfIlIsQVkqf@K$c&@Ki z+9&>nGi^$Njq~jTf}8qf(yLc>XP$tRP3*~-4g zyK~QM-TvW`w|=p%{lSR5nMaQp{j2|@@w*cX=3|Y!LFg_3W(u-+4=03+H4NuC={wz{cd;?4g`+xY^BD zqFzcesb*bYaLl9S_CF<0-q2dV|D*h_Uvdjr*N~x76 zcFpC#@1FiY@7c2Rk1JO@ZWGDh`z4S0LYvzk2c<>{C61zF zyV_jl+DJ`}&iyp=q=3?;Iqb7|yUZ?H^%xzF2;*MlGeuDC^48fQMyI#s$j|5dKRe=z zije8ddGpjKy;xvk-&bK;bDr}TTVb<{%Axi9rZfC_6_aq=>}1NOnZgcJ81g3UjupSY zTDh$;OmW(BZ;|?~j(*Zpy1Y9+HBIl_5VfcAy{SXY2ipVONj@yOHNJ+kba%|Lk$QT5 zdG59CnI}WIROK`rk2qJ(3bMQ}6J_GXxnjW#&P{5Dt!ws5@Om+s|Nrz-BA8orTb|b) z-NOlPHkBq^2jcB`Zmr!E8`T{p>Y-|}FS5gB*6;0xmt919GR}U|+CA^v*JXLW$F~dA k2A6SnRDM5Zp8KCUIo0UeC8qi63=9kmp00i_>zopr00|;%y#N3J diff --git a/src/main/resources/assets/ebwizardry/textures/spells/shockwave.png b/src/main/resources/assets/ebwizardry/textures/spells/shockwave.png index 49f649990e58e6f8693e7fc8ecb8cdb0e3987c7d..554a6e2578002dbbbdb7bce3f783b2540f57b76b 100644 GIT binary patch delta 2535 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 P7#KWV{an^LB{Ts5`~9vB delta 2431 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 Q7#J8lUHx3vIVCg!0M(W(#sB~S diff --git a/src/main/resources/assets/ebwizardry/textures/spells/snowball.png b/src/main/resources/assets/ebwizardry/textures/spells/snowball.png index a38ca35043582d8145224df86cfa79259405ce28..9ecb3c41fbdad5e45203ef3812c3dbfcb9c3e1ff 100644 GIT binary patch delta 1654 zcmbQv+sivatNuU3ItHGX*n2KEw9Usv`=Ts(sM zR&l51uV7$clk#+N42d{=bb5BaOt|c^`sZ_YzWHUe+wak>PU+}#OMRU~xB@-3R&j*x z(bVFYpmk7M%h8UBL(z`m5$^}ahA#020imF!VWJbZT@a`@wGfF?S9I)@y8bb5&$i_E zXYQ4!oqKrn-J10LsTIO~CbLe@yZQX5{r}e;-Qt_t{y*Nt!1dJqe4?WMH%Or_$pEO!J;Uth{&P`z7t#{GNwbwcjQ(z2wc*7XIMqRDVq3k;S{; zwm0Y3nfI9;A!Bsbb^=CQYOU-MLpcd zT)#i)dc5O2uY!Qnr1>))Bh9uwUZ5krQfJAgjXBb%%QnbPZ*HINaO$Cx371Wv14p9( z(^8Qjuc)dhLAE+jObOw%3)CG?c0}=($RzH1Y2~88sgdlXzrw06MB}v6O~3bXQDSeSM0*si=RUq+{CuO#^al^k zPHj3_RVicM+@~ZbcCF(un^l)!(hjkR%-7YeE>S7Vm(85<>4cx(BiR{GH!hvLWp-)W zbbm$N_S@n2kKMm_g#K!YtD%5j-EZkBIWTp-)GbPH~#vTZFA?| zv2C*Zejc8`DLN+oY481utHP~jCh=^_evnZ1mE*_0^IM)L-Zon|JF)Cvp%%a0Gwbzx z4$Tzq-cr*2tnqUFn>X(YcfJ(XlU3)tePgE1v7(cHeo9LhRXkT){eGY4<~YSZrvoKS z5gax5<&_jKbA@P&PDwSKIXf{gapLFa=QmcQ@TFRw@!Kt9YjHB&&+goG`|l#l_kR#o zTV}J2U-sGO_}^lu%4W>8_u4CUVO1zcnU^dR+mntnQl1VTo=d}&jp_@YwXQcRf2DJ? z$NSp5JtD{2G}!cC2khJ1)R%lMEIgw2Ij^7nch^H{b9-;gUs}O(Bv5)WFPm}7R}a=D zQ#e?rg}m5sw0HZz25m+AhYNUH47Y4O5Hw--sR_1Q7>*h2|HGnR|Ngj4R76t#>I3fb zF-te?cD=Ep(QrlHslG||7Til5>a~u3y8PT?M@3V?W45o%^PM=GvpF|$Et1&M7`3*^ zdT#R9Px6{~{+j=f{K@?`YU+lY4zE{4Z~4XS-@|dlj&)MjY><(1!I~=!3)nVWJ?_JjyaQ_nV;7U1L zfB$I8^1{BkPxm@azQa7fXlrL^Wy9_-nP#sI<@bEHnl1f(Mfj;7)~bujxMkh<#`rTd zEBtU_{T0jbLSsoF?~dZHx-lll=Uck3e)QPy`Hv6&`=5UZPS?D%*Y)2EPrH3T{Z~D0 zKN9=FFI|SsUp`Z{&8u+vT{n|#M(d-c>td^VUx(N0CHA--7hIdx?6lEi?H>2n@9URF zuD+0W#d_+whAF=t9v?WqOJU|+6#;j}uM2#32ReIP%?!9}_wfA`fuN)yBR&g<4#{#Kse#~J;xuH7eQs*g_zSC7w66Um_CC+9W%f3S4r#kUq5 zOg86VPhMd@qbC2*nFqiBc|7><+4v~#$WiXdx_@~Wwkt{=y}W?)L4vxhis7s5m%rm@ zCF~7JEzHY`Xmq++@X<-EAwDMWoxk(Sk2!ZLV^;B=+84L#+hqTJeZp@2S*k8;4zl-G b{S_~oQ?)4Oo`*OC0|SGntDnm{r-UW|W(F5( delta 1664 zcmeC>oz6Q!t6qjdkU?(u4$~V93=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgg~9%*4M z)*MqAZw3Z76;Bt(kch)ar$^_=gv%bQe?DjDn_ouvd>`HFjE>H`Z05UGY=u{Fpwfzp z%$*_=v|1*tV5xj0E5OA1u|r_`@=r`5HVjNEOFY(UWn|O`_%1o6xTtj2F^#}v%edp& z*7xq-{C)0>rOlgjRo}uorxz@_81wB+-TnW+`g_PtuZV#z`WhJ@7u zOa(gGhSLTAyc5b;Yj~`rKhT?_af;A_=Q8%+Yv(_g^Zxq4=5N8Y-kPTk3QRy?95DeqXBYzkH6^_j5lpT6FwS-RWM#yY`*a-~YD#oqRG` zH7Q)>YKN$FfWo%A8LAt5{&H2!YkywpeBXQBlf8y*;d9P&7(+|6gJDfV`WWr+;=D^V? zz_e5($ZOWwwC_?5TCJ(pJ-(?PsrBy`25JgznI*AyVo<@G#>pH!t$)Nk1UPt-Od6Lw z{kZl0ZwUv7=vRH^EmJ&F4Xgii8eQJ}CMVbES!%_no#K^`r_OI=NR8xJdBJMYhP|DJ zyWTEOWJz*J_PM?Pn1a;_rxShrspeOw1l?HYz4wvv_X|S5u35GBpDX^ieZPa2>xC7Y z>uWz-ZF?+W_WFg!k&;WL4GuB^$7bXOZ2h|;U|Q>@x$pLF(TTdsCE;9E)b-oGi0gFW z$MCE0T{a|763xg+qd2=;ZEI!Pk$d=tWb<4hJk0q{ENs~5m_J8?dac^PfyU24tCLW=|>GzVULVjQP>t)2AC2M%_wJtAA+GH#_a|t^I~pPOmvy92DBh z52rYHZaL_=bjFDk%j&$TPvieJEKT3<^X*~(#^Sd^VOdRo=jQr|Y^eOJwYgh8qV}^) zd0F|!-1hZ#|DV6f&)x9pmVD;5Q*V6?*=`zcu;0Cl#cQe1 zKc9K)Z!D>qw=C~cy+z5Sy?>cb_X-_6#O&h8Z9Vl^gx<@Kg-b$mV)vhV6}|rQim9E4 z7!2Mrh&2VRG;wfJ6J0Uow8rVA8m-f3?$|8%vpxD}qvVvQ2DUGY?msNF`}JUN&A-R} z1)qZB6LJnEe>xFp_i^d^#X0S7-qc>vvOAk4S+9RzEy02BTdewT};^&ui4k=T!>-Uz%ed|0V<|fUP zcHq@QE)PvX4xN=394CMO_fI^AbEYACu0qFxrL5DMR(6WKR4z{7+1$s2RXoo<_1l`|tCmFbt0iv?ezMnZcHmkPq+|C@r2TonaLzvWw-**`Bo^p8Mmb6} zngy(#R;a!_BKDv5PU-ib=TEJ_uqup0s&osVwd-p04@V|Aya`mWE6cyTWXJ61r`RpE zwpwX=U*O?!OvzvoT)$2<<62fo*Kd)$`$>OKaUHGc3)|}@!g@EQyU}ZD(DsV2yBD}O z*6(l#^Zvc(!`%5n`tLSMTkY9jHalr)W9Yu#-5)G&Z|x}8+jHvMGvBPIN=x_JB(Co4 zJCwKXc*DN;^(&b6>M@i^1g!t@=SlYbl$TeQ7w-S+yl!71V|h_m`TuX}eRiK%c1mCW zaq8yupBK6NgEj9dzG~QR{aB&mlZTdJK-cZJW=jIU*5AB+>%pa;#W6c83C; zvSo@y?ggtiC-{O+>IE1*`hD=}ipmEwk2Z9_K6miMQst(!k_(E-;YWpq-!dr++x50z z3EXu2!TsNNj(jM4Q~BF&-t(^>S7d$cQqnZ0dO0`#S7+VErI_xw{O8r^y7O%nBK}Rs z8vf4RGXKbi^-JH|*&lP;cj(WVBMX>zE_!(8r3u6SxI7sj=gyBgS1LnReLcNz;`%R> q`uF!GyOn1jby@R|y}bIb_=@g|2U(&^@)#Hx7(8A5T-G@yGywpAR5qso diff --git a/src/main/resources/assets/ebwizardry/textures/spells/spark_bomb.png b/src/main/resources/assets/ebwizardry/textures/spells/spark_bomb.png index 1ea4084ba99421b526fb3a60221f833b219eae21..80538999d7d0ea4dbdd7e5e3dda94ceccddeb8de 100644 GIT binary patch delta 2220 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 delta 2147 zcmdld_)TDfR(%Nr1H)N?BhIx93=EtF9+AZi4BWyX%*Zfnjsyb(1AB?5uPgg~9#MW3 ztu-x*yBQcbm_1z_Ln00zonGA&lPYmrBQK}|tf-oZ+f^bG4AwWd2Y@oqO!kno=UZpzCt z{o=H;w6e5wm46@4o_jaVQ0m}Vk;HISpxH?xsb_+`RMN{s zCseGvpQT&O(e7ieXZUeSrhoZ=%@wOm-|bi-am1ow!Lgp^4~sg)omVS2L-wI5=@#|H_3xM(ZgsXie?rgN*(+DwzHotc@=viyZHTQ<(`Xn6eT z$i7=A85oX88fUz5I^LYYojdokV*O3W88aPcymY&L%Ts^%)PA$|if2kDzL?eBx%J_e z)CG%YKia*1;mXVoao1i(L4&rC>gPLpCo}X^_L&6i_OM}`sn_(fcxCCiv=2}3^6c9( zc|o$;;qzgC<%{}8>LA9egd@^Ic^VgF;spzD8{JZzu**u0-T;o6!=o#>5SwR?BJc>Q`aBin|LX&uWYZf)$#)PBdF z@S}C@lKnd*j5qep;W&`>KH}^mLzR18CdP9suIo$+zt^_^v!ctAOpEFd&fmViI~2RG z@kF)$#ZPw*PbrG5cge9TUwg~r|Fqp6aodE_KX3#|=SqpsRpRJfQ=T_8o4Lm5(bKUTswQnJ&NV@oxL%g70qAV(Pc`^xIcV|2OY_ z!JEH(FYM;_k^VPtZ^dV^qAv&P80>03sD(^DbG1CNY1Y(BVmaDZSvb!ekuW%>u$AlN zW<7<%gQh(;-wjrt4u8lJ${;pxD@XZHHmzcX%8TX}3AbKwa^KmI!pZP=s#JW`mr{m( z1?R)sw%zYHPUcft-k7YtX3hoC`q>PB_Vh2X_$syTe!ux2&XwHjmG@UCZ!SpTuRCFF zef`1vo89}<*Do#j$yT+r`AB6t^M`A%|1%^!Slm44(`8MUK|;%bj`)|0bpr2KB1 z-1hYMb6)yD+(1LCx0YZ2f82D=r^#QJ ztlQW9$N2S2oA*H`D<1LlD)GKI<(QRexl?G>-vb;D9n;(=C>-eB`e^@#)@%8(-p4c3 z3x4pI8`VFJveMtvccLfw#qBEp;_fe@+l}`eHd}Q?)&9`x&=2+OYzk}4zu3=g{Ajfx zi`|n~k;g#lK~>-pd4-FcJC-yq+@70$M($nmmEH^6zsgNIowr%`Lszt+^ZW~S|B9^i z_s;zDdA0@*->rkDJc=9&Tkf5{(PHAsl|znaycM zsKOe>V~!2C4g~r<+uS3!o$>mvFK$XdWtLUQ^tk_?e*SpRw24`g^%Xa+{aMh(Qkq?J z#`3Sc&>ZXKZHCJX&$A1diFGM{>A%T)B;e0)v#9+$=S;kJHltABlyZQK%cs9T>UY}x zIrvzhM`^2(&=rL>(d|+S9L(?bs2GM?Z*$d{>0`EN%R!gglA5;D-zWe2GqYly`>yA! zJ+|_E)jHagzdUhEV8$E&PM;3Vz}GVj(_T4EkzKVpsc??2{%@Z-lP8W1VW!Pq|m-R5FVBLu`FFPkozK{+J)9GXW@IzbF;Uqtw z$^X71nLZ{-zjp~<&UxA!lgA_|!rQ#;Sn?M6bE4{o3d!}ylRNCzCi8SuKkD}X{X;)3 XwLw=+u{(x=fq}u()z4*}Q$iB}m`VH< diff --git a/src/main/resources/assets/ebwizardry/textures/spells/static_aura.png b/src/main/resources/assets/ebwizardry/textures/spells/static_aura.png index eea54a25e477703cf8be8b4e780cba75aeeea30c..693a711e4c5a0bc11411bbc7c2b839b90bf97cac 100644 GIT binary patch delta 2176 zcmZn^oGds&tDXS_emd_4F*pl6B8wRqxP?KOkzv*x2?hoR_7YEDSN2Doaw3K@kN+|) zWnkb?@N{tui8$OkJ$p?|s%YE%t@~`N&(E=(o+%xzA=qpf6Yas`>a-(-X(j6v3B?Z9 z=nTOLO>W#$_8qcB&??UtO;7GoNwd!TZ&*mugQPSo8kOuX|hG zi!#|R6$~rnOZgkVG)q{#k7W;8!p@NJy+WG#*?BF4{fly{eLti< zEM;qBzc}xqT|EO+hsA*aha&-kEY6`T{Czf5B=#iMnA~G~u){g+QPpE&o^Tr38H5T0Rq93Ii z-F7nfUG!o#zVWH()E_VXszCMUpS2GbUvZRU3^6p}Ut?sGt{0|}+-kIA#!ENhMJ$UX z-Y3P~uTze2Qu| zI(j(ZpG<%LzKN>Y@{e}%+9zBz?f-Oc?`exiTT*xY`kk@4>)2tL+QKvIbXRw9_Z>bL z+pn^C!ZpMBNsSg8&-*9W9hQICYja|T zo=S4PfavbEcNdmSW>lMUX9shygUD5m^?gUf@10!t_WH*Ea{?cEES%6Fw!o5cU+W4b zrm!^|KL5%uytGSwVoHno`&iFga~|%54 zsXQqrac_S8ojS31TYq18wO=9oslL&Xo+np%b)r65m+h_pB2u_SX4fOTl1H&~p2}V` zKl3ZSt89XY`kz$~WL_m55uLcAWe1afOu1J3-xvNn(nL?rTEQ|;oZ-G(bg;o+L+=R>F7N1W__Hr+?`xgvU_*(? zU#*%RvK+bPku7z7mGWD*`2F8F@7*gA9TQe(<-QZ$j+GMY10ilsdS+c1lhDD%IqER(W4)N};M`lie)UY5vLDwP9Q=LBc0q@eILAGkMQsmfuDh-% zIKk-ry;?hN{aYM?onN}|vxpyz&#&i*QB+uJ_~yrIhaT1IIj)yHGeRbY*^21QtIBOM zcwwETS(9C_z4FPQ6uBDdO=?R_{q}xHUowBMztu;>3(vmZ-rvo0mTzT;&=QMd_swGu zv`6bVR!CfFZ95mWVyock1L?A!#us{SY08Ci3P(E}EqF9hr*)>3iCy!SV|~%nm?yZ@ z^Yyj|h=)wr)v;KwdcwtpGydDuXs*xO$#rJ&y#w1<`iBUYGg#K~k)--0({?s^Jm z(ls=vS!Vb-8=W<;s}WzH6L)r^wt4H!Wm3CN@#Ok`I=H-4OlLRm+JDm5XF2`h3BFo* z$mCSf;<*>aZv^aKaUwWD&anScVUmT>6rQ8asWSEZvy83tBfEBJh$K&0(Ax66ZtoP< z`};*#zIR)0?>5VH*)e-&CoU_w)n8smD!+ObuRLLofZ&1TX{=_&T{~x(Z(paXcSNS} zpKeB>$Vc51Q64eRwrIb5a@04x=+mZB53|D|UxPQK8T9eTsxm$MT=K(F?uE#Lt_4Y! zuRd%@ve}!dTOV)tJgd*5TK9Z@MB`b@8S4Kwh+03$$oY2Aruz2MIeR{_&D-%;-N(PD zIlnQ#{J!v%e*U)^d*3>T&578=zsgZ#&!4cy2EpxHq<-z6yXa9dZ_3WX^RtXkaeVn!-{f%KZEsj|N{NZa z^cahZ`%PuCYdC#bdpB-5HfiZ}<-m!@-^ZT!Opj;l)mkDvVX4Qzz>jyEUQ4{^+rX!} z)?#Cdd|2<@$GLr$D-QhCH{1P-LD22ERt0mRUW$+MtI53z$GML#__;|WiZ{czeL{C> zw3M_--PuWs_ih`XZ2a8DZeFR}a5wbvB4Hti9sidyEHN{*V^|S=D3UqKaSw-``g)!9 zOKTpK_1<>4anqWKf&HBHy>#n$ddqlDtvF}HUuCbe;NkjnPOo;?-dp)?@Ak)h6Efa6 t*M^t;a`>XZbkqC0%-NRz%T3vT$Y1zBp?t!NpMs#ahNr8a%Q~loCIEfq_~ifq delta 2158 zcmbO%*eEzbt9}*(69ZF!y&kwgM}}8b zdDD60T?`Bye4Z|jArXgm-VB4)g0>E)R( z&(xl+om2en)8U<;+3X(qg%!A4B4SSUp z8Rq87#jZW{ced_1%`Tr73I5qW$!qwPc4!=FWmHO7+b+Qz*x;tv zyvcm|i|ZGda56mjQ7<=tf8I8YreN2j4?-MxB=|j-cszMF>D0M{65eZrl-7hBBz^d! zq9hR3-7-~aT^yr`>&a(PH#V$o=qNg>`OoCo+v&Uh&h835v5dEW?_={x%*PI|T#$6| z$Bhu%Yc+IrH9Ok4pW`FM9iTY?}W4ThE8byRQ{r z-uwFHySR?)SK8)hI{#6TkZ)&9J{Tbq@w>=G+976VC#$;H$4N6%+EPBt^x1w)soV0) zNbkojqbjj8>4#TaTYlc*8lokd7x$ZGVmHU32?scr&#%#`eZKZU+NKA~10FYj4BYr6 zD(bOJy;ZXGF$N#ze#Vah8*jKs=}%71w|nB>pL@*P?Bm^H{|E2f#>M)YvmQThVGlCToDuenH9v2BnfHmDd}?wmX5PJ{VBNb z;mmUOo%wek$9(-Nyrb-_>5LU^AB`uxeGq>*IIzF>F+jJEkUR@4KjyPkiqFrkvk4aW^JDe|FkGIpMw1wwzk&kcp4%d@R~{ z_Vt#0`*`r4;=2FOR@(fEnf6;=%HfZR)D=hB72Th^mM%OoQ_4Vr%}{Kk-6M5RlcyC` zx7}rmZ!n3K)%BHJs()V2pYvoQuYV%jHpQ<(tGdjziUQ}p|Nk+QDRfT73eN`LhOY-J zge{Y{*|RlBbW7;xHO@ccZSrur(UV!1)>!@K_{Dx&MnZRj{4HD8-Ax?@ho_2v{_v|e zgz5NU{eA3pT$4{I)G7JhyTQ6~<;}N@y zvBAi;a-qQHi<_tT94a^;Y%THg1#?rBXz9k+oK71f=49N=5nMEd>*x#x#z6PIVQFhD zoR-$dJm8nU|NPv(R)g}w8oM(ddP*l6=YHXz&iN`d>#AW>6>IOI3h85EB9qtuDwOIl z4blT1xutepo6Hg;{V*Pirt#?(32etN9y*5I-HvOr{!;Kq&CE{{8e zUxz5qVM$Oa)0p^!J$b26qQHgX0_(6T8^WGle;xO{y8imV25-HcQ=E31MegL7d$-&2 z6SuqKsy+AZPt4-p*K;s2kS9P(guz_*rwMP5zy2z|f{5%7HmA$0rVCDZaDMhZ_rqGp z2OCy+hWj*rb{PXS|4QgVfVGX#FGDVT0a@L*s%qkX;8GA)a&z| zF|sl%>iF>|;=hb}d!@D*cJ;g4%vtv6L(Lx_?wj8#muxDIsJ%GzPUU@Pp7%c+yy^>Q ztgvfa-McW6cag$1QNGIp4|}zP7&gCWJz6s_$D3Q}mW95|Dn$!d=l1Sb83B&A@=aVz z3wjn99MR9Oo%}0eVpe6#iYO-WMsBI5V&P?G2M-+odEnl}2~)j=@BFT*`*cIZdEHjt z(4!e^1eDwpOC$ulKMG5n&+mz0)LU`7{G6s?bDu&|on{45>5L_K5vu9QDzHhnKP kM?H4fGgH3i+UxqI?1%XNGQ8Qzz`(%Z>FVdQ&MBb@09GabZU6uP diff --git a/src/main/resources/assets/ebwizardry/textures/spells/summon_iron_golem.png b/src/main/resources/assets/ebwizardry/textures/spells/summon_iron_golem.png index 8c30b0829ff8b1d7e3951e60568c42b95341496b..bcebc77d797570ba0a4d48967fb1db9cd88ce85c 100644 GIT binary patch delta 2582 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 Sugt)}z~JfX=d#Wzp$P!C^XYs5 delta 2466 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 delta 2108 zcmdnae_mjMR{bmnCI+Vddcz(D1_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmP~kBk@_ z&-Npx!VC=TcRXDjLn00zou1t@<*MZI`tz0g#dqgMPLmZA+n%#BV5^oym{!-ikIhYs zbhl}&SbIt;I#W7VDtl^_PiLm-(QDVP2{}Z!X5{crb$e6ao)w}a=<0Y%b(@!qW7*By zcgo7s?tPzAS8;#t-Bh!hCF+(ZW9y z{p<&}u+5&f<-?mi?zOyZE8|>P#T{5CymD7Pn6BDzQG@Z|0+vrZWxDqz^&j4uQO4}P zi)%3p!>!vgX79HdaMa(D=+W51+0eVfP{pZ0P=)1NualDAv5kRol5eL9h$MI{lfF@> z&@M55s<`!Ik@Z3|t|e@KYAem0!K`5&pupmOQ$l&cnm{3?83Bxiiz9l2EuR0el(8$B z5R}MZE!P~xx>CebRej>yw@HW3Ia=v&TE%kZ#+(r4kT8LrMF!KF0}s}(oqfe+Q=(C4 ziE?L~T8E0_q(eJ6Rf3M+>9)S{=|tAPl9Qqqxy3g=ygnX~e%}4ovkh;yS7&ys z@A+6=ZSiZP7ZI{YyPmxiRB7VChjdX7W-n_pq{hlt*6mU&pqQ;~wE{_Luq8J0i91au-STmJ1O)C8OdiKZJ`w#HvN1wXP zzve*`_qpW1^W^4LJ{MNAZZoy7-oo|o;lEg(FEZ&GH;+sxI?%iM)imh&sZ)P;H_l9Ves^-FSgqw@Q}h2T#P(FG{oQC{ zzclp5}fTw3AQ@v?at7CcaLe8mA z8-yK|1h;IwFz;F0=VhOMt@^nnb;ir)<1cQ7a@$Rrb#Pbi`@*Nn(UlMX`p?)|CS7;^ z`HOvWANCg1onT>^;uIM+wWUzzO$wLx-Hsb(%R-)gQZM`P&He6{DZ5v^whm#gJGx1< zWNDP9&_Q{fPwn;Z9$$SQ(>33=v3}i@0JS+`MvRRydh89UthKkcC7;Qie|*0DFTIJ& zGH-OM+z#Ki`Q_2@m9MP=nC)(qDT;5Kf4+HpeCsJ6XVuF#_bV;$-~M4_b-g{r=F`ub z72A9goOoJe=I!zfoFcU4N6m+i>05mKKK@-F?~?62r?FAy>+x^b8@B81nI-D2_xRfL zdj3sMqlMv&P4 zm?!4a-xXTpG`=mY>37m&e^L10v9Cm)ev-)!v2ROwzTc}9jt;+nreD5diP@(%$u-q~ z4Z`P@vvst)vYJ0kaE)0KBIEligW+-pt+p`G@rX#K*DMC-&`*`TRS)@{{S0$D7Kg z{rzOQ=im9jpK?9+9Y0jNZrWWCy%6W{D1^o3fJE;UuM79j7To8|n0Kgt-Sv2;gwONq zypJC~U-D=`3>|dF8+6GsypM7tZ_pC5}G5hBqhn+QY9i|JcZ+bdi zaKDh7T$8l?MLRE^jQS+jDI9FVv+A7|`_5cseqvYny|mlSbLUttp80fth1B~O^&i># zn#I4Ac()%jvf5+Unq&Xsltcl4>$-KXlYcjq#7P+|XMgHb{&-*o} zS}$OzvDomZ+?fEm`(=i+61p@uxU+Q$vMA0!-x~PxV$fbhu)leptgIF%uB5cR;rbs zbU5yH%;j#rT6s8H)S&H-L;Q{vZQU-VGX-3FmpPc8nUN)xX;x+O{JVZ%XsUd5%9B!? nLoZ6^3Mzd&X+P)PXZwAsi;eSdWV~TuU|{fc^>bP0l+XkKBC`SO diff --git a/src/main/resources/assets/ebwizardry/textures/spells/summon_skeleton_legion.png b/src/main/resources/assets/ebwizardry/textures/spells/summon_skeleton_legion.png index 7e10c45f8d35e755aab4a026ad422bbc5092e9e2..03750155a2e0a80e5ded0aec1e50adee3b1de728 100644 GIT binary patch delta 2142 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 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/thunderstorm.png b/src/main/resources/assets/ebwizardry/textures/spells/thunderstorm.png index 28920c9a59cc80951f11a3fc598f6fe9408fdb5a..371daf99553509ebc95fb2a8df103b511f5ff001 100644 GIT binary patch delta 2577 zcmew_x*n2KEw9Usv`=oN_`u zDobbenKLkOuJv?r42d{=bb98LkfWjv`?r_xfA@V^wOHHC#FRjluFk-|&Q8HzDbr3R zcjiZWjD@^fO-&6lJQ^!9db)PxGnN;08)jMP6*gwvc~rmP#0e|oyJx=K`}^x_^ykBm zXPgwMpY?mW-&M=d@4LTWTU+ft!_H3XQ@x1f0`32Ijkl<_p62<%Yn!8 zS}vuso|8BZPgt>T@|yL>zuLGsCX{RSuF4eg7FBUwXgG7p&Qy+dk1t%m-JN^;N{;mL z!h$T*WBs4lUi>^cL#5vOQtFZaORQ3s99lh})#mq1M;*E2CcaX$XL($?uB;HCDfTgT z`mET;ua=qzi!R#H<=M;8mt~X_VZBg6`4rbwFV^dyGjg(&X8L>z+&1xhkXn0BNQUpX z+kbf-vV)%OJX?C@`t`+GQnQu?uKfArlWUB8)a_drc!ke%uecU-t8HttdcB+Qk@kjp zDp#Z}|2#h)DCE1w;E-y#uG+HW9WF{MqFVO4_q$y-k*hfUviv_o!?u=&;MET;_#6d- zN?ex3*I0&{c4{9z!O7|N-kR-bj?x8bjR;ef#f_H6`U*X2D>(w)dL_NXa-S~pPA@)x z%3i2TsBCN3s+Di4@sY!M`)xo+|G zdecibOJ*i6{3v<}a!6`$hKC@9&w_yO;4-t%4E>WgQqt=G5j zW;Is(c;Odch;G-K6(?r(UAoYwa%zr6s+6UD({uKEpPApRQ(PUde?2J2aO2Zaahbv| z`Zqp&e6FzaNshxM0aZ>@sl=z;?~4yFT`s8f=}Ma}&;8SnFFgGH`H{P=&YWM_cf2}x zmfQ3_G2ifFyYPgRnK!TNJiWyl-u&LM`q;}WS*DAsnNFk`sl0N%_xi@6C6m=Zeb~Hy z(GH;;Qj7$?r+aeZk|C{m+6*i|{ZQqv?UT(fUzEsaJG~w7K z_7$c1hqRZ>uum6jntOa(?wlyz``;Op6&&uYP)?e$;$zjk>U!zZ;<2tKizaGckJ$6e z^o~QqP2=~MFWorN@onLjt=qmt7oK5!JLgAp+NaiwG2f3!#}qy~*wR$rp#Hj|h$pzT z!$noZ^FU$js;jRO_>b^5a|){!Jh^!MVT)05es#~P#|vln-mxh*@}5`G{&Tsk-==d* zyjqgok26#}^zP4%Y!BM$6K{6>!@}M>o8INF+yBB`=g;B493L&()C`n@mP|MsaN_w( z&!r623Ju~cdw#rnz31k|Ug69G8|!sh0v!WInhcHvJowo=w@1=;(lbS8_LQPSJ;f*e zr5hfusoUP^9=}e2g|YLOTiTogjWWygpI={lWFaSd+DYKZ!N>{c(^iUpmMOhpcV>2( zQB#_NwC^3GVj=T&)%?n03%4FzV3=5Nt#RW&W-*!{SrXS5ZOSN}wX0%E*JI_B-4UN(EIy*z?@~Ky-n(}P84?8+ zc_{@(rW{+cc*n18rWH|5rrpan{rK3cGp9%*=*olo>B&9+SN?g|8)^6c&Z%W*Z$}gz ztB~rEXna56^fS(E(IW>Or>WMQmzH6=Y$9QuB@ympKXv!@HAhdD35o^1@%XA(VaC7a zeL`~jv*@+wr=LnOiafPc>GQkl*0(QZsxp+13$-M6sC0>ZX6`t7q3t|?;l zY^d4T@jhhc=4Z9j_HSv;(ewBDw`}sMFYlf`oc_=8*JYSZ#CD=vFJ<9zP7pYb(!7! zJAU1Y#)a{s4bpM{CdJ;~KH0ByBcc1Nq(AD#g>EEzuI@anPCYUdEY}03Tf$J(ctC(^zHo= z_h%LFqP9oVX4=0D5R2X2@?yhAAG=oy46ha&l>Xs(cJ~*@%iQRIqUZ}(nl~E7p0W8G zUh^YRy1w#dDpzf2+1nePGgmlIdU}vy)v`dX=^HO)*1H5Qidp&KNwvTcj>4q0XZQ^*qfNzI(ceu9@Y# zY<<5^zW%<~0&I4lpT(Rk&X!+%=`ZW;{cl`?Lq$B@6jWxPEcpEBrqA9CvA)Lv@$vWn zpS+nIerN9I8ATiXw8Dc!6=D@B$jO+4^jbNZ(pVKb99 zdYt{t5i>i<(Es|mxhE#|=y=_!FTdS;B}aO7kYiw|*u0SAeI+~P9Y8IfvZv0wisSxo z=Xr3?JhyGzmVm7~hYVEmW<1#>X>(s)sE9QAC&R1Xc`pdg} zy@?VLQ@K8?*L>}%Ut6>OnT7SGr|TK^#r@EGnl12izxclFpXM_cMj7aR_RMBr;9_9# MboFyt=akR{0E}Mw>;M1& delta 2801 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 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/tornado.png b/src/main/resources/assets/ebwizardry/textures/spells/tornado.png index dffc70b2028e3e04a33546f43cb07c8bd832099a..737a6c2b962b5b84b9022d744c530b392ee9ec43 100644 GIT binary patch delta 2307 zcmZn?oGLUytDcwP1jDSpt%q_L7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=T-@Ru z(t$RWGZ+{+7J0fjhD01bI^DZp_IPF6{8y`9oqkztUz~PA(Q=VSz!Hu2CMJn(jK@!C zacuHw_`%P@IidG|(|^A($8U^#43pSD^j-jg#pG?v=MHE-> z_TL#N%<4X`e1^FAmp12T-Mrmbg(R21aM?WTtbo_0h~qC8sa%`1YU7%)?7E80m9K5> zcbPvp`tlVo!-4Pjub-%&U4Qy$&A}6q+lpLcbZ5+!-Mn|NcfLu|-dhv4OFIc1S|q2)-QTR%(!Tk1O81QZ@g8{R@bUL&*^?t3760n0g^gXT zk&`aHExB<|PPy@>*P_jQhsW|cGk`y9!= zBIA3}BbB8y^bPA;uQk0&YFh6tS69+rU;X`^^PGi`XGFNIF<0&Dn0(pT@7(g5UoXYt zYku||v%K})%kSCoHz)L_c3p^4NX2 zerDQMzdnC++}aJt_GT~mG;c%9B);Q1=lf=gKi{&;_Sj*@rUU6~*i%VO#cCBAqZzg~DPVfHNU%M+e!Hrp(}oNK&aqrz-fQeE_=w=-uz_ z8{$5E_?P>k@m56F&!&S*9{f0LIr*~iv*qbiyf%M7sAtu;;n<@dH5Z22+ZpSpOv=y= z)KV&4eOhP^`@SUp`PD6RC$5y}b?`d*Fa7tF(!&QQ*Rm}(%(H#`Z0&6sxjjp+zMJsW z(sNPe{@IC-B%U+-J{1UbXwlYM7}VwA;<0qYuH%=c+br*&(p9uK(Jt0GCg`@qtkjgk z{=)de+8fVmj1F3#e=ql!aq70f!1lFy?e*f5HN`)(eoX3p%X1;>VUw!K#oY`X6TFmK z6ebCtiuMWJxY=Ck9LwoYw^=DMmj$h+Jz#zOR`9Lg^w-tzH{J}9k(p~4zs^!C%|-7* zUiy-^cH);cFPU%I9otmEQt!%kYSWUb%UvcO2$}YA?d+1@k}eF4f;ORsOD70U-mE!M zXid0v{hOHE%L2M|PQKVKa!B)>KF`63O?iA954p^$Ti?sir>UHxa-UVeDPWpvp_H;q z%N4=k?f$3lE-4h-eQ!dh@0_f6_B&2zZBDe+zhQ5=(Dse-t}@x^$gIaFLR-9p)=aYb z_toz0$A+?b8#S|A3hM7&+0HQMbHjp_*_U(_eS;4@(wklXMsvxBm-b&~)TJg&HL#vD zF;!FP+=Yxd`PdJSQXT78JMX``EO1iNHkIh`ocs6E-v9gUu~M+qm*Jm3+kJ)>fr4`f zQx`WG@_KPko7}dy-%8}U>Ehd*mzzyb^7=liep8nJ;njx;b2B_%^0FMfc(dhSZ*1AR z-j`+8Z|=wlxK7%%rlY>4L7?DU7mvm3k7f_n9GCLun6%1h&#mtVKJgxz+jG?W_%xB6 zm1c|E??1k}|r@Ior_A>51tZBCIc)}f5ZC{2x-+u_~GyKcfP%igeX4yuUz?R~9 zUz3jh+VkM)`g?aa%rPn1mK5i!HYd#ZiQ2&vEhc9p&DVEk%s8w2_nz>Rpu~E{%T*o5 ze8JJPjwMKa)@#_>x6JTGgkp=rj{_G!8-JMhFTuy|e(J`U;3)5~l8axNo}1kW*sQSZ zy1bC;ESIp7-LYw(kIr`#i87VQHar$L>sz>pQnpT*=d5Ef|8!awT=tr{y?o~S>_s;x zWdsZSJdl2#Z-;4~;Odrl746d3^9n0I)VFBlZq~ECcI`=J`?mz{ncob=e}`PmopmeW ztm+9-wm(Z-Z#}T(VDYp*&e{2S!IA||hI8kA{1{(z;_vSA8@sppMoRztz4`pfDQUS( zc3Wnwm;Q87?4Iy&%R~m2K#|7&fS`%XBwwFpQ%tt| z@q)3u-u}-7lc|5+omA{>%bO-plVBGswB00nceI9T=A0u|{;{SrmMvVzb1dRb=<)}P z|I9f)J9iFO%P%ADpe8S60m0QvUE2?QJSkbeTiDJ%JR)1;*|e(A3$pRc@5(A{S#s-& z#!`-$W%s1KL(ME+XJ#F?|No%NpTWR(e}akJBsIfxRVno%icJcBNyn~lx3Hi4pqE*x zt|t7$QEhkiz?%Q>|IJenmaDHkAwN$}NJ*k+SN!g!D|N3~yjoScTApP>{m*&-es0<| zC*t3;eGkmpO?!8ST)V<1dc5TUCu7PIgKL+=OcgoAdY4_lzwGkuB)k0y6S9LCkFP%; z8Oj^v<@0#Mv7qqjY&HMB9&Z$1u3hzZ#?M`qw+~#@`OrV#V!;#pc_|h08p~L{v|U&x z?#NjyKR4r1@sHK~GTqCb`Op79t?XXi9FW(x)e1_n=8KbLh*2~7Y5M0qp- delta 2159 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 Pz`)??>gTe~DWM4fR0qHq delta 2505 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 From b33037fd1b42171c51c326b5af376d62c2b00f4f Mon Sep 17 00:00:00 2001 From: Electroblob77 <35599699+Electroblob77@users.noreply.github.com> Date: Sat, 5 Jan 2019 23:18:52 +0000 Subject: [PATCH 61/68] Missed in 1356905 --- .../ebwizardry/textures/gui/handbook.png | Bin 17760 -> 12848 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/ebwizardry/textures/gui/handbook.png b/src/main/resources/assets/ebwizardry/textures/gui/handbook.png index 9e8aa947e1cc51492084f06041de0c98956a5ad9..67a4415fc2b054caa0655f629263d088f6cea0ce 100644 GIT binary patch literal 12848 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

  • Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only * has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. Examples * include worldgen, mob drops and commands. @@ -38,7 +38,7 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage; *
  • Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys its * own values for these, and changing them on a dedicated server will have no effect. These are usually only display and * controls settings.
  • - *

    + *

    * Each of the settings fields in this class is marked with one of the above categories to indicate which it belongs to. * This in turn dictates which logical side it should be called from: client, server or both. Do not access a config * setting from the wrong side, because it may cause unexpected or strange behaviour. @@ -46,13 +46,14 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage; * @since Wizardry 1.2 * @author Electroblob */ -// TODO: New plan: convert to the @Config system BUT separate the spells config out so it doesn't break stuff. (Maybe even -// make it a JSON instead? Either way, there's scope for then adding more options for adjusting the base attributes etc.) +// For the time being, I'm sticking with the old config system because @Config doesn't support custom config entry classes // @Config(modid = Wizardry.MODID) -@SuppressWarnings("deprecation") // Used server I18n deliberately; we want to write the comments in english. +@SuppressWarnings("deprecation") // Used server I18n deliberately; we want to write the comments in the actual config file in english. public final class Settings { // Category names + /** The unlocalised name of the gameplay config category. */ + public static final String GAMEPLAY_CATEGORY = "gameplay"; /** The unlocalised name of the spells config category. */ public static final String SPELLS_CATEGORY = "spells"; /** The unlocalised name of the resistances config category. */ @@ -63,8 +64,14 @@ public final class Settings { public static final String COMMANDS_CATEGORY = "commands"; /** The unlocalised name of the worldgen config category. */ public static final String WORLDGEN_CATEGORY = "worldgen"; - /** The unlocalised name of the gameplay config category. */ - public static final String GAMEPLAY_CATEGORY = "gameplay"; + /** The unlocalised name of the compatibility config category. */ + public static final String COMPATIBILITY_CATEGORY = "compatibility"; + + private static final String[] DEFAULT_LOOT_INJECTION_LOCATIONS = {"minecraft:chests/simple_dungeon", + "minecraft:chests/abandoned_mineshaft", "minecraft:chests/desert_pyramid", "minecraft:chests/jungle_temple", + "minecraft:chests/stronghold_corridor", "minecraft:chests/stronghold_crossing", + "minecraft:chests/stronghold_library", "minecraft:chests/igloo_chest", "minecraft:chests/woodland_mansion", + "minecraft:chests/end_city_treasure"}; /** The wizardry config file. */ private Configuration config; @@ -73,34 +80,88 @@ public final class Settings { // has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. // Worldgen + /** [Server-only] Whether to use faster worldgen at the cost of 'seamlessness'. */ + public boolean fastWorldgen = false; + /** [Server-only] List of dimension ids in which to generate wizard towers. */ + public int[] towerDimensions = {0}; /** [Server-only] The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */ - public int towerRarity = 8; + public int towerRarity = 600; + /** [Server-only] List of structure file locations for wizard towers without loot chests. */ + public ResourceLocation[] towerFiles = {new ResourceLocation(Wizardry.MODID, "wizard_tower_0"), + new ResourceLocation(Wizardry.MODID, "wizard_tower_1"), + new ResourceLocation(Wizardry.MODID, "wizard_tower_2"), + new ResourceLocation(Wizardry.MODID, "wizard_tower_3")}; + /** [Server-only] List of structure file locations for wizard towers with loot chests. */ + public ResourceLocation[] towerWithChestFiles = {new ResourceLocation(Wizardry.MODID, "wizard_tower_chest_0"), + new ResourceLocation(Wizardry.MODID, "wizard_tower_chest_1"), + new ResourceLocation(Wizardry.MODID, "wizard_tower_chest_2"), + new ResourceLocation(Wizardry.MODID, "wizard_tower_chest_3")}; + /** [Server-only] List of dimension ids in which to generate obelisks. */ + public int[] obeliskDimensions = {0, -1}; + /** [Server-only] The rarity of obelisks, used by the world generator. Larger numbers are rarer. */ + public int obeliskRarity = 550; + /** [Server-only] List of structure file locations for obelisks. */ + public ResourceLocation[] obeliskFiles = {new ResourceLocation(Wizardry.MODID, "obelisk_0"), + new ResourceLocation(Wizardry.MODID, "obelisk_1"), + new ResourceLocation(Wizardry.MODID, "obelisk_2"), + new ResourceLocation(Wizardry.MODID, "obelisk_3"), + new ResourceLocation(Wizardry.MODID, "obelisk_4")}; + /** [Server-only] List of dimension ids in which to generate shrines. */ + public int[] shrineDimensions = {0, -1}; + /** [Server-only] The rarity of shrines, used by the world generator. Larger numbers are rarer. */ + public int shrineRarity = 1000; + /** [Server-only] List of structure file locations for shrines. */ + public ResourceLocation[] shrineFiles = {new ResourceLocation(Wizardry.MODID, "shrine_0"), + new ResourceLocation(Wizardry.MODID, "shrine_1"), + new ResourceLocation(Wizardry.MODID, "shrine_2"), + new ResourceLocation(Wizardry.MODID, "shrine_3"), + new ResourceLocation(Wizardry.MODID, "shrine_4"), + new ResourceLocation(Wizardry.MODID, "shrine_5"), + new ResourceLocation(Wizardry.MODID, "shrine_6"), + new ResourceLocation(Wizardry.MODID, "shrine_7")}; + /** [Server-only] The chance for wizard towers to generate with an evil wizard and chest inside. */ + public double evilWizardChance = 0.2; /** [Server-only] List of dimension ids in which to generate crystal ore. */ public int[] oreDimensions = {0}; - /** [Server-only] List of dimension ids in which to generate crystal ore. */ + /** [Server-only] List of dimension ids in which to generate crystal flowers. */ public int[] flowerDimensions = {0}; - /** [Server-only] List of dimension ids in which to generate crystal ore. */ - public int[] towerDimensions = {0}; /** - * [Server-only] Whether or not wizardry loot should generate in dungeon chests. Note that this does not - * affect the generation of loot in wizard towers. + * [Server-only] List of resource location strings for loot tables to inject wizardry loot into. Note that + * this does not affect the generation of loot in wizard towers. */ - public boolean generateLoot = true; + public ResourceLocation[] lootInjectionLocations = toResourceLocations(DEFAULT_LOOT_INJECTION_LOCATIONS); // Entities' drops, targeting, damage, etc. - /** [Server-only] Chance (out of 200) for mobs to drop spell books. */ - public int spellBookDropChance = 3; + /** [Server-only] Whitelist for loot tables to inject additional mob drops into. */ + public ResourceLocation[] mobLootTableWhitelist = {}; + /** [Server-only] Blacklist for loot tables to inject additional mob drops into. */ + public ResourceLocation[] mobLootTableBlacklist = toResourceLocations("entities/vex", "entities/ender_dragon", + "entities/wither", "entities/silverfish", "entities/endermite", + Wizardry.MODID + "entities/evil_wizard"); /** * [Server-only] Whether or not players can teleport through unbreakable blocks (e.g. bedrock) using the * phase step spell. */ public boolean teleportThroughUnbreakableBlocks = false; /** [Server-only] Whether to allow players to damage their designated allies using magic. */ - public boolean friendlyFire = true; + public FriendlyFire friendlyFire = FriendlyFire.ALL; /** [Server-only] Whether to allow players to disarm other players using the telekinesis spell. */ public boolean telekineticDisarmament = true; /** [Server-only] Whether summoned creatures can revenge attack their caster if their caster attacks them. */ public boolean minionRevengeTargeting = true; + /** [Server-only] Whether to allow players to change the world time using the speed time spell. */ + public boolean worldTimeManipulation = true; + /** [Server-only] Whether to allow players to move other players around using magic. */ + public boolean playersMoveEachOther = true; + /** [Server-only] Whether spells cast by players can destroy blocks in the world. */ + public boolean playerBlockDamage = true; + /** [Server-only] Whether to revert to the old wand upgrade system, which only requires tomes of arcana. */ + public boolean legacyWandLevelling = false; + /** [Server-only] Whether to replace Minecraft's own fireballs with wizardry fireballs. */ + public boolean replaceVanillaFireballs = true; + /** [Server-only] Whether to replace Minecraft's distance-based fall damage calculation with an equivalent, + * velocity-based one. */ + public boolean replaceVanillaFallDamage = true; /** * [Server-only] List of registry names of entities which summoned creatures are allowed to attack, in addition * to the defaults. @@ -110,18 +171,39 @@ public final class Settings { * [Server-only] List of registry names of entities which summoned creatures are specifically not allowed to * attack, overriding the defaults and the whitelist. */ - public ResourceLocation[] summonedCreatureTargetsBlacklist = {new ResourceLocation("creeper")}; + public ResourceLocation[] summonedCreatureTargetsBlacklist = toResourceLocations("creeper"); /** * [Server-only] List of registry names of entities which are immune to the mind control spell, in addition to * the defaults. */ public ResourceLocation[] mindControlTargetsBlacklist = {}; + /** + * [Server-only] List of registry names of items which cannot be smelted by the pocket furnace spell, in + * addition to armour, tools and weapons. + */ + public ResourceLocation[] pocketFurnaceItemBlacklist = toResourceLocations("cobblestone", "netherrack"); + /** [Server-only] List of registry names of blocks which can be detected by the divination spell. */ + public ResourceLocation[] divinationOreWhitelist = {}; + /** [Server-only] List of registry names of items which count as swords for imbuement spells. */ + public ResourceLocation[] swordItemWhitelist = {}; + /** [Server-only] List of registry names of items which count as bows for imbuement spells. */ + public ResourceLocation[] bowItemWhitelist = {}; + /** [Server-only] Map of items to values which wizard trades may use as currency. */ + public Map currencyItems = new HashMap<>(); /** [Server-only] Global damage scaling factor for all player magic damage. */ - public double playerDamageScale = 1.0f; + public double playerDamageScale = 1.0; /** [Server-only] Global damage scaling factor for all npc magic damage. */ - public double npcDamageScale = 1.0f; - /** [Server-only] List of dimension ids in which evil wizards can spawn. */ - public int[] evilWizardDimensions = {0}; + public double npcDamageScale = 1.0; + /** [Server-only] List of dimension ids in which wizardry's hostile mobs can spawn. */ + public int[] mobSpawnDimensions = {0}; + /** [Server-only] Spawn rate for naturally-spawned evil wizards; higher numbers mean more evil wizards will spawn. */ + public int evilWizardSpawnRate = 3; + /** [Server-only] Spawn rate for naturally-spawned evil wizards; higher numbers mean more evil wizards will spawn. */ + public int iceWraithSpawnRate = 3; + /** [Server-only] Spawn rate for naturally-spawned evil wizards; higher numbers mean more evil wizards will spawn. */ + public int lightningWraithSpawnRate = 1; + /** [Server-only] List of registry names of biomes in which wizardry's hostile mobs cannot spawn. */ + public ResourceLocation[] mobSpawnBiomeBlacklist = toResourceLocations("mushroom_island", "mushroom_island_shore"); // Commands (these don't need synchronising since typing a command always queries the server). /** @@ -138,6 +220,25 @@ public final class Settings { /** [Server-only] The name of the /allies command. */ public String alliesCommandName = "allies"; + /** + * [Server-only] List of damage source string identifiers to be ignored when re-applying damage. + */ + public String[] damageSourceBlacklist = {}; + /** [Server-only] Whether to print compatibility warnings to the console. */ + public boolean compatibilityWarnings = true; + /** [Server-only] Whether Baubles integration features are enabled. */ + public boolean baublesIntegration = true; +// /** [Server-only] Whether JEI integration features are enabled. */ +// public boolean jeiIntegration = true; + /** [Server-only] Whether Antique Atlas integration features are enabled. */ + public boolean antiqueAtlasIntegration = true; + /** [Server-only] Whether global markers for wizard towers are added to antique atlases. */ + public boolean autoTowerMarkers = true; + /** [Server-only] Whether global markers for obelisks are added to antique atlases. */ + public boolean autoObeliskMarkers = true; + /** [Server-only] Whether global markers for shrines are added to antique atlases. */ + public boolean autoShrineMarkers = true; + // Synchronised settings. These settings affect both client-side AND server-side code. Changing these locally // only has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world. @@ -148,6 +249,18 @@ public final class Settings { * survival mode if this is false. */ public boolean discoveryMode = true; + /** + * [Synchronised] When set to true, players in creative mode can bypass arcane locks regardless of whether + * they are an op or not. + */ + public boolean creativeBypassesArcaneLock = true; + /** + * [Synchronised] When set to true, players will be slowed when a nearby player or entity has the slow time + * effect. + */ + public boolean slowTimeAffectsPlayers = true; + /** [Synchronised] Chance of 'misreading' an undiscovered spell and triggering a forfeit instead. */ + public double forfeitChance = 0.2; // Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys // its own values for these, and changing them on a dedicated server will have no effect. @@ -157,32 +270,46 @@ public final class Settings { * [Client-only] Whether the player can switch between spells on a wand by scrolling with the mouse wheel * while sneaking. */ - public boolean enableShiftScrolling = true; - /** [Client-only] Whether to reverse the spell switching scroll direction.*/ + public boolean shiftScrolling = true; + /** [Client-only] Whether to reverse the spell switching scroll direction. */ public boolean reverseScrollDirection = false; // Display /** [Client-only] Whether to show summoned creatures' names and owners above their heads. */ - public boolean showSummonedCreatureNames = true; + public boolean summonedCreatureNames = true; + /** + * [Client-only] When set to true, sections of The Wizard's Handbook are unlocked when a player + * gains the advancement that triggers them, and are hidden otherwise. When set to false, the entire handbook is + * readable regardless of advancement progress. + */ + public boolean handbookProgression = true; + /** [Client-only] Whether the various book GUIs pause the game in singleplayer worlds. */ + public boolean booksPauseGame = true; + /** [Client-only] Whether to use custom shaders for certain spells. */ + public boolean useShaders = true; /** [Client-only] The position of the spell HUD. */ public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT; - + public static final String DEFAULT_HUD_SKIN_KEY = "default"; // Defined here so it's not in a client-only class. /** [Client-only] The string identifier of the skin used for the spell HUD. */ public String spellHUDSkin = DEFAULT_HUD_SKIN_KEY; - /** Set of constants for each of the four positions that the spell HUD can be in. */ + /** Set of constants for each of the eight positions that the spell HUD can be in. */ public enum GuiPosition { - BOTTOM_LEFT("Bottom left", false, false), - TOP_LEFT("Top left", false, true), - TOP_RIGHT("Top right", true, true), - BOTTOM_RIGHT("Bottom right", true, false); + BOTTOM_LEFT("Bottom left", false, false, false), + TOP_LEFT("Top left", false, true, false), + TOP_RIGHT("Top right", true, true, false), + BOTTOM_RIGHT("Bottom right", true, false, false), + FOLLOW_BOTTOM("Follow wand, bottom", false, false, true), + FOLLOW_TOP("Follow wand, top", false, true, true), + OPPOSITE_BOTTOM("Opposite wand, bottom", true, false, true), + OPPOSITE_TOP("Opposite wand, top", true, true, true); /** Constant array storing the names of each of the constants, in the order they are declared. */ public static final String[] names; - static{ + static { names = new String[values().length]; for(GuiPosition position : values()){ names[position.ordinal()] = position.name; @@ -191,13 +318,15 @@ public final class Settings { /** The readable name for this GUI position that will be displayed on the button in the config GUI. */ public final String name; - public boolean flipX; - public boolean flipY; + public final boolean flipX; + public final boolean flipY; + public final boolean dynamic; - GuiPosition(String name, boolean flipX, boolean flipY){ + GuiPosition(String name, boolean flipX, boolean flipY, boolean dynamic){ this.name = name; this.flipX = flipX; this.flipY = flipY; + this.dynamic = dynamic; } /** @@ -236,8 +365,9 @@ public final class Settings { setupGeneralConfig(); setupWorldgenConfig(); - setupClientConfig(); + if(event.getSide() == Side.CLIENT) setupClientConfig(); // Server has no spell HUD skins so this would crash it setupCommandsConfig(); + setupCompatibilityConfig(); config.save(); } @@ -252,9 +382,9 @@ public final class Settings { Wizardry.logger.info("Setting up spells config for " + Spell.getTotalSpellCount() + " spells"); setupSpellsConfig(); - + Wizardry.logger.info("Setting up resistances config"); - + setupResistancesConfig(); config.save(); @@ -269,6 +399,7 @@ public final class Settings { setupWorldgenConfig(); setupClientConfig(); setupCommandsConfig(); + setupCompatibilityConfig(); setupSpellsConfig(); setupResistancesConfig(); @@ -298,6 +429,7 @@ public final class Settings { I18n.translateToLocal("spell." + spell.getUnlocalisedName() + ".desc")); // Uses the same config key as the spell name, because - well, that's what it's called! property.setLanguageKey("spell." + spell.getUnlocalisedName()); + Wizardry.proxy.setToNamedBooleanEntry(property); spell.setEnabled(property.getBoolean()); } @@ -306,7 +438,7 @@ public final class Settings { private void setupGeneralConfig(){ // This trick is borrowed from forge; it sorts the config options into the order you want them. - List propOrder = new ArrayList(); + List propOrder = new ArrayList<>(); Property property; @@ -315,108 +447,251 @@ public final class Settings { property = config.get(GAMEPLAY_CATEGORY, "discoveryMode", true, "For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false."); property.setLanguageKey("config." + Wizardry.MODID + ".discovery_mode"); + Wizardry.proxy.setToNamedBooleanEntry(property); property.setRequiresWorldRestart(true); discoveryMode = property.getBoolean(); propOrder.add(property.getName()); - property = config.get(GAMEPLAY_CATEGORY, "friendlyFire", true, - "Whether to allow players to damage their designated allies using magic."); + property = config.get(GAMEPLAY_CATEGORY, "legacyWandLevelling", false, + "Controls whether wands are required to gain progression before they can be upgraded to the next tier. Enable this option to revert to the pre-4.2 system, which only requires tomes of arcana. Wands will still gain progression even when this is enabled, so if you go back to the new system you won't lose any progress."); + property.setLanguageKey("config." + Wizardry.MODID + ".legacy_wand_levelling"); + Wizardry.proxy.setToNamedBooleanEntry(property); + legacyWandLevelling = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "friendlyFire", FriendlyFire.ALL.name, "Controls which creatures may be damaged by your magic when allied to you. Your spells will not target your allies or creatures summoned/owned by them regardless of this setting, but this setting prevents all magic damage to allies.", FriendlyFire.names); property.setLanguageKey("config." + Wizardry.MODID + ".friendly_fire"); - friendlyFire = property.getBoolean(); - propOrder.add(property.getName()); - - property = config.get(GAMEPLAY_CATEGORY, "spellBookDropChance", 3, - "The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops.", - 0, 200); - property.setLanguageKey("config." + Wizardry.MODID + ".spell_book_drop_chance"); - Wizardry.proxy.setToNumberSliderEntry(property); - spellBookDropChance = property.getInt(); - propOrder.add(property.getName()); - - property = config.get(GAMEPLAY_CATEGORY, "evilWizardDimensions", new int[]{0}, - "List of dimension ids in which evil wizards can spawn."); - property.setLanguageKey("config." + Wizardry.MODID + ".evil_wizard_dimensions"); - property.setRequiresMcRestart(true); - evilWizardDimensions = property.getIntList(); - propOrder.add(property.getName()); - - // These two aren't sliders because using a slider makes it difficult to fine-tune the numbers; the nature of a - // scaling factor means that 0.5 is as big a change as 2.0, so whilst a slider is fine for increasing the - // damage, it doesn't give fine enough control for values less than 1. - property = config.get(GAMEPLAY_CATEGORY, "playerDamageScaling", 1.0, - "Global damage scaling factor for the damage dealt by players casting spells, relative to 1.", 0, 20); - property.setLanguageKey("config." + Wizardry.MODID + ".player_damage_scaling"); - playerDamageScale = property.getDouble(); - propOrder.add(property.getName()); - - property = config.get(GAMEPLAY_CATEGORY, "npcDamageScaling", 1.0, - "Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1.", 0, 20); - property.setLanguageKey("config." + Wizardry.MODID + ".npc_damage_scaling"); - npcDamageScale = property.getDouble(); + friendlyFire = FriendlyFire.fromName(property.getString()); propOrder.add(property.getName()); property = config.get(GAMEPLAY_CATEGORY, "minionRevengeTargeting", true, "Whether summoned creatures can revenge attack their owner if their owner attacks them."); property.setLanguageKey("config." + Wizardry.MODID + ".minion_revenge_targeting"); + Wizardry.proxy.setToNamedBooleanEntry(property); property.setRequiresWorldRestart(false); minionRevengeTargeting = property.getBoolean(); propOrder.add(property.getName()); - property = config.get(GAMEPLAY_CATEGORY, "summonedCreatureTargetsWhitelist", new String[0], - "List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); - property.setLanguageKey("config." + Wizardry.MODID + ".summoned_creature_targets_whitelist"); - property.setRequiresWorldRestart(true); - // Converts all strings in the list to a ResourceLocation. - summonedCreatureTargetsWhitelist = Arrays.stream(property.getStringList()).map(s -> new ResourceLocation(s.toLowerCase(Locale.ROOT).trim())).toArray(ResourceLocation[]::new); + property = config.get(GAMEPLAY_CATEGORY, "playersMoveEachOther", true, + "Whether to allow players to move other players around using magic."); + property.setLanguageKey("config." + Wizardry.MODID + ".players_move_each_other"); + Wizardry.proxy.setToNamedBooleanEntry(property); + playersMoveEachOther = property.getBoolean(); propOrder.add(property.getName()); - property = config.get(GAMEPLAY_CATEGORY, "summonedCreatureTargetsBlacklist", - new String[]{"creeper"}, - "List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); - property.setLanguageKey("config." + Wizardry.MODID + ".summoned_creature_targets_blacklist"); - property.setRequiresWorldRestart(true); - // Converts all strings in the list to a ResourceLocation. - summonedCreatureTargetsBlacklist = Arrays.stream(property.getStringList()).map(s -> new ResourceLocation(s.toLowerCase(Locale.ROOT).trim())).toArray(ResourceLocation[]::new); + property = config.get(GAMEPLAY_CATEGORY, "playerBlockDamage", true, + "Whether spells cast by players can destroy blocks in the world. Set to false to prevent griefing. To prevent non-players from destroying blocks with magic, use the mobGriefing gamerule."); + property.setLanguageKey("config." + Wizardry.MODID + ".player_block_damage"); + Wizardry.proxy.setToNamedBooleanEntry(property); + playerBlockDamage = property.getBoolean(); propOrder.add(property.getName()); property = config.get(GAMEPLAY_CATEGORY, "telekineticDisarmament", true, "Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items."); property.setLanguageKey("config." + Wizardry.MODID + ".telekinetic_disarmament"); + Wizardry.proxy.setToNamedBooleanEntry(property); telekineticDisarmament = property.getBoolean(); propOrder.add(property.getName()); property = config.get(GAMEPLAY_CATEGORY, "teleportThroughUnbreakableBlocks", false, "Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell."); property.setLanguageKey("config." + Wizardry.MODID + ".teleport_through_unbreakable_blocks"); + Wizardry.proxy.setToNamedBooleanEntry(property); teleportThroughUnbreakableBlocks = property.getBoolean(); propOrder.add(property.getName()); + property = config.get(GAMEPLAY_CATEGORY, "worldTimeManipulation", true, + "Whether players are allowed to change the world time with the speed time spell. If this is false, the speed time spell will not change the world time but will still speed up nearby block, entity and tile entity ticks."); + property.setLanguageKey("config." + Wizardry.MODID + ".world_time_manipulation"); + Wizardry.proxy.setToNamedBooleanEntry(property); + worldTimeManipulation = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "replaceVanillaFireballs", true, + "Whether to replace Minecraft's own fireballs with wizardry fireballs. If this is disabled, only wizardry spells will use the custom fireballs."); + property.setLanguageKey("config." + Wizardry.MODID + ".replace_vanilla_fireballs"); + Wizardry.proxy.setToNamedBooleanEntry(property); + replaceVanillaFireballs = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "replaceVanillaFallDamage", true, + "Whether to replace Minecraft's distance-based fall damage calculation with an equivalent, velocity-based one. This is done such that mobs in freefall will take exactly the same damage as normal, so it will not break falling-based mob farms. Disable this if you experience falling-related weirdness! If this is disabled, some spells will use a more simplistic method of resetting the player's fall damage in certain cases."); + property.setLanguageKey("config." + Wizardry.MODID + ".replace_vanilla_fall_damage"); + Wizardry.proxy.setToNamedBooleanEntry(property); + replaceVanillaFallDamage = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "creativeBypassesArcaneLock", true, + "Whether any player in creative mode can bypass arcane-locked blocks. If this is false, players must also be op in order to do so."); + property.setLanguageKey("config." + Wizardry.MODID + ".creative_bypasses_arcane_lock"); + Wizardry.proxy.setToNamedBooleanEntry(property); + creativeBypassesArcaneLock = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "slowTimeAffectsPlayers", true, + "Whether players are slowed when another nearby player uses the slow time spell. If this is false, mobs and projectiles will still be affected but players will move at normal speed."); + property.setLanguageKey("config." + Wizardry.MODID + ".slow_time_affects_players"); + Wizardry.proxy.setToNamedBooleanEntry(property); + slowTimeAffectsPlayers = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "mobLootTableWhitelist", new String[0], "Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them."); + property.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist"); + property.setRequiresMcRestart(true); + mobLootTableWhitelist = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "mobLootTableBlacklist", new String[]{"entities/vex", "entities/ender_dragon", "entities/wither", Wizardry.MODID + ":entities/evil_wizard"}, "Blacklist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually exclude them."); + property.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_blacklist"); + property.setRequiresMcRestart(true); + mobLootTableBlacklist = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "mobSpawnDimensions", new int[]{0}, + "List of dimension ids in which wizardry's hostile mobs can spawn."); + property.setLanguageKey("config." + Wizardry.MODID + ".mob_spawn_dimensions"); + property.setRequiresMcRestart(true); + mobSpawnDimensions = property.getIntList(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "mobSpawnBiomeBlacklist", new String[]{"mushroom_island", "mushroom_island_shore"}, + "List of names of biomes in which wizardry's hostile mobs cannot spawn. Biome names are not case-sensitive. For mod biomes, prefix with the mod ID (e.g. biomesoplenty:mystic_grove)."); + property.setLanguageKey("config." + Wizardry.MODID + ".mob_spawn_biome_blacklist"); + property.setRequiresMcRestart(true); + mobSpawnBiomeBlacklist = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "evilWizardSpawnRate", 3, + "Spawn rate for naturally-spawned evil wizards; higher numbers mean more evil wizards will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable evil wizard spawning entirely.", + 0, 100); + property.setLanguageKey("config." + Wizardry.MODID + ".evil_wizard_spawn_rate"); + Wizardry.proxy.setToNumberSliderEntry(property); + property.setRequiresMcRestart(true); + evilWizardSpawnRate = property.getInt(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "iceWraithSpawnRate", 3, + "Spawn rate for naturally-spawned ice wraiths; higher numbers mean more ice wraiths will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable ice wraith spawning entirely.", + 0, 100); + property.setLanguageKey("config." + Wizardry.MODID + ".ice_wraith_spawn_rate"); + Wizardry.proxy.setToNumberSliderEntry(property); + property.setRequiresMcRestart(true); + iceWraithSpawnRate = property.getInt(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "lightningWraithSpawnRate", 1, + "Spawn rate for naturally-spawned lightning wraiths; higher numbers mean more lightning wraiths will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable lightning wraith spawning entirely.", + 0, 100); + property.setLanguageKey("config." + Wizardry.MODID + ".lightning_wraith_spawn_rate"); + Wizardry.proxy.setToNumberSliderEntry(property); + property.setRequiresMcRestart(true); + lightningWraithSpawnRate = property.getInt(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "forfeitChance", 0.2, + "The chance to 'misread' an undiscovered spell and trigger a forfeit instead. Setting this to 0 effectively disables the forfeit mechanic. Has no effect if discovery mode is disabled.", + 0, 1); + property.setLanguageKey("config." + Wizardry.MODID + ".forfeit_chance"); + Wizardry.proxy.setToNumberSliderEntry(property); + forfeitChance = property.getDouble(); + propOrder.add(property.getName()); + + // These two aren't sliders because using a slider makes it difficult to fine-tune the numbers; the nature of a + // scaling factor means that 0.5 is as big a change as 2.0, so whilst a slider is fine for increasing the + // damage, it doesn't give fine enough control for values less than 1. + property = config.get(GAMEPLAY_CATEGORY, "playerDamageScaling", 1.0, + "Global damage scaling factor for the damage dealt by players casting spells, relative to 1.", 0, 255); + property.setLanguageKey("config." + Wizardry.MODID + ".player_damage_scaling"); + playerDamageScale = property.getDouble(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "npcDamageScaling", 1.0, + "Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1.", 0, 255); + property.setLanguageKey("config." + Wizardry.MODID + ".npc_damage_scaling"); + npcDamageScale = property.getDouble(); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "summonedCreatureTargetsWhitelist", new String[0], + "List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); + property.setLanguageKey("config." + Wizardry.MODID + ".summoned_creature_targets_whitelist"); + property.setRequiresWorldRestart(true); + summonedCreatureTargetsWhitelist = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "summonedCreatureTargetsBlacklist", new String[]{"creeper"}, + "List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); + property.setLanguageKey("config." + Wizardry.MODID + ".summoned_creature_targets_blacklist"); + property.setRequiresWorldRestart(true); + summonedCreatureTargetsBlacklist = getResourceLocationList(property); + propOrder.add(property.getName()); + property = config.get(GAMEPLAY_CATEGORY, "mindControlTargetsBlacklist", new String[]{}, - "List of names of entities which cannot be mind controlled, in addition to the defaults. Add creatures to this list if allowing them to be mind-controlled causes problems or could be exploited. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); + "List of names of entities which cannot be mind controlled, in addition to the defaults. Add creatures to this list if allowing them to be mind-controlled causes problems or could be exploited. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); property.setLanguageKey("config." + Wizardry.MODID + ".mind_control_targets_blacklist"); property.setRequiresWorldRestart(true); - // Converts all strings in the list to a ResourceLocation. - mindControlTargetsBlacklist = Arrays.stream(property.getStringList()).map(s -> new ResourceLocation(s.toLowerCase(Locale.ROOT).trim())).toArray(ResourceLocation[]::new); + mindControlTargetsBlacklist = getResourceLocationList(property); propOrder.add(property.getName()); + property = config.get(GAMEPLAY_CATEGORY, "pocketFurnaceItemBlacklist", new String[]{"cobblestone", "netherrack"}, + "List of registry names of blocks or items which cannot be smelted by the pocket furnace spell, in addition to armour, tools and weapons. Block/item names are not case sensitive. For mod items, prefix with the mod ID (e.g. " + Wizardry.MODID + ":crystal_ore)."); + property.setLanguageKey("config." + Wizardry.MODID + ".pocket_furnace_item_blacklist"); + property.setRequiresWorldRestart(true); + pocketFurnaceItemBlacklist = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "divinationOreWhitelist", new String[0], "List of registry names of ore blocks which can be detected by the divination spell. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. " + Wizardry.MODID + ":crystal_ore)."); + property.setLanguageKey("config." + Wizardry.MODID + ".divination_ore_whitelist"); + property.setRequiresWorldRestart(true); + divinationOreWhitelist = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "swordItemWhitelist", new String[0], "List of registry names of items which should count as swords for imbuement spells. Most swords should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:broadsword)."); + property.setLanguageKey("config." + Wizardry.MODID + ".sword_item_whitelist"); + property.setRequiresWorldRestart(true); + swordItemWhitelist = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "bowItemWhitelist", new String[0], "List of registry names of items which should count as bows for imbuement spells. Most bows should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:shortbow)."); + property.setLanguageKey("config." + Wizardry.MODID + ".bow_item_whitelist"); + property.setRequiresWorldRestart(true); + bowItemWhitelist = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(GAMEPLAY_CATEGORY, "currencyItems", new String[]{"gold_ingot 3", "emerald 6"}, "List of registry names of items which wizard trades can use as currency (in the first slot; the second slot is unaffected). Each entry in this list should consist of an item registry name, followed by a single space, then an integer which defines the 'value' of the item. Higher values mean fewer of that currency item are required for a given trade.", + Pattern.compile("[A-Za-z:_]+ [0-9]+")); + property.setLanguageKey("config." + Wizardry.MODID + ".currency_items"); + property.setRequiresWorldRestart(true); + propOrder.add(property.getName()); + currencyItems = new HashMap<>(); + for(String string : property.getStringList()){ + String[] args = string.split(" "); + if(args.length != 2){ + Wizardry.logger.warn("Invalid entry in currency items: {}", string); + continue; // Ignore invalid entries, the pattern above should ensure this never happens + } + try { + currencyItems.put(new ResourceLocation(args[0]), Integer.parseInt(args[1])); + }catch(NumberFormatException e){ + Wizardry.logger.warn("Invalid integer in currency items: {}", args[1]); + } + } + config.setCategoryPropertyOrder(GAMEPLAY_CATEGORY, propOrder); } - + private void setupWorldgenConfig(){ - // This trick is borrowed from forge; it sorts the config options into the order you want them. - List propOrder = new ArrayList(); + List propOrder = new ArrayList<>(); Property property; config.addCustomCategoryComment(WORLDGEN_CATEGORY, "Settings that affect world generation. In multiplayer, the server/LAN host settings will apply."); - - property = config.get(WORLDGEN_CATEGORY, "towerRarity", 8, "Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely.", 0, 50); - property.setLanguageKey("config." + Wizardry.MODID + ".tower_rarity"); - property.setRequiresWorldRestart(true); - Wizardry.proxy.setToNumberSliderEntry(property); - towerRarity = property.getInt(); + + property = config.get(WORLDGEN_CATEGORY, "fastWorldgen", false, "Whether to use faster worldgen at the cost of 'seamlessness'. Enabling this option removes the checks for steep slopes and cleanup of floating trees that improve the look of worldgen. Performance improvement will vary depending on your setup. This option will affect randomisation; for any given seed, structures will not be the same as when it is turned off."); + property.setLanguageKey("config." + Wizardry.MODID + ".fast_worldgen"); + Wizardry.proxy.setToNamedBooleanEntry(property); + fastWorldgen = property.getBoolean(); propOrder.add(property.getName()); property = config.get(WORLDGEN_CATEGORY, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate."); @@ -425,6 +700,74 @@ public final class Settings { towerDimensions = property.getIntList(); propOrder.add(property.getName()); + property = config.get(WORLDGEN_CATEGORY, "towerRarity", 600, "Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.", 20, 5000); + property.setLanguageKey("config." + Wizardry.MODID + ".tower_rarity"); + property.setRequiresWorldRestart(true); + Wizardry.proxy.setToNumberSliderEntry(property); + towerRarity = property.getInt(); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "evilWizardChance", 0.2, "The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.", 0, 1); + property.setLanguageKey("config." + Wizardry.MODID + ".evil_wizard_chance"); + property.setRequiresWorldRestart(true); + Wizardry.proxy.setToNumberSliderEntry(property); + evilWizardChance = property.getDouble(); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "towerFiles", new String[]{Wizardry.MODID + ":wizard_tower_0", Wizardry.MODID + ":wizard_tower_1", Wizardry.MODID + ":wizard_tower_2", Wizardry.MODID + ":wizard_tower_3"}, + "List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves."); + property.setLanguageKey("config." + Wizardry.MODID + ".tower_files"); + property.setRequiresWorldRestart(true); + towerFiles = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "towerWithChestFiles", new String[]{Wizardry.MODID + ":wizard_tower_chest_0", Wizardry.MODID + ":wizard_tower_chest_1", Wizardry.MODID + ":wizard_tower_chest_2", Wizardry.MODID + ":wizard_tower_chest_3"}, + "List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves."); + property.setLanguageKey("config." + Wizardry.MODID + ".tower_with_chest_files"); + property.setRequiresWorldRestart(true); + towerWithChestFiles = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "obeliskDimensions", new int[]{0, -1}, "List of dimension ids in which obelisks will generate."); + property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_dimensions"); + property.setRequiresWorldRestart(true); + obeliskDimensions = property.getIntList(); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "obeliskRarity", 550, "Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.", 20, 5000); + property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_rarity"); + property.setRequiresWorldRestart(true); + Wizardry.proxy.setToNumberSliderEntry(property); + obeliskRarity = property.getInt(); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "obeliskFiles", new String[]{Wizardry.MODID + ":obelisk_0", Wizardry.MODID + ":obelisk_1", Wizardry.MODID + ":obelisk_2", Wizardry.MODID + ":obelisk_3", Wizardry.MODID + ":obelisk_4"}, + "List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves."); + property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_files"); + property.setRequiresWorldRestart(true); + obeliskFiles = getResourceLocationList(property); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "shrineDimensions", new int[]{0, -1}, "List of dimension ids in which shrines will generate."); + property.setLanguageKey("config." + Wizardry.MODID + ".shrine_dimensions"); + property.setRequiresWorldRestart(true); + shrineDimensions = property.getIntList(); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "shrineRarity", 1000, "Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.", 20, 5000); + property.setLanguageKey("config." + Wizardry.MODID + ".shrine_rarity"); + property.setRequiresWorldRestart(true); + Wizardry.proxy.setToNumberSliderEntry(property); + shrineRarity = property.getInt(); + propOrder.add(property.getName()); + + property = config.get(WORLDGEN_CATEGORY, "shrineFiles", new String[]{Wizardry.MODID + ":shrine_0", Wizardry.MODID + ":shrine_1", Wizardry.MODID + ":shrine_2", Wizardry.MODID + ":shrine_3", Wizardry.MODID + ":shrine_4", Wizardry.MODID + ":shrine_5", Wizardry.MODID + ":shrine_6", Wizardry.MODID + ":shrine_7"}, + "List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves."); + property.setLanguageKey("config." + Wizardry.MODID + ".shrine_files"); + property.setRequiresWorldRestart(true); + shrineFiles = getResourceLocationList(property); + propOrder.add(property.getName()); + property = config.get(WORLDGEN_CATEGORY, "oreDimensions", new int[]{0}, "List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!"); property.setLanguageKey("config." + Wizardry.MODID + ".ore_dimensions"); property.setRequiresWorldRestart(true); @@ -437,34 +780,35 @@ public final class Settings { flowerDimensions = property.getIntList(); propOrder.add(property.getName()); - property = config.get(WORLDGEN_CATEGORY, "generateLoot", true, "Whether to inject wizardry loot (as specified in loot_tables/chests/dungeon_additions.json) into the loot tables for vanilla dungeon chests."); - property.setLanguageKey("config." + Wizardry.MODID + ".generate_loot"); - property.setRequiresWorldRestart(true); - generateLoot = property.getBoolean(); + property = config.get(WORLDGEN_CATEGORY, "lootInjectionLocations", DEFAULT_LOOT_INJECTION_LOCATIONS, "List of loot tables to inject wizardry loot (as specified in loot_tables/chests/dungeon_additions.json) into."); + property.setLanguageKey("config." + Wizardry.MODID + ".loot_injection_locations"); + property.setRequiresMcRestart(true); + lootInjectionLocations = getResourceLocationList(property); propOrder.add(property.getName()); - + config.setCategoryPropertyOrder(WORLDGEN_CATEGORY, propOrder); } - + private void setupClientConfig(){ - // This trick is borrowed from forge; it sorts the config options into the order you want them. List propOrder = new ArrayList(); Property property; config.addCustomCategoryComment(CLIENT_CATEGORY, "Client-side settings that only affect the local minecraft game. If this file is on a dedicated server, these settings will have no effect; in multiplayer, each player obeys their own settings."); - property = config.get(CLIENT_CATEGORY, "enableShiftScrolling", true, + property = config.get(CLIENT_CATEGORY, "shiftScrolling", true, "Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings."); - property.setLanguageKey("config." + Wizardry.MODID + ".enable_shift_scrolling"); + property.setLanguageKey("config." + Wizardry.MODID + ".shift_scrolling"); property.setRequiresWorldRestart(false); - enableShiftScrolling = property.getBoolean(); + Wizardry.proxy.setToNamedBooleanEntry(property); + shiftScrolling = property.getBoolean(); propOrder.add(property.getName()); - - property = config.get(CLIENT_CATEGORY, "reverseScrollDirection", false, "Whether to reverse the scroll direction used to switch between spells on a wand while sneaking."); + + property = config.get(CLIENT_CATEGORY, "reverseScrollDirection", false, "The scroll direction used to switch between spells on a wand while sneaking."); property.setLanguageKey("config." + Wizardry.MODID + ".reverse_scroll_direction"); property.setRequiresWorldRestart(false); + Wizardry.proxy.setToNamedBooleanEntry(property); reverseScrollDirection = property.getBoolean(); propOrder.add(property.getName()); @@ -472,35 +816,51 @@ public final class Settings { property.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_position"); spellHUDPosition = GuiPosition.fromName(property.getString()); propOrder.add(property.getName()); - + property = config.get(CLIENT_CATEGORY, "spellHUDSkin", DEFAULT_HUD_SKIN_KEY, "The skin used for the spell HUD.", Wizardry.proxy.getSpellHUDSkins().toArray(new String[0])); property.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_skin"); Wizardry.proxy.setToHUDChooserEntry(property); spellHUDSkin = property.getString(); propOrder.add(property.getName()); - property = config.get(CLIENT_CATEGORY, "showSummonedCreatureNames", true, "Whether to show summoned creatures' names and owners above their heads."); - property.setLanguageKey("config." + Wizardry.MODID + ".show_summoned_creature_names"); - showSummonedCreatureNames = property.getBoolean(); + property = config.get(CLIENT_CATEGORY, "handbookProgression", true, "When set to true, sections of The Wizard's Handbook are unlocked when a player gains the advancement that triggers them, and are hidden otherwise. When set to false, the entire handbook is readable regardless of advancement progress."); + property.setLanguageKey("config." + Wizardry.MODID + ".handbook_progression"); + Wizardry.proxy.setToNamedBooleanEntry(property); + handbookProgression = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(CLIENT_CATEGORY, "booksPauseGame", true, "Whether opening any of wizardry's books pauses the game in singleplayer. Has no effect on servers or LAN worlds."); + property.setLanguageKey("config." + Wizardry.MODID + ".books_pause_game"); + Wizardry.proxy.setToNamedBooleanEntry(property); + booksPauseGame = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(CLIENT_CATEGORY, "summonedCreatureNames", true, "Whether to show summoned creatures' names and owners above their heads."); + property.setLanguageKey("config." + Wizardry.MODID + ".summoned_creature_names"); + Wizardry.proxy.setToNamedBooleanEntry(property); + summonedCreatureNames = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(CLIENT_CATEGORY, "useShaders", true, "Whether to use custom shaders for certain spells. These use the vanilla shader system (like mob spectating shaders) and shouldn't have much of an effect on performance in most cases, but they may conflict with other shaders."); + property.setLanguageKey("config." + Wizardry.MODID + ".use_shaders"); + Wizardry.proxy.setToNamedBooleanEntry(property); + useShaders = property.getBoolean(); propOrder.add(property.getName()); config.setCategoryPropertyOrder(CLIENT_CATEGORY, propOrder); } - + private void setupCommandsConfig(){ - // This trick is borrowed from forge; it sorts the config options into the order you want them. List propOrder = new ArrayList(); Property property; config.addCustomCategoryComment(COMMANDS_CATEGORY, "Settings for the commands added by Wizardry. In multiplayer, the server/LAN host settings will apply."); - // This one isn't a slider either because people are likely to want exact values ("it must be at most 50.3" is a - // bit strange!). property = config.get(COMMANDS_CATEGORY, "castCommandMultiplierLimit", 20.0, "Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned!", - 1, 255); + 1, Integer.MAX_VALUE); // Sure, I mean you COULD set it to 2^31-1... what could possibly go wrong? property.setLanguageKey("config." + Wizardry.MODID + ".cast_command_multiplier_limit"); maxSpellCommandMultiplier = property.getDouble(); propOrder.add(property.getName()); @@ -532,7 +892,7 @@ public final class Settings { property.setRequiresWorldRestart(true); alliesCommandName = property.getString(); propOrder.add(property.getName()); - + config.setCategoryPropertyOrder(COMMANDS_CATEGORY, propOrder); } @@ -546,7 +906,7 @@ public final class Settings { "Settings which allow entities to be made immune to certain types of magic. In multiplayer, the server/LAN host settings will apply."); property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToFire", new String[]{}, - "List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); + "List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); property.setLanguageKey("config." + Wizardry.MODID + ".mobs_immune_to_fire"); property.setRequiresMcRestart(true); // Wizardry.proxy.setToEntityNameEntry(property); @@ -559,7 +919,7 @@ public final class Settings { propOrder.add(property.getName()); property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToIce", new String[]{}, - "List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); + "List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); property.setLanguageKey("config." + Wizardry.MODID + ".mobs_immune_to_ice"); property.setRequiresMcRestart(true); // Wizardry.proxy.setToEntityNameEntry(property); @@ -572,7 +932,7 @@ public final class Settings { propOrder.add(property.getName()); property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToLightning", new String[]{}, - "List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); + "List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); property.setLanguageKey("config." + Wizardry.MODID + ".mobs_immune_to_lightning"); property.setRequiresMcRestart(true); // Wizardry.proxy.setToEntityNameEntry(property); @@ -585,7 +945,7 @@ public final class Settings { propOrder.add(property.getName()); property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToWither", new String[]{}, - "List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); + "List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); property.setLanguageKey("config." + Wizardry.MODID + ".mobs_immune_to_wither"); property.setRequiresMcRestart(true); // Wizardry.proxy.setToEntityNameEntry(property); @@ -598,7 +958,7 @@ public final class Settings { propOrder.add(property.getName()); property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToPoison", new String[]{}, - "List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); + "List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard)."); property.setLanguageKey("config." + Wizardry.MODID + ".mobs_immune_to_poison"); property.setRequiresMcRestart(true); // Wizardry.proxy.setToEntityNameEntry(property); @@ -613,4 +973,87 @@ public final class Settings { config.setCategoryPropertyOrder(RESISTANCES_CATEGORY, propOrder); } + private void setupCompatibilityConfig(){ + + List propOrder = new ArrayList(); + + Property property; + + config.addCustomCategoryComment(COMPATIBILITY_CATEGORY, "Settings that affect how wizardry interacts with other mods. In multiplayer, the server/LAN host settings will apply."); + + property = config.get(COMPATIBILITY_CATEGORY, "damageSourceBlacklist", new String[]{}, + "List of damage source string identifiers to be ignored when re-applying damage. Case-sensitive. A message will be logged if wizardry detects a damage source that should be added to this list. Otherwise, don't change unless instructed to do so."); + property.setLanguageKey("config." + Wizardry.MODID + ".damage_source_blacklist"); + property.setRequiresWorldRestart(true); + damageSourceBlacklist = property.getStringList(); + propOrder.add(property.getName()); + + property = config.get(COMPATIBILITY_CATEGORY, "compatibilityWarnings", true, + "Whether to print compatibility warnings to the console. Set to false if excessive messages are being printed."); + property.setLanguageKey("config." + Wizardry.MODID + ".compatibility_warnings"); + Wizardry.proxy.setToNamedBooleanEntry(property); + compatibilityWarnings = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(COMPATIBILITY_CATEGORY, "baublesIntegration", true, + "If Baubles is installed, controls whether Baubles integration features are enabled. If this is disabled, wizardry will always behave as if Baubles is not installed."); + property.setLanguageKey("config." + Wizardry.MODID + ".baubles_integration"); + property.setRequiresMcRestart(true); + Wizardry.proxy.setToNamedBooleanEntry(property); + baublesIntegration = property.getBoolean(); + propOrder.add(property.getName()); + +// property = config.get(COMPATIBILITY_CATEGORY, "jeiIntegration", true, +// "If JEI (Just Enough Items) is installed, controls whether JEI integration features are enabled. If this is disabled, wizardry will always behave as if JEI is not installed."); +// property.setLanguageKey("config." + Wizardry.MODID + ".jei_integration"); +// property.setRequiresMcRestart(true); +// Wizardry.proxy.setToNamedBooleanEntry(property); +// jeiIntegration = property.getBoolean(); +// propOrder.add(property.getName()); + + property = config.get(COMPATIBILITY_CATEGORY, "antiqueAtlasIntegration", true, + "If Antique Atlas is installed, controls whether Antique Atlas integration features are enabled. If this is disabled, wizardry will always behave as if Antique Atlas is not installed."); + property.setLanguageKey("config." + Wizardry.MODID + ".antique_atlas_integration"); + property.setRequiresMcRestart(true); + Wizardry.proxy.setToNamedBooleanEntry(property); + antiqueAtlasIntegration = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(COMPATIBILITY_CATEGORY, "autoPlaceTowerMarkers", true, + "Controls whether wizardry automatically places antique atlas markers at the locations of wizard towers."); + property.setLanguageKey("config." + Wizardry.MODID + ".auto_place_tower_markers"); + property.setRequiresMcRestart(true); + Wizardry.proxy.setToNamedBooleanEntry(property); + autoTowerMarkers = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(COMPATIBILITY_CATEGORY, "autoPlaceObeliskMarkers", true, + "Controls whether wizardry automatically places antique atlas markers at the locations of obelisks."); + property.setLanguageKey("config." + Wizardry.MODID + ".auto_place_obelisk_markers"); + property.setRequiresMcRestart(true); + Wizardry.proxy.setToNamedBooleanEntry(property); + autoObeliskMarkers = property.getBoolean(); + propOrder.add(property.getName()); + + property = config.get(COMPATIBILITY_CATEGORY, "autoPlaceShrineMarkers", true, + "Controls whether wizardry automatically places antique atlas markers at the locations of shrines."); + property.setLanguageKey("config." + Wizardry.MODID + ".auto_place_shrine_markers"); + property.setRequiresMcRestart(true); + Wizardry.proxy.setToNamedBooleanEntry(property); + autoShrineMarkers = property.getBoolean(); + propOrder.add(property.getName()); + + config.setCategoryPropertyOrder(COMPATIBILITY_CATEGORY, propOrder); + + } + + /** Retrieves a string list from the given property and converts it to an array of {@link ResourceLocation}s. */ + public static ResourceLocation[] getResourceLocationList(Property property){ + return toResourceLocations(property.getStringList()); + } + + /** Converts the given strings to an array of {@link ResourceLocation}s */ + public static ResourceLocation[] toResourceLocations(String... strings){ + return Arrays.stream(strings).map(s -> new ResourceLocation(s.toLowerCase(Locale.ROOT).trim())).toArray(ResourceLocation[]::new); + } } diff --git a/src/main/java/electroblob/wizardry/Wizardry.java b/src/main/java/electroblob/wizardry/Wizardry.java index 732b36ae..1eeb4806 100644 --- a/src/main/java/electroblob/wizardry/Wizardry.java +++ b/src/main/java/electroblob/wizardry/Wizardry.java @@ -1,23 +1,22 @@ package electroblob.wizardry; -import org.apache.logging.log4j.Logger; - import electroblob.wizardry.command.CommandCastSpell; import electroblob.wizardry.command.CommandDiscoverSpell; import electroblob.wizardry.command.CommandSetAlly; import electroblob.wizardry.command.CommandViewAllies; +import electroblob.wizardry.data.DispenserCastingData; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration; +import electroblob.wizardry.integration.baubles.WizardryBaublesIntegration; +import electroblob.wizardry.misc.Forfeit; import electroblob.wizardry.packet.WizardryPacketHandler; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardryRegistry; -import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.registry.*; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.CustomSoundCategory; +import electroblob.wizardry.util.SpellProperties; +import electroblob.wizardry.worldgen.*; import net.minecraft.item.Item; -import net.minecraft.nbt.NBTBase; -import net.minecraft.util.EnumFacing; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.Capability.IStorage; -import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; @@ -30,12 +29,13 @@ import net.minecraftforge.fml.common.event.FMLServerStartingEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.registry.GameRegistry; +import org.apache.logging.log4j.Logger; /** * "Electroblob's Wizardry adds an RPG-like system of spells to Minecraft, with the aim of being as playable as * possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master * the arcane! - But you knew that, right?" - *

    + *

    * Main mod class for Wizardry. Contains the logger and settings instances, along with all the other stuff that's normally * in a main mod class. * @author Electroblob @@ -50,9 +50,9 @@ public class Wizardry { public static final String NAME = "Electroblob's Wizardry"; /** * The version number for this version of wizardry. The following system is used for version numbers: - *

    + *

    *
    [major Minecraft version].[major mod version].[minor mod version/patch] - *

    + *

    *
    The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same * features as Wizardry 2.1, but they are for different versions of Minecraft and have separate minor versioning. * 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft @@ -60,56 +60,28 @@ public class Wizardry { */ public static final String VERSION = "4.2.0"; - // IDEA: Improve the algorithm that finds a place to summon creatures to take walls into account. - // IDEA: Replace all uses of Math.cos and Math.sin with MathHelper versions // IDEA: Triggering of inbuilt Forge events in relevant places? // IDEA: Abstract the vanilla particles behind the particle builder - /* Minor bugs that need fixing at some point: - * - Player skin hat layer shows through wizard hats - Wizard armour breaks rather than just running out of mana (I - * can't seem to replicate this bug, but I have had it happen to me before...) - * - Shift-clicking a stack of special upgrades when in the arcane workbench causes the whole stack to be - * transferred when it should be just one (this is a bug with vanilla as well - try putting a stack of bottles into - * a brewing stand). I have at least made it so only one gets used now, so it has no impact on the game. - * - When a spell is on cooldown, you can't break blocks when holding a wand. */ - - // TODO: So somehow I have managed to overlook the fact that health is actually a float. What this means is that - // I can make the healing spells use damage multipliers - hurrah! - - // TODO: Switch from IInventory to IItemHandler (Or don't. It's only useful for automation really.) // TODO: Have particles obey Minecraft's particle setting where appropriate // (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java) - // TODO: Go over all the worldgen code, use IWorldGenerator - // TODO: Implement a continuous sound system using MovingSoundEntity, allowing continuous spells to have a long sound - // loop as well as a start and end sound - // TODO: EntityMagicArrow needs attention - // TODO: Go over particle spawning on projectile impact and make sure hitvec is used wherever appropriate - // TODO: Replace spell IDs in packets with ResourceLocation strings - // TODO: Forcefield needs looking at, esp. with regards to projectiles and explosions // TODO: TileEntityArcaneWorkbench needs looking at, esp. regarding inventory and markDirty - // TODO: Fireskin somehow lost its particles - // TODO: Convert settings over to the @Config system - // TODO: Go through listeners of LivingHurtEvent and decide whether they should change to LivingDamageEvent - - // NOTE: Add melee upgrades to loot tables when they are added. + // TODO: See what can be done with the illager spell sounds (and go over sounds in general) + // TODO: Fix possession + // TODO: Fix charge /** Static instance of the {@link Settings} object for Wizardry. */ public static final Settings settings = new Settings(); /** Static instance of the {@link Logger} object for Wizardry. - *

    + *

    * Logging conventions for wizardry (only these levels are used currently): - *

    + *

    * - ERROR: Anything that threw an exception; may or may not crash the game.
    * - WARN: Anything that isn't supposed to happen during normal operation, but didn't throw an exception.
    * - INFO: Anything that might happen during normal mod operation that the user needs to know about. */ public static Logger logger; - // private static Pattern entityNamePattern; - - // EventManager - WizardryWorldGenerator generator = new WizardryWorldGenerator(); - // The instance of wizardry that Forge uses. @Instance(Wizardry.MODID) public static Wizardry instance; @@ -123,40 +95,27 @@ public class Wizardry { logger = event.getModLog(); - proxy.registerResourceReloadListener(); + proxy.registerResourceReloadListeners(); settings.initConfig(event); - // Yes - by the looks of it, having an interface is completely unnecessary in this case. - CapabilityManager.INSTANCE.register(WizardData.class, new IStorage(){ - // These methods are only called by Capability.writeNBT() or Capability.readNBT(), which in turn are - // NEVER CALLED. Unless I'm missing some reflective invocation, that means this entire class serves only - // to allow capabilities to be saved and loaded manually. What that would be useful for I don't know. - // (If an API forces most users to write redundant code for no reason, it's not user friendly, is it?) - // ... well, that's my rant for today! - @Override - public NBTBase writeNBT(Capability capability, WizardData instance, EnumFacing side){ - return null; - } - - @Override - public void readNBT(Capability capability, WizardData instance, EnumFacing side, NBTBase nbt){ - } - }, WizardData::new); - - WizardryRegistry.registerTileEntities(); - - WizardryRegistry.registerEntities(); - // The check for the generateLoot setting is now done within this method. - WizardryRegistry.registerLoot(); + // Capabilities + WizardData.register(); + DispenserCastingData.register(); + // Register things that don't have registries + WizardryBlocks.registerTileEntities(); + WizardryLoot.register(); WizardryAdvancementTriggers.register(); + Forfeit.register(); - // Moved to preInit, because apparently it has to be here now. + // Client-side stuff (via proxies) proxy.registerRenderers(); - // It seems this also has to be here proxy.registerKeyBindings(); + WizardryBaublesIntegration.init(); + WizardryAntiqueAtlasIntegration.init(); + } @EventHandler @@ -164,26 +123,41 @@ public class Wizardry { settings.initConfigExtras(); - // Event Handlers - GameRegistry.registerWorldGenerator(generator, 0); - MinecraftForge.EVENT_BUS.register(instance); + // World generators + // Weight is a misnomer, it's actually the priority (where lower numbers get generated first) + // Literally nothing on typical 'weight' values here, there isn't even an upper limit + // Examples I've managed to find: + // - Tinker's construct slime islands use 25 + GameRegistry.registerWorldGenerator(new WorldGenCrystalOre(), 0); + GameRegistry.registerWorldGenerator(new WorldGenCrystalFlower(), 50); + GameRegistry.registerWorldGenerator(new WorldGenWizardTower(), 20); + GameRegistry.registerWorldGenerator(new WorldGenObelisk(), 20); + GameRegistry.registerWorldGenerator(new WorldGenShrine(), 20); + + // This is for the config change and missing mappings events + MinecraftForge.EVENT_BUS.register(instance); // Since there's already an instance we might as well use it + NetworkRegistry.INSTANCE.registerGuiHandler(this, new WizardryGuiHandler()); WizardryPacketHandler.initPackets(); + // Post-registry extras + WizardryItems.populateWandMap(); + WizardryItems.populateArmourMap(); + WizardryItems.registerDispenseBehaviours(); + Spell.registry.forEach(Spell::init); + SpellProperties.init(); + + // Client-side stuff (via proxies) proxy.initGuiBits(); - proxy.initParticleFactories(); + proxy.registerParticles(); + proxy.registerSoundEventListener(); + + WizardrySounds.SPELLS = CustomSoundCategory.add(Wizardry.MODID + ":spells"); } @EventHandler public void postInit(FMLPostInitializationEvent event){ - // This needs to be here or it won't necessarily include all the mods' entities. - // TODO: Re-implement this when the Forge bug is fixed. - /* Doesn't seem to be doing anything... String entityNames = ""; for(Object name : - * EntityList.classToStringMapping.values()){ if(name instanceof String){ entityNames = entityNames + name + - * '|'; } } // Cuts off the last '|' entityNames = entityNames.substring(0, entityNames.length()-1); - * entityNamePattern = Pattern.compile(entityNames); */ proxy.initialiseLayers(); - WizardryTabs.sort(); } @EventHandler @@ -205,23 +179,30 @@ public class Wizardry { // 2.1 changed some item ids, so this fixes them for existing worlds // Nobody updates minecraft versions when using mods, but I may as well leave this here just in case. @SubscribeEvent - public static void onMissingMappingEvent(RegistryEvent.MissingMappings event){ + public static void onMissingItemMappingEvent(RegistryEvent.MissingMappings event){ // Just get, not getAll, since the mod id didn't change! for(RegistryEvent.MissingMappings.Mapping mapping : event.getAllMappings()){ - if(mapping.key.getResourceDomain().equals(Wizardry.MODID)){ + if(mapping.key.getNamespace().equals(Wizardry.MODID)){ Item replacement; - switch(mapping.key.getResourcePath()){ + switch(mapping.key.getPath()){ case "wand_basic": replacement = WizardryItems.magic_wand; break; - case "wand_basic_fire": replacement = WizardryItems.basic_fire_wand; break; - case "wand_basic_ice": replacement = WizardryItems.basic_ice_wand; break; - case "wand_basic_lightning": replacement = WizardryItems.basic_lightning_wand; break; - case "wand_basic_necromancy": replacement = WizardryItems.basic_necromancy_wand; break; - case "wand_basic_earth": replacement = WizardryItems.basic_earth_wand; break; - case "wand_basic_sorcery": replacement = WizardryItems.basic_sorcery_wand; break; - case "wand_basic_healing": replacement = WizardryItems.basic_healing_wand; break; + case "wand_basic_fire": replacement = WizardryItems.novice_fire_wand; break; + case "wand_basic_ice": replacement = WizardryItems.novice_ice_wand; break; + case "wand_basic_lightning": replacement = WizardryItems.novice_lightning_wand; break; + case "wand_basic_necromancy": replacement = WizardryItems.novice_necromancy_wand; break; + case "wand_basic_earth": replacement = WizardryItems.novice_earth_wand; break; + case "wand_basic_sorcery": replacement = WizardryItems.novice_sorcery_wand; break; + case "wand_basic_healing": replacement = WizardryItems.novice_healing_wand; break; + case "basic_fire_wand": replacement = WizardryItems.novice_fire_wand; break; + case "basic_ice_wand": replacement = WizardryItems.novice_ice_wand; break; + case "basic_lightning_wand": replacement = WizardryItems.novice_lightning_wand; break; + case "basic_necromancy_wand": replacement = WizardryItems.novice_necromancy_wand; break; + case "basic_earth_wand": replacement = WizardryItems.novice_earth_wand; break; + case "basic_sorcery_wand": replacement = WizardryItems.novice_sorcery_wand; break; + case "basic_healing_wand": replacement = WizardryItems.novice_healing_wand; break; case "wand_apprentice": replacement = WizardryItems.apprentice_wand; break; case "wand_apprentice_fire": replacement = WizardryItems.apprentice_fire_wand; break; case "wand_apprentice_ice": replacement = WizardryItems.apprentice_ice_wand; break; @@ -264,4 +245,13 @@ public class Wizardry { } } + @SubscribeEvent + public static void onMissingSpellMappingEvent(RegistryEvent.MissingMappings event){ + for(RegistryEvent.MissingMappings.Mapping mapping : event.getAllMappings()){ + if(mapping.key.getNamespace().equals(Wizardry.MODID)){ + if(mapping.key.getPath().equals("firestorm")) mapping.remap(Spells.fire_breath); + } + } + } + } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/WizardryEventHandler.java b/src/main/java/electroblob/wizardry/WizardryEventHandler.java index ebebcb77..7a57ef9c 100644 --- a/src/main/java/electroblob/wizardry/WizardryEventHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryEventHandler.java @@ -1,120 +1,137 @@ package electroblob.wizardry; import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.entity.EntityArc; -import electroblob.wizardry.entity.living.EntityEvilWizard; +import electroblob.wizardry.data.SpellEmitterData; +import electroblob.wizardry.data.SpellGlyphData; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.entity.living.ISpellCaster; -import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.event.DiscoverSpellEvent; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.integration.DamageSafetyChecker; -import electroblob.wizardry.item.ItemWand; -import electroblob.wizardry.item.ItemWizardArmour; -import electroblob.wizardry.registry.Spells; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; -import electroblob.wizardry.registry.WizardryEnchantments; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.item.IManaStoringItem; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.packet.PacketSyncAdvancements; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.*; import electroblob.wizardry.spell.FreezingWeapon; +import electroblob.wizardry.spell.ImbueWeapon; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WandHelper; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.advancements.Advancement; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.item.EntityItem; -import net.minecraft.entity.monster.IMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.projectile.EntityArrow; -import net.minecraft.init.SoundEvents; -import net.minecraft.inventory.ContainerPlayer; -import net.minecraft.inventory.ContainerWorkbench; -import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemSword; import net.minecraft.potion.PotionEffect; -import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; -import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -import net.minecraft.world.storage.loot.LootEntry; -import net.minecraft.world.storage.loot.LootEntryTable; -import net.minecraft.world.storage.loot.LootPool; -import net.minecraft.world.storage.loot.RandomValueRange; -import net.minecraft.world.storage.loot.conditions.LootCondition; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.FakePlayer; -import net.minecraftforge.event.LootTableLoadEvent; -import net.minecraftforge.event.entity.living.LivingAttackEvent; -import net.minecraftforge.event.entity.living.LivingDeathEvent; -import net.minecraftforge.event.entity.living.LivingDropsEvent; +import net.minecraftforge.event.entity.PlaySoundAtEntityEvent; +import net.minecraftforge.event.entity.living.*; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; -import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraftforge.event.entity.player.AdvancementEvent; +import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent; +import java.util.ArrayList; + /** - * As of Wizardry 2.1, most of the code in this class has been relocated somewhere sensible, leaving only a few - * miscellaneous things that don't make much sense anywhere else, or that are better kept together. Previously, this was - * a gigantic class with about half of the entire mod's logic in it! + * General-purpose event handler for things that don't fit anywhere else or groups of related behaviours that are better + * kept together. As of Wizardry 2.1, most of the code in this class has been relocated somewhere sensible, leaving only + * a few miscellaneous things that don't make much sense anywhere else, or that are better kept together (previously, + * this was a gigantic class with about half of the entire mod's logic in it!) * * @author Electroblob * @since Wizardry 1.0 */ +// The general rules for where event-based logic goes are: +// - If the logic relates only to vanilla things or is general (e.g. gameplay settings) it lives in here +// - If there is an obvious class for the thing relevant to the logic being performed, it goes in there for the sake +// of modularity/separation-of-concerns (e.g. armour cost reductions go in ItemWizardArmour) +// - If the thing has an instance but not a separate class (e.g. most custom potions), it goes in a related class +// where applicable (e.g. a spell class), or if not it goes in here +// - If several things share a significant amount of logic, to avoid duplicate code and potentially improve efficiency +// they should be kept together either in a class relevant to all of them (probably a common superclass) or in here +// - Client-side logic goes in WizardryClientEventHandler or another relevant client-side class @Mod.EventBusSubscriber public final class WizardryEventHandler { - // IDEA: Config option allowing users to specify loot locations - private static final String[] LOOT_INJECTION_LOCATIONS = {"minecraft:chests/simple_dungeon", - "minecraft:chests/abandoned_mineshaft", "minecraft:chests/desert_pyramid", "minecraft:chests/jungle_temple", - "minecraft:chests/stronghold_corridor", "minecraft:chests/stronghold_crossing", - "minecraft:chests/stronghold_library", "minecraft:chests/igloo_chest", "minecraft:chests/woodland_mansion", - "minecraft:chests/end_city_treasure"}; - - @SubscribeEvent - public static void onLootTableLoadEvent(LootTableLoadEvent event){ - if(Wizardry.settings.generateLoot){ - for(String location : LOOT_INJECTION_LOCATIONS){ - if(event.getName().toString().matches(location)){ - event.getTable().addPool(getAdditive(Wizardry.MODID + ":chests/dungeon_additions")); - } - } - } - } - - private static LootPool getAdditive(String entryName){ - return new LootPool(new LootEntry[]{getAdditiveEntry(entryName, 1)}, new LootCondition[0], - new RandomValueRange(1), new RandomValueRange(0, 1), Wizardry.MODID + "_additive_pool"); - } - - private static LootEntryTable getAdditiveEntry(String name, int weight){ - return new LootEntryTable(new ResourceLocation(name), weight, 0, new LootCondition[0], - Wizardry.MODID + "_additive_entry"); - } + private WizardryEventHandler(){} // No instances! @SubscribeEvent public static void onPlayerLoggedInEvent(PlayerLoggedInEvent event){ - // When a player logs in, they are sent the glyph data and the server's settings. + // When a player logs in, they are sent the glyph data, server settings and spell properties. if(event.player instanceof EntityPlayerMP){ SpellGlyphData.get(event.player.world).sync((EntityPlayerMP)event.player); + SpellEmitterData.get(event.player.world).sync((EntityPlayerMP)event.player); Wizardry.settings.sync((EntityPlayerMP)event.player); + syncAdvancements((EntityPlayerMP)event.player, false); + } + Spell.syncProperties(event.player); + } + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void onPlaySoundAtEntityEvent(PlaySoundAtEntityEvent event){ + // Muffle (there's no spell class for it so it's here instead) + if(event.getEntity() instanceof EntityLivingBase + && ((EntityLivingBase)event.getEntity()).isPotionActive(WizardryPotions.muffle)){ + event.setCanceled(true); } } @SubscribeEvent + public static void onAdvancementEvent(AdvancementEvent event){ + // Forge has no hook for revoked advancements :( + // Guess we'll just have to make do + // Also, this seems to get fired on player login, so to prevent the toasts from appearing every login the + // only way I can see to do it is by testing the player has been around long enough. + if(event.getEntityPlayer() instanceof EntityPlayerMP && event.getEntityPlayer().ticksExisted > 0){ + syncAdvancements((EntityPlayerMP)event.getEntityPlayer(), true); + } + } + + private static void syncAdvancements(EntityPlayerMP player, boolean showToasts){ + + Wizardry.logger.info("Synchronising advancements for " + player.getName()); + + ArrayList advancements = new ArrayList<>(); + + for(Advancement advancement : player.getServer().getAdvancementManager().getAdvancements()){ + if(player.getAdvancements().getProgress(advancement).isDone()) advancements.add(advancement.getId()); + } + + WizardryPacketHandler.net.sendTo(new PacketSyncAdvancements.Message(showToasts, advancements.toArray(new ResourceLocation[0])), player); + } + + @SubscribeEvent(priority = EventPriority.HIGH) // Disabling of specific spells comes after arcane jammer but before everything else public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ + + boolean enabled = true; + + switch(event.getSource()){ + case WAND: enabled = event.getSpell().isEnabled(SpellProperties.Context.WANDS); break; + case SCROLL: enabled = event.getSpell().isEnabled(SpellProperties.Context.SCROLL); break; + case COMMAND: enabled = event.getSpell().isEnabled(SpellProperties.Context.COMMANDS); break; + case NPC: enabled = event.getSpell().isEnabled(SpellProperties.Context.NPCS); break; + case DISPENSER: enabled = event.getSpell().isEnabled(SpellProperties.Context.DISPENSERS); break; + case OTHER: enabled = event.getSpell().isEnabled(); break; // Any enabled context will do for this one + } + // If a spell is disabled in the config, it will not work. - if(!event.getSpell().isEnabled()){ - if(!event.getEntityLiving().world.isRemote) event.getEntity().sendMessage( + if(!enabled){ + if(event.getCaster() != null && !event.getCaster().world.isRemote) event.getCaster().sendMessage( new TextComponentTranslation("spell.disabled", event.getSpell().getNameForTranslationFormatted())); event.setCanceled(true); } @@ -123,32 +140,36 @@ public final class WizardryEventHandler { @SubscribeEvent public static void onSpellCastPostEvent(SpellCastEvent.Post event){ - // Spell discovery (only players can discover spells, obviously) - if(event.getEntity() instanceof EntityPlayer){ + if(event.getCaster() instanceof EntityPlayer){ - EntityPlayer player = (EntityPlayer)event.getEntity(); + EntityPlayer player = (EntityPlayer)event.getCaster(); + // Advancement triggers + if(player instanceof EntityPlayerMP){ + WizardryAdvancementTriggers.cast_spell.trigger((EntityPlayerMP)player, event.getSpell(), player.getHeldItem(player.getActiveHand())); + } + + // Spell discovery (only players can discover spells, obviously) WizardData data = WizardData.get(player); if(data != null){ // Data is updated on both sides (This line was added client-side to fix a bug back in 1.1.3, so now // it's in common code, which is nice!) // Short-circuiting AND means that discoverSpell is only called if the event isn't cancelled. - if(!MinecraftForge.EVENT_BUS - .post(new DiscoverSpellEvent(player, event.getSpell(), DiscoverSpellEvent.Source.CASTING)) + if(!MinecraftForge.EVENT_BUS.post(new DiscoverSpellEvent(player, event.getSpell(), DiscoverSpellEvent.Source.CASTING)) && data.discoverSpell(event.getSpell())){ // If the spell wasn't already discovered, other stuff happens: if(event.getSource() == SpellCastEvent.Source.COMMAND){ // If the spell didn't send a packet itself, the extended player needs to be synced so the // spell discovery updates on the client. - if(!event.getSpell().doesSpellRequirePacket()) data.sync(); + if(!event.getSpell().requiresPacket()) data.sync(); - }else if(!event.getEntity().world.isRemote && !player.capabilities.isCreativeMode + }else if(!event.getCaster().world.isRemote && !player.isCreative() && Wizardry.settings.discoveryMode){ // Sound and text only happen server-side, in survival, with discovery mode on, and only when // the spell wasn't cast using commands. - WizardryUtilities.playSoundAtPlayer(player, SoundEvents.ENTITY_PLAYER_LEVELUP, 1.25f, 1); + WizardryUtilities.playSoundAtPlayer(player, WizardrySounds.MISC_DISCOVER_SPELL, 1.25f, 1); player.sendMessage(new TextComponentTranslation("spell.discover", event.getSpell().getNameForTranslationFormatted())); } @@ -157,33 +178,59 @@ public final class WizardryEventHandler { } } + @SubscribeEvent(priority = EventPriority.LOW) + public static void onDiscoverSpellEvent(DiscoverSpellEvent event){ + if(event.getEntityPlayer() instanceof EntityPlayerMP){ + WizardryAdvancementTriggers.discover_spell.trigger((EntityPlayerMP)event.getEntityPlayer(), event.getSpell(), event.getSource()); + } + } + + @SubscribeEvent + public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){ + + if(event.getTarget() != null && event.getEntityLiving() instanceof EntityLiving + && event.getTarget().isPotionActive(WizardryPotions.muffle)){ + + Vec3d vec = event.getTarget().getPositionEyes(1).subtract(event.getEntity().getPositionEyes(1)); + // Find the angle between the direction the mob is looking and the direction the player is in + // Angle between a and b = acos((a.b) / (|a|*|b|)) + double angle = Math.acos(vec.dotProduct(event.getEntity().getLookVec()) / vec.length()); + System.out.println(angle); + // If the player is not within the 144-degree arc in front of the mob, it won't detect them + if(angle > 0.4 * Math.PI){ + ((EntityLiving)event.getEntityLiving()).setAttackTarget(null); + } + } + } + /* There is a subtle but important difference between LivingAttackEvent and LivingHurtEvent - LivingAttackEvent * fires immediately when attackEntityFrom is called, whereas LivingHurtEvent only fires if the attack actually * succeeded, i.e. if the entity in question takes damage (though the event is fired before that so you can cancel - * the damage). Things are processed in the following order: * LivingAttackEvent * - Invulnerability - - * Already-dead-ness - Fire resistance - Helmets vs. falling things - Hurt resistant time - Invulnerability (again) - * * LivingHurtEvent * - Armour - Potions - Health is finally changed Of course, there are no guarantees that other + * the damage). Things are processed in the following order: + * + * * LivingAttackEvent * + * - Invulnerability + * - Already-dead-ness + * - Fire resistance + * - Helmets vs. falling things + * - Hurt resistant time + * - Invulnerability (again) + * * LivingHurtEvent * + * - Armour + * - Potions + * * LivingDamageEvent * + * - Health is finally changed + * + * Of course, there are no guarantees that other * mods hooking into these two events will be called before or after yours, but you can have some degree of control * by choosing which event to use. EDIT: Actually, there are. Firstly, you can set a priority in the @SubscribeEvent * annotation which defines how early (higher priority) or late (lower priority) the method is called. Methods with * the same priority are sorted alphabetically by mod id (so it's safe to assume wizardry would be fairly late on!). * I wonder if there are any conventions for what sort of things take what priority...? */ - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOW) // Low priority in case the event gets cancelled at default priority public static void onLivingAttackEvent(LivingAttackEvent event){ - // Prevents any damage to allies from magic if friendly fire is disabled - if(!Wizardry.settings.friendlyFire && event.getSource() != null - && event.getSource().getTrueSource() instanceof EntityPlayer && event.getEntity() instanceof EntityPlayer - && event.getSource() instanceof IElementalDamage){ - if(WizardryUtilities.isPlayerAlly((EntityPlayer)event.getSource().getTrueSource(), - (EntityPlayer)event.getEntity())){ - event.setCanceled(true); - // This needs to be here, since if the event is cancelled nothing else needs to happen. - return; - } - } - // Retaliatory effects // These are better off here because the revenge effects are pretty similar, and I'd rather keep the (lengthy) // if statement in one place. @@ -194,38 +241,43 @@ public final class WizardryEventHandler { EntityLivingBase attacker = (EntityLivingBase)event.getSource().getTrueSource(); World world = event.getEntityLiving().world; - // Fireskin - if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin) - && !MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving())) - attacker.setFire(5); + if(attacker.getDistance(event.getEntityLiving()) < 10){ - // Ice Shroud - if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud) - && !MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()) - && !(event.getEntityLiving() instanceof FakePlayer)) - attacker.addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0)); + // Fireskin + if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin) + && !MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving())) + attacker.setFire(Spells.fire_breath.getProperty(Spell.BURN_DURATION).intValue()); - // Static Aura - if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura)){ + // Ice Shroud + if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud) + && !MagicDamage.isEntityImmune(DamageType.FROST, event.getEntityLiving()) + && !(attacker instanceof FakePlayer)) // Fake players cause problems + attacker.addPotionEffect(new PotionEffect(WizardryPotions.frost, + Spells.ice_shroud.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.ice_shroud.getProperty(Spell.EFFECT_STRENGTH).intValue())); - if(world.isRemote){ - - ParticleBuilder.create(Type.LIGHTNING).entity(event.getEntity()).pos(0, event.getEntity().height/2, 0) - .target(attacker).spawn(world); - - ParticleBuilder.spawnShockParticles(world, attacker.posX, - attacker.getEntityBoundingBox().minY + attacker.height, attacker.posZ); + // Static Aura + if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura)){ + + if(world.isRemote){ + + ParticleBuilder.create(Type.LIGHTNING).entity(event.getEntity()).pos(0, event.getEntity().height / 2, 0) + .target(attacker).spawn(world); + + ParticleBuilder.spawnShockParticles(world, attacker.posX, + attacker.getEntityBoundingBox().minY + attacker.height / 2, attacker.posZ); + } + + DamageSafetyChecker.attackEntitySafely(attacker, MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), + DamageType.SHOCK, true), Spells.static_aura.getProperty(Spell.DAMAGE).floatValue(), event.getSource().getDamageType()); + attacker.playSound(WizardrySounds.SPELL_STATIC_AURA_RETALIATE, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); } - - DamageSafetyChecker.attackEntitySafely(attacker, MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), - DamageType.SHOCK, true), 4.0f, event.getSource().getDamageType()); - attacker.playSound(WizardrySounds.SPELL_STATIC_AURA_RETALIATE, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); } } } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOW) // Again, we don't want these effects if the event is cancelled public static void onLivingHurtEvent(LivingHurtEvent event){ // Flaming and freezing swords @@ -234,7 +286,7 @@ public final class WizardryEventHandler { EntityLivingBase attacker = (EntityLivingBase)event.getSource().getTrueSource(); // Players can only ever attack with their main hand, so this is the right method to use here. - if(!attacker.getHeldItemMainhand().isEmpty() && attacker.getHeldItemMainhand().getItem() instanceof ItemSword){ + if(!attacker.getHeldItemMainhand().isEmpty() && ImbueWeapon.isSword(attacker.getHeldItemMainhand().getItem())){ int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, attacker.getHeldItemMainhand()); @@ -275,30 +327,13 @@ public final class WizardryEventHandler { @SubscribeEvent public static void onLivingUpdateEvent(LivingUpdateEvent event){ - if(event.getEntityLiving() instanceof EntityPlayer){ - - EntityPlayer player = (EntityPlayer)event.getEntityLiving(); - - if(player.world.isRemote) hackilyFixContinuousSpellCasting(player); - - // Mana flask crafting - if(player.openContainer instanceof ContainerWorkbench){ - - IInventory craftMatrix = ((ContainerWorkbench)player.openContainer).craftMatrix; - ItemStack output = ((ContainerWorkbench)player.openContainer).craftResult.getStackInSlot(0); - processManaFlaskCrafting(craftMatrix, output); - - }else if(player.openContainer instanceof ContainerPlayer){ - - IInventory craftMatrix = ((ContainerPlayer)player.openContainer).craftMatrix; - ItemStack output = ((ContainerPlayer)player.openContainer).craftResult.getStackInSlot(0); - // Unfortunately I have no choice but to call this method every tick when the player isn't using another - // inventory, since the only thing tracking whether the player is looking at their inventory is the GUI - // itself, which is client-side only. - processManaFlaskCrafting(craftMatrix, output); - } - - } + // Experimental animation feature +// if(event.getEntityLiving().isHandActive() && event.getEntityLiving().getActiveItemStack().getItemUseAction() == WizardryUtilities.POINT){ +// event.getEntityLiving().isSwingInProgress = true; +// event.getEntityLiving().swingProgress = 1f; +// event.getEntityLiving().prevSwingProgress = 1; +// event.getEntityLiving().swingingHand = event.getEntityLiving().getActiveHand(); +// } if(event.getEntityLiving().world.isRemote){ @@ -309,13 +344,14 @@ public final class WizardryEventHandler { Spell spell = ((ISpellCaster)event.getEntity()).getContinuousSpell(); SpellModifiers modifiers = ((ISpellCaster)event.getEntity()).getModifiers(); - if(spell != null && spell != Spells.none){ + if(spell != null && spell != Spells.none){ // IntelliJ is wrong, do NOT remove the null check! - if(!MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(event.getEntityLiving(), spell, modifiers, - SpellCastEvent.Source.NPC, 0))){ + if(!MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(SpellCastEvent.Source.NPC, spell, event.getEntityLiving(), + modifiers, 0))){ spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, 0, // TODO: This implementation of modifiers relies on them being accessible client-side. + // Right now that doesn't matter because NPCs don't use modifiers, but they might in future ((EntityLiving)event.getEntity()).getAttackTarget(), modifiers); } } @@ -323,7 +359,7 @@ public final class WizardryEventHandler { } } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOWEST) // No siphoning if the event is cancelled, that could be exploited... public static void onLivingDeathEvent(LivingDeathEvent event){ if(event.getSource().getTrueSource() instanceof EntityPlayer){ @@ -332,108 +368,83 @@ public final class WizardryEventHandler { for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){ - if(stack.getItem() instanceof ItemWand && stack.isItemDamaged() + if(stack.getItem() instanceof IManaStoringItem && !((IManaStoringItem)stack.getItem()).isManaFull(stack) && WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) > 0){ - int damage = stack.getItemDamage() - - Constants.SIPHON_MANA_PER_LEVEL + + int mana = Constants.SIPHON_MANA_PER_LEVEL * WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) - - player.world.rand.nextInt(Constants.SIPHON_MANA_PER_LEVEL); - if(damage < 0) damage = 0; - stack.setItemDamage(damage); - break; + + player.world.rand.nextInt(Constants.SIPHON_MANA_PER_LEVEL); + + if(ItemArtefact.isArtefactActive(player, WizardryItems.ring_siphoning)) mana *= 1.3f; + + ((IManaStoringItem)stack.getItem()).rechargeMana(stack, mana); + + break; // Only recharge one item per kill + } + } + } + } + + // These two are lifted from EntityLivingBase#travel + private static final double LIVING_ENTITY_GRAVITY = 0.08; + private static final double LIVING_ENTITY_DRAG = 0.98; + + private static final double LIVING_ENTITY_TERMINAL_VELOCITY = 3.92; // From Minecraft Wiki! + + private static final double LOG_LIVING_ENTITY_DRAG = Math.log(LIVING_ENTITY_DRAG); + private static final double FALL_TICKS_ERROR_CORRECTION = 0.500841776608447; + + @SubscribeEvent // Priority doesn't matter here, we're only setting event fields so if it's cancelled it won't matter + public static void onLivingFallEvent(LivingFallEvent event){ + // Why is fall damage based on distance fallen? Why? Who on earth came up with that? It makes no sense whatsoever! + if(Wizardry.settings.replaceVanillaFallDamage && !Loader.isModLoaded("speedbasedfalldamage")){ + // We want to keep the fall damage EXACTLY THE SAME for free, uninterrupted falls, but fix the weirdness + // caused when something else changes the entity's velocity + // All living entities have a gravity of 0.08b/t^2 + // Therefore it would be simple to say v^2 = u^2 + 2gs gives the equivalent fall distance as motionY^2 / 0.16 + // However, Minecraft also has a drag of 0.02 * the velocity, so we actually expect a slightly different value + // Much maths later... + + double v = event.getEntity().motionY; + // Players are weird, their velocity somehow resets on the server just before this event fires so + // instead we're storing the y velocity from the previous tick in WizardData and retrieving it here + // Of course, if another mod screws things up and sets a player's velocity client-side only then this won't + // work ...but it's better than having clients calculate their own fall damage + if(event.getEntity() instanceof EntityPlayer){ + WizardData data = WizardData.get((EntityPlayer)event.getEntity()); + if(data != null){ + v = data.prevMotionY; } } - if(event.getEntityLiving() == player && event.getSource() instanceof IElementalDamage){ - WizardryAdvancementTriggers.self_destruct.triggerFor(player); - } - } - } + // At terminal velocity, there's no way of finding fall distance from velocity, and the entity is probably dead anyway! + if(v > -3.9){ - @SubscribeEvent - public static void onLivingDropsEvent(LivingDropsEvent event){ - // TODO: Really, this should be in a loot table (mob_additions), however I can't seem to find a way of - // automatically adding it to all subclasses of IMob. - // Evil wizards drop spell books themselves - if(event.getEntityLiving() instanceof IMob && !(event.getEntityLiving() instanceof EntityEvilWizard) - // TODO: Backport when you backport the new summoned creature system. - && !(event.getEntityLiving() instanceof ISummonedCreature) - && event.getSource().getTrueSource() instanceof EntityPlayer && Wizardry.settings.spellBookDropChance > 0){ + // Just to make the code more readable, java will replace them all with numbers anyway + double g = LIVING_ENTITY_GRAVITY; + double f = LIVING_ENTITY_DRAG; + double lnf = LOG_LIVING_ENTITY_DRAG; + double tv = LIVING_ENTITY_TERMINAL_VELOCITY; - // This does exactly what the entity drop method does, but with a different random number so that the - // spell book doesn't always drop with other rare drops. - int rareDropNumber = event.getEntity().world.rand.nextInt(200) - event.getLootingLevel(); - if(rareDropNumber < Wizardry.settings.spellBookDropChance){ - // Drops a spell book - int id = WizardryUtilities.getStandardWeightedRandomSpellId(event.getEntity().world.rand); + // Work backwards from y velocity to get fall time + // logs are probably slow but it's not like this gets calculated every tick, and we only need one log + double t = Math.log(((-v - tv) * lnf) / g) / lnf; // Log the number over log the base - event.getDrops() - .add(new EntityItem(event.getEntityLiving().world, event.getEntityLiving().posX, - event.getEntityLiving().posY, event.getEntityLiving().posZ, - new ItemStack(WizardryItems.spell_book, 1, id))); - } - } - } + // Because time is in discrete ticks, the above equation for t results in a constant error of + // +0.500841776608447, so I guess we can just subtract it... if it works it works I guess! + t -= FALL_TICKS_ERROR_CORRECTION; // Don't cast to int or perform any rounding - // Private helper methods - // ================================================================================================================ + // Now work forwards from t to find the effective fall distance, i.e. the distance the entity would + // have to freefall to reach the same velocity + // Don't ask me where the 196 is from, again, it just works! + double y = (g * Math.pow(f, t)) / (lnf*lnf) + tv * (t) - 196; - /** - * Detects inconsistencies between player.getActiveItemStack and the actual itemstack and forces them to be equal. - * Fixes issue #25. - * - * @param player - */ - private static void hackilyFixContinuousSpellCasting(EntityPlayer player){ - if(player.isHandActive() && player.getHeldItem(player.getActiveHand()).getItem() instanceof ItemWand - && WandHelper.getCurrentSpell(player.getHeldItem(player.getActiveHand())).isContinuous){ - if(player.getActiveItemStack() != player.getHeldItem(player.getActiveHand())){ - player.setHeldItem(player.getActiveHand(), player.getActiveItemStack()); - } - } - } + // DEBUG +// if(event.getEntity() instanceof EntityPlayer){ +// Wizardry.logger.info("Replaced fall distance {} with effective distance {} based on entity velocity", event.getDistance(), y); +// } - private static void processManaFlaskCrafting(IInventory craftMatrix, ItemStack output){ - - // Charges wand using mana flask. It is here rather than in the crafting handler so the result displays - // the proper damage before it is actually crafted. - - boolean flag = false; - ItemStack wand = ItemStack.EMPTY; - ItemStack armour = ItemStack.EMPTY; - - for(int i = 0; i < craftMatrix.getSizeInventory(); i++){ - - ItemStack itemstack = craftMatrix.getStackInSlot(i); - - if(itemstack.getItem() == WizardryItems.mana_flask){ - flag = true; - } - - if(itemstack.getItem() instanceof ItemWand){ - wand = itemstack; - } - - if(itemstack.getItem() instanceof ItemWizardArmour){ - armour = itemstack; - } - } - - if(output.getItem() instanceof ItemWand && flag && !wand.isEmpty()){ - output.setTagCompound((wand.getTagCompound())); - if(wand.getItemDamage() - Constants.MANA_PER_FLASK < 0){ - output.setItemDamage(0); - }else{ - output.setItemDamage(wand.getItemDamage() - Constants.MANA_PER_FLASK); - } - } - - if(output.getItem() instanceof ItemWizardArmour && flag && !armour.isEmpty()){ - output.setTagCompound((armour.getTagCompound())); - if(armour.getItemDamage() - Constants.MANA_PER_FLASK < 0){ - output.setItemDamage(0); - }else{ - output.setItemDamage(wand.getItemDamage() - Constants.MANA_PER_FLASK); + event.setDistance((float)y); } } } diff --git a/src/main/java/electroblob/wizardry/WizardryGuiFactory.java b/src/main/java/electroblob/wizardry/WizardryGuiFactory.java index 169c473e..a6ef1190 100644 --- a/src/main/java/electroblob/wizardry/WizardryGuiFactory.java +++ b/src/main/java/electroblob/wizardry/WizardryGuiFactory.java @@ -1,12 +1,12 @@ package electroblob.wizardry; -import java.util.Set; - -import electroblob.wizardry.client.gui.GuiConfigWizardry; +import electroblob.wizardry.client.gui.config.GuiConfigWizardry; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraftforge.fml.client.IModGuiFactory; +import java.util.Set; + public class WizardryGuiFactory implements IModGuiFactory { @Override diff --git a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java index 5bd9364c..140ed107 100644 --- a/src/main/java/electroblob/wizardry/WizardryGuiHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryGuiHandler.java @@ -1,6 +1,5 @@ package electroblob.wizardry; -import electroblob.wizardry.client.gui.handbook.GuiWizardHandbook; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.item.ItemWizardHandbook; import electroblob.wizardry.spell.Spell; @@ -46,12 +45,12 @@ public class WizardryGuiHandler implements IGuiHandler { } }else if(id == WIZARD_HANDBOOK && (player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook || player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook)){ - return new GuiWizardHandbook(); + return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook(); }else if(id == SPELL_BOOK){ if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){ - return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.get(player.getHeldItemMainhand().getItemDamage())); + return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemMainhand().getItemDamage())); }else if(player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){ - return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.get(player.getHeldItemOffhand().getItemDamage())); + return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemOffhand().getItemDamage())); } }else if(id == PORTABLE_CRAFTING){ return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z)); diff --git a/src/main/java/electroblob/wizardry/WizardryWorldGenerator.java b/src/main/java/electroblob/wizardry/WizardryWorldGenerator.java deleted file mode 100644 index 4283a41e..00000000 --- a/src/main/java/electroblob/wizardry/WizardryWorldGenerator.java +++ /dev/null @@ -1,949 +0,0 @@ -package electroblob.wizardry; - -import java.util.HashSet; -import java.util.Random; -import java.util.Set; - -import org.apache.commons.lang3.ArrayUtils; - -import electroblob.wizardry.entity.living.EntityEvilWizard; -import electroblob.wizardry.entity.living.EntityWizard; -import electroblob.wizardry.registry.WizardryBlocks; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.block.BlockChest; -import net.minecraft.block.BlockColored; -import net.minecraft.block.BlockLeaves; -import net.minecraft.block.BlockLiquid; -import net.minecraft.block.BlockPlanks; -import net.minecraft.block.BlockSlab; -import net.minecraft.block.BlockSlab.EnumBlockHalf; -import net.minecraft.block.BlockTorch; -import net.minecraft.block.state.IBlockState; -import net.minecraft.init.Biomes; -import net.minecraft.init.Blocks; -import net.minecraft.inventory.IInventory; -import net.minecraft.item.EnumDyeColor; -import net.minecraft.item.ItemDoor; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.gen.IChunkGenerator; -import net.minecraft.world.gen.feature.WorldGenMinable; -import net.minecraft.world.storage.loot.LootContext; -import net.minecraft.world.storage.loot.LootTable; -import net.minecraftforge.common.BiomeDictionary; -import net.minecraftforge.common.IPlantable; -import net.minecraftforge.fml.common.IWorldGenerator; - -public class WizardryWorldGenerator implements IWorldGenerator { - - /** The string identifier for wizard tower chests, used in ChestGenHooks. */ - public static final String WIZARD_TOWER = Wizardry.MODID + "wizardTower"; - - @Override - public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, - IChunkProvider chunkProvider){ - - for(int id : Wizardry.settings.oreDimensions){ - if(id == world.provider.getDimension()) this.addOreSpawn(WizardryBlocks.crystal_ore.getDefaultState(), - world, random, chunkX * 16, chunkZ * 16, 16, 16, 5, 7, 5, 30); - } - - for(int id : Wizardry.settings.flowerDimensions){ - if(id == world.provider.getDimension()) this.generatePlant(WizardryBlocks.crystal_flower.getDefaultState(), - world, random, chunkX * 16, chunkZ * 16, 2, 20); - } - - if(world.getWorldInfo().isMapFeaturesEnabled()){ - for(int id : Wizardry.settings.towerDimensions){ - if(id == world.provider.getDimension()) - this.generateWizardTower(world, random, chunkX * 16, chunkZ * 16); - } - } - } - - /** - * Adds an Ore Spawn to Minecraft. Simply register all Ores to spawn with this method in your Generation method in - * your IWorldGeneration extending Class - * - * @param The Block to spawn - * @param The World to spawn in - * @param A Random object for retrieving random positions within the world to spawn the Block - * @param An int for passing the X-Coordinate for the Generation method - * @param An int for passing the Z-Coordinate for the Generation method - * @param An int for setting the maximum X-Coordinate values for spawning on the X-Axis on a Per-Chunk basis - * @param An int for setting the maximum Z-Coordinate values for spawning on the Z-Axis on a Per-Chunk basis - * @param An int for setting the maximum size of a vein - * @param An int for the Number of chances available for the Block to spawn per-chunk - * @param An int for the minimum Y-Coordinate height at which this block may spawn - * @param An int for the maximum Y-Coordinate height at which this block may spawn - **/ - public void addOreSpawn(IBlockState state, World world, Random random, int blockXPos, int blockZPos, int maxX, - int maxZ, int maxVeinSize, int chancesToSpawn, int minY, int maxY){ - // int maxPossY = minY + (maxY - 1); - assert maxY > minY : "The maximum Y must be greater than the Minimum Y"; - assert maxX > 0 && maxX <= 16 : "addOreSpawn: The Maximum X must be greater than 0 and less than 16"; - assert minY > 0 : "addOreSpawn: The Minimum Y must be greater than 0"; - assert maxY < 256 && maxY > 0 : "addOreSpawn: The Maximum Y must be less than 256 but greater than 0"; - assert maxZ > 0 && maxZ <= 16 : "addOreSpawn: The Maximum Z must be greater than 0 and less than 16"; - - int diffBtwnMinMaxY = maxY - minY; - for(int x = 0; x < chancesToSpawn; x++){ - int posX = blockXPos + random.nextInt(maxX); - int posY = minY + random.nextInt(diffBtwnMinMaxY); - int posZ = blockZPos + random.nextInt(maxZ); - (new WorldGenMinable(state, maxVeinSize)).generate(world, random, new BlockPos(posX, posY, posZ)); - } - } - - /** - * Generates the specified plant randomly throughout the world. - * - * @param block The plant block - * @param world The world - * @param random A random instance - * @param x The x coord of the first block in the chunk - * @param z The y coord of the first block in the chunk - * @param chancesToSpawn Number of chances to spawn a flower patch - * @param groupSize The number of times to try generating a flower per flower patch spawn - */ - public void generatePlant(IBlockState state, World world, Random random, int x, int z, int chancesToSpawn, - int groupSize){ - - for(int i = 0; i < chancesToSpawn; i++){ - int randPosX = x + random.nextInt(16); - int randPosY = random.nextInt(256); - int randPosZ = z + random.nextInt(16); - for(int l = 0; l < groupSize; ++l){ - int i1 = randPosX + random.nextInt(8) - random.nextInt(8); - int j1 = randPosY + random.nextInt(4) - random.nextInt(4); - int k1 = randPosZ + random.nextInt(8) - random.nextInt(8); - - BlockPos pos = new BlockPos(i1, j1, k1); - - if(world.isBlockLoaded(pos) && world.isAirBlock(pos) && (!world.provider.isNether() || j1 < 127) - && state.getBlock().canPlaceBlockOnSide(world, pos, EnumFacing.UP)){ - - world.setBlockState(pos, state, 2); - } - } - } - } - - /** - * Generates wizard towers randomly throughout the world. - */ - public void generateWizardTower(World world, Random random, int chunkX, int chunkZ){ - - // Allows the config file to set the rarity value to 0 to disable tower generation completely. - if(Wizardry.settings.towerRarity == 0) return; - - // Compensates for the lack of space in forests. Math.max is required since treeless biomes have treesPerChunk = - // -999 - // double treeFactor = 70 - Math.max((double)world.getBiomeGenForCoords(chunkX, - // chunkZ).theBiomeDecorator.treesPerChunk, 0) * 1.5d; - - // Multiplied by 70 to (roughly) retain the old rarity scale - if(random.nextInt((int)(Wizardry.settings.towerRarity * 70)) == 0){ - - BlockPos origin = new BlockPos(chunkX + random.nextInt(16), 0, chunkZ + random.nextInt(16)); - - // Despite what its name suggests, this method does not return the position of a liquid. It is in fact - // exactly what is needed here since it is used for placing villages and stuff, and doesn't include leaves - // or other foliage. - origin = origin.up(world.getTopSolidOrLiquidBlock(origin).getY() - 1); - - int[][][] towerBlueprint = towerBlueprintSmall; - - switch(random.nextInt(4)){ - case 0: - towerBlueprint = towerBlueprintSmall; - break; - case 1: - towerBlueprint = towerBlueprintMedium; - break; - case 2: - towerBlueprint = towerBlueprintTall; - break; - case 3: - towerBlueprint = towerBlueprintDouble; - break; - } - - // 0 = West, 1 = North, 2 = East, 3 = South (The way you would face when walking out of the door) - EnumFacing orientation = EnumFacing.byHorizontalIndex(random.nextInt(4)); - boolean flip = random.nextBoolean(); - - if(checkSpaceForTower(world, origin, towerBlueprint, orientation, flip)){ - - // == Setup == - - boolean evilWizard = random.nextInt(5) == 0; - - IBlockState wallMaterial = Blocks.COBBLESTONE.getDefaultState(); - BlockPlanks.EnumType woodType = BlockPlanks.EnumType.OAK; - - Biome biome = world.getBiome(origin); - - // The order of these is somewhat important in that biomes can be many types, so the last of these - // checks - // that is true gets priority. Generally speaking, the later the check, the more specific it is. - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.DENSE)) - wallMaterial = Blocks.MOSSY_COBBLESTONE.getDefaultState(); - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.SWAMP)) - wallMaterial = Blocks.MOSSY_COBBLESTONE.getDefaultState(); - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.SANDY)) - wallMaterial = Blocks.SANDSTONE.getDefaultState(); - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.NETHER)) - wallMaterial = Blocks.NETHER_BRICK.getDefaultState(); - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.MOUNTAIN)) - wallMaterial = Blocks.STONEBRICK.getDefaultState(); - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.MESA)) - wallMaterial = Blocks.HARDENED_CLAY.getDefaultState(); - - // Unfortunately, I can't check all the wood types with the biome dictionary - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.CONIFEROUS)) - woodType = BlockPlanks.EnumType.SPRUCE; - if(biome == Biomes.BIRCH_FOREST || biome == Biomes.BIRCH_FOREST_HILLS) - woodType = BlockPlanks.EnumType.BIRCH; - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.JUNGLE)) woodType = BlockPlanks.EnumType.JUNGLE; - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.SAVANNA)) woodType = BlockPlanks.EnumType.ACACIA; - // Not technically a tree type, but I think it fits quite well anyway - if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.SPOOKY)) - woodType = BlockPlanks.EnumType.DARK_OAK; - - IBlockState[] blockStateList = new IBlockState[]{null, Blocks.AIR.getDefaultState(), - Blocks.PLANKS.getDefaultState().withProperty(BlockPlanks.VARIANT, woodType), - Blocks.BOOKSHELF.getDefaultState(), - Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(BlockColored.COLOR, - EnumDyeColor.values()[random.nextInt(EnumDyeColor.values().length)]), - Blocks.WOODEN_SLAB.getDefaultState().withProperty(BlockSlab.HALF, EnumBlockHalf.BOTTOM), - Blocks.WOODEN_SLAB.getDefaultState().withProperty(BlockSlab.HALF, EnumBlockHalf.TOP), - wallMaterial, Blocks.GLASS_PANE.getDefaultState(), Blocks.OAK_DOOR.getDefaultState(), - WizardryBlocks.arcane_workbench.getDefaultState(), Blocks.TORCH.getDefaultState(), - evilWizard ? Blocks.CHEST.getDefaultState() : Blocks.BOOKSHELF.getDefaultState()}; - - Set blocksPlaced = new HashSet(); - - // == Foundations == - - // Fills in foundations. This is done first so the door always has something to be placed on. - boolean flag = true; - - // BlockPos is immutable, so I'm not sure if simply saying pos1 = pos will be sufficient. - BlockPos layerCentre = new BlockPos(origin); - - // Stop when the bottom of the world is reached - while(flag && layerCentre.getY() > 0){ - - flag = false; - - for(BlockPos offset : foundationLayer){ - if(!world.isBlockNormalCube(layerCentre.add(offset), false)){ - world.setBlockState(layerCentre.add(offset), wallMaterial); - blocksPlaced.add(layerCentre.add(offset)); - // Keeps going as long as something was filled in. - flag = true; - } - } - - layerCentre = layerCentre.down(); - } - - // == Main Structure == - - // It is assumed that the width of the blueprint is the same all the way up, and that the layers are - // square. - int width = towerBlueprint[0].length - 1; - - // x, y and z are the position the block is being put in. - // x1, y and z1 are the position in the blueprint which determines which block is being placed. - - int x1 = 0, z1 = 0; - - for(int y = 0; y < towerBlueprint.length; y++){ - for(int z = 0; z < towerBlueprint[y].length; z++){ - for(int x = 0; x < towerBlueprint[y][z].length; x++){ - - BlockPos pos = origin.add(x - width / 2, y, z - width / 2); - - switch(orientation){ - case WEST: - x1 = flip ? width - x : x; - z1 = z; - break; - case NORTH: - x1 = z; - z1 = flip ? x : width - x; - break; - case EAST: - x1 = flip ? x : width - x; - z1 = width - z; - break; - case SOUTH: - x1 = width - z; - z1 = flip ? width - x : x; - break; - default: - break; - } - - if(blockStateList[towerBlueprint[y][z1][x1]] != null - && blockStateList[towerBlueprint[y][z1][x1]].getBlock() != Blocks.TORCH - && blockStateList[towerBlueprint[y][z1][x1]].getBlock() != Blocks.CHEST){ - - if(blockStateList[towerBlueprint[y][z1][x1]].getBlock() == Blocks.OAK_DOOR){ - // Rotates the door depending on whether flip is true. - ItemDoor.placeDoor( - world, pos, flip - ? EnumFacing.byHorizontalIndex(3 - orientation.getHorizontalIndex()) - .getOpposite() - : orientation.rotateYCCW(), - Blocks.OAK_DOOR, false); - }else{ - world.setBlockState(pos, blockStateList[towerBlueprint[y][z1][x1]], 2); - } - - blocksPlaced.add(pos); - - } - } - } - } - - // == Extras == - - // Torches are done afterwards so they don't fall off - // Chests are also done afterwards, because for some reason the chest decides which way round to face - // itself, after it has been placed, based on the surrounding blocks... but if it was placed during - // the rest of the tower generation, some of those blocks wouldn't exist, hence it must be done here. - for(int y = 0; y < towerBlueprint.length; y++){ - for(int z = 0; z < towerBlueprint[y].length; z++){ - for(int x = 0; x < towerBlueprint[y][z].length; x++){ - - BlockPos pos = origin.add(x - width / 2, y, z - width / 2); - - switch(orientation){ - case WEST: - x1 = flip ? width - x : x; - z1 = z; - break; - case NORTH: - x1 = z; - z1 = flip ? x : width - x; - break; - case EAST: - x1 = flip ? x : width - x; - z1 = width - z; - break; - case SOUTH: - x1 = width - z; - z1 = flip ? width - x : x; - break; - default: - break; - } - - if(blockStateList[towerBlueprint[y][z1][x1]] != null){ - - if(blockStateList[towerBlueprint[y][z1][x1]].getBlock() == Blocks.TORCH){ - if(placeTorch(world, pos, true)){ - blocksPlaced.add(pos); - }else{ - Wizardry.logger.info("Attempted to generate a torch at " + pos + " in " + world - + ", but failed!"); - } - } - - // World should always be a WorldServer, but it's worth checking anyway. - if(blockStateList[towerBlueprint[y][z1][x1]].getBlock() == Blocks.CHEST - && world instanceof WorldServer){ - if(placeChest(world, pos)){ - blocksPlaced.add(pos); - LootTable table = world.getLootTableManager().getLootTableFromLocation( - new ResourceLocation(Wizardry.MODID, "chests/wizard_tower")); - IInventory inventory = (IInventory)world.getTileEntity(pos); - LootContext context = new LootContext.Builder((WorldServer)world).build(); - table.fillInventory(inventory, random, context); - }else{ - Wizardry.logger.info("Attempted to generate a chest at " + pos + " in " + world - + ", but failed!"); - } - } - } - } - } - } - - if(evilWizard){ - - EntityEvilWizard wizard = new EntityEvilWizard(world); - wizard.hasTower = true; - wizard.setLocationAndAngles(origin.getX() + 1.5, origin.getY() + towerBlueprint.length - 9.5, - origin.getZ() + 1.5, 0, 0); - wizard.onInitialSpawn(world.getDifficultyForLocation(origin), null); - - world.spawnEntity(wizard); - - }else{ - - EntityWizard wizard = new EntityWizard(world); - wizard.setLocationAndAngles(origin.getX() + 1.5, origin.getY() + towerBlueprint.length - 9.5, - origin.getZ() + 1.5, 0, 0); - wizard.onInitialSpawn(world.getDifficultyForLocation(origin), null); - wizard.setTowerBlocks(blocksPlaced); - - world.spawnEntity(wizard); - } - } - } - } - - /** - * Places a torch at the given position in the given world and automatically assigns an appropriate state. Order of - * priority is U-S-W-N-E, or S-W-N-E-U if wallPriority is true. - * - * @param world The world to place the torch in. - * @param pos The position to place the torch at. - * @param wallPriority True to prioritise wall torches, false to prioritise floor torches. - * @return True if the torch was placed, false if it is not possible. - */ - private static boolean placeTorch(World world, BlockPos pos, boolean wallPriority){ - - for(EnumFacing facing : ArrayUtils.add(EnumFacing.HORIZONTALS, wallPriority ? 4 : 0, EnumFacing.UP)){ - if(world.isSideSolid(pos.offset(facing.getOpposite()), facing)){ - world.setBlockState(pos, Blocks.TORCH.getDefaultState().withProperty(BlockTorch.FACING, facing)); - return true; - } - } - - return false; - } - - /** - * Places a chest at the given position in the given world and automatically assigns an appropriate state. Order of - * priority is S-W-N-E. - * - * @param world The world to chest the torch in. - * @param pos The position to chest the torch at. - * @return True if the chest was placed, false if it is not possible. - */ - private static boolean placeChest(World world, BlockPos pos){ - - for(EnumFacing facing : EnumFacing.HORIZONTALS){ - if(world.isAirBlock(pos.offset(facing))){ - world.setBlockState(pos, Blocks.CHEST.getDefaultState().withProperty(BlockChest.FACING, facing)); - return true; - } - } - - return false; - } - - /** - * Checks whether a tower generated at the given coordinates will intersect any solid or liquid blocks. Only tests - * for liquids (not solid blocks) for the first four layers to account for the floor and for sloping terrain. - * - * @return True if none of the blocks which the tower would replace are solid or liquid. Dirt, stone etc., water and - * lava count, as do logs, but leaves and plants don't. - */ - private static boolean checkSpaceForTower(World world, BlockPos pos, int[][][] towerBlueprint, - EnumFacing orientation, boolean flip){ - - // x, y and z are the position the block is being put in. - // x1, y and z1 are the position in the blueprint which determines which block is being placed. - - int x1 = 0, z1 = 0; - - // It is assumed that the width of the blueprint is the same all the way up, and that the layers are square. - int width = towerBlueprint[0].length - 1; - - for(int y = 0; y < towerBlueprint.length; y++){ - for(int z = 0; z < towerBlueprint[y].length; z++){ - for(int x = 0; x < towerBlueprint[y][z].length; x++){ - - BlockPos pos1 = pos.add(x - width / 2, y, z - width / 2); - - switch(orientation){ - case WEST: - x1 = flip ? width - x : x; - z1 = z; - break; - case NORTH: - x1 = z; - z1 = flip ? x : width - x; - break; - case EAST: - x1 = flip ? x : width - x; - z1 = width - z; - break; - case SOUTH: - x1 = width - z; - z1 = flip ? width - x : x; - break; - default: - break; - } - - if(towerBlueprint[y][z1][x1] != 0 && !WizardryUtilities.canBlockBeReplacedB(world, pos1) - // TODO: Is this a better replacement for the subsequent two lines? - // && !world.getBlockState(pos1).getBlock().isFoliage(world, pos1) - && !(world.getBlockState(pos1).getBlock() instanceof IPlantable) - && !(world.getBlockState(pos1).getBlock() instanceof BlockLeaves) - && (y > 3 || world.getBlockState(pos1).getBlock() instanceof BlockLiquid)){ - return false; - } - } - } - } - - return true; - } - - /** Array of relative positions of each block in a layer of foundations. */ - private static final BlockPos[] foundationLayer = new BlockPos[]{new BlockPos(-2, 0, -1), new BlockPos(-2, 0, 0), - new BlockPos(-2, 0, 1), new BlockPos(2, 0, -1), new BlockPos(2, 0, 0), new BlockPos(2, 0, 1), - new BlockPos(-1, 0, -2), new BlockPos(0, 0, -2), new BlockPos(1, 0, -2), new BlockPos(-1, 0, 2), - new BlockPos(0, 0, 2), new BlockPos(1, 0, 2),}; - - /** - * 3D matrix of integers representing the different blocks which make up the wizard tower. The blocks corresponding - * to each integer are as follows (note that some blocks change depending on the biome): - *

    - * 0 Nothing (keep existing block)
    - * 1 Air (remove existing block)
    - * 2 Floor (planks)
    - * 3 Bookshelf
    - * 4 Roof (stained clay)
    - * 5 Floor slab (lower half)
    - * 6 Floor slab (upper half)
    - * 7 Wall (cobblestone by default)
    - * 8 Glass pane
    - * 9 Door (metadata is handled by the built-in vanilla method)
    - * 10 Arcane workbench
    - * 11 Torch (metadata is handled separately depending on adjacent blocks)
    - * 12 Chest (only generates if the wizard is evil, otherwise places a bookshelf instead) - */ - private static final int[][][] towerBlueprintSmall = { - // x is horizontal, z is vertical, y is layers - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 2, 2, 2, 0, 0, 0}, {0, 0, 0, 2, 2, 2, 0, 0, 0}, {0, 0, 0, 2, 2, 2, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 9, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 6, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 0, 7, 0, 0, 0}, {0, 0, 0, 11, 1, 11, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 11, 7, 0, 0}, {0, 0, 7, 5, 6, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 6, 7, 0, 0}, {0, 0, 7, 1, 1, 5, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 11, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 7, 2, 2, 2, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 2, 7, 0}, {0, 7, 5, 2, 2, 6, 2, 7, 0}, {0, 7, 2, 2, 2, 2, 2, 7, 0}, - {0, 0, 7, 2, 2, 2, 7, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 7, 3, 3, 3, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 10, 1, 3, 7, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 7, 11, 1, 11, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 8, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 1, 1, 3, 7, 0}, - {0, 0, 7, 11, 1, 11, 7, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 4, 7, 7, 7, 4, 0, 0}, {0, 4, 7, 1, 1, 1, 7, 4, 0}, - {4, 7, 1, 1, 1, 1, 3, 7, 4}, {4, 7, 1, 1, 1, 1, 3, 7, 4}, {4, 7, 1, 1, 1, 1, 12, 7, 4}, - {0, 4, 7, 1, 1, 1, 7, 4, 0}, {0, 0, 4, 7, 7, 7, 4, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, - {0, 4, 1, 1, 1, 1, 1, 4, 0}, {0, 4, 1, 1, 1, 1, 1, 4, 0}, {0, 4, 1, 1, 1, 1, 1, 4, 0}, - {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, - {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, - {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, - {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, - {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}}; - - /** - * 3D matrix of integers representing the different blocks which make up the wizard tower. The blocks corresponding - * to each integer are as follows (note that some blocks change depending on the biome): - *

    - * 0 Nothing (keep existing block)
    - * 1 Air (remove existing block)
    - * 2 Floor (planks)
    - * 3 Bookshelf
    - * 4 Roof (stained clay)
    - * 5 Floor slab (lower half)
    - * 6 Floor slab (upper half)
    - * 7 Wall (cobblestone by default)
    - * 8 Glass pane
    - * 9 Door (metadata is handled by the built-in vanilla method)
    - * 10 Arcane workbench
    - * 11 Torch (metadata is handled separately depending on adjacent blocks)
    - * 12 Chest (only generates if the wizard is evil, otherwise places a bookshelf instead) - */ - private static final int[][][] towerBlueprintMedium = { - // x is horizontal, z is vertical, y is layers - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 2, 2, 2, 0, 0, 0}, {0, 0, 0, 2, 2, 2, 0, 0, 0}, {0, 0, 0, 2, 2, 2, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 9, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 6, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 0, 7, 0, 0, 0}, {0, 0, 0, 11, 1, 11, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 11, 7, 0, 0}, {0, 0, 7, 5, 6, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 6, 7, 0, 0}, {0, 0, 7, 1, 1, 5, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 11, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 6, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 11, 7, 0, 0}, {0, 0, 7, 5, 6, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 6, 7, 0, 0}, {0, 0, 7, 1, 1, 5, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 11, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 7, 2, 2, 2, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 2, 7, 0}, {0, 7, 5, 2, 2, 6, 2, 7, 0}, {0, 7, 2, 2, 2, 2, 2, 7, 0}, - {0, 0, 7, 2, 2, 2, 7, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 7, 3, 3, 3, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 10, 1, 3, 7, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 7, 11, 1, 11, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 8, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 1, 1, 3, 7, 0}, - {0, 0, 7, 11, 1, 11, 7, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 4, 7, 7, 7, 4, 0, 0}, {0, 4, 7, 1, 1, 1, 7, 4, 0}, - {4, 7, 1, 1, 1, 1, 3, 7, 4}, {4, 7, 1, 1, 1, 1, 3, 7, 4}, {4, 7, 1, 1, 1, 1, 12, 7, 4}, - {0, 4, 7, 1, 1, 1, 7, 4, 0}, {0, 0, 4, 7, 7, 7, 4, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, - {0, 4, 1, 1, 1, 1, 1, 4, 0}, {0, 4, 1, 1, 1, 1, 1, 4, 0}, {0, 4, 1, 1, 1, 1, 1, 4, 0}, - {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, - {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, - {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, - {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, - {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}}; - - /** - * 3D matrix of integers representing the different blocks which make up the wizard tower. The blocks corresponding - * to each integer are as follows (note that some blocks change depending on the biome): - *

    - * 0 Nothing (keep existing block)
    - * 1 Air (remove existing block)
    - * 2 Floor (planks)
    - * 3 Bookshelf
    - * 4 Roof (stained clay)
    - * 5 Floor slab (lower half)
    - * 6 Floor slab (upper half)
    - * 7 Wall (cobblestone by default)
    - * 8 Glass pane
    - * 9 Door (metadata is handled by the built-in vanilla method)
    - * 10 Arcane workbench
    - * 11 Torch (metadata is handled separately depending on adjacent blocks)
    - * 12 Chest (only generates if the wizard is evil, otherwise places a bookshelf instead) - */ - private static final int[][][] towerBlueprintTall = { - // x is horizontal, z is vertical, y is layers - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 2, 2, 2, 0, 0, 0}, {0, 0, 0, 2, 2, 2, 0, 0, 0}, {0, 0, 0, 2, 2, 2, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 9, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 6, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 0, 7, 0, 0, 0}, {0, 0, 0, 11, 1, 11, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 11, 7, 0, 0}, {0, 0, 7, 5, 6, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 6, 7, 0, 0}, {0, 0, 7, 1, 1, 5, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 11, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 6, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 11, 7, 0, 0}, {0, 0, 7, 5, 6, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 6, 7, 0, 0}, {0, 0, 7, 1, 1, 5, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 11, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 6, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 11, 7, 0, 0}, {0, 0, 7, 5, 6, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 6, 7, 0, 0}, {0, 0, 7, 1, 1, 5, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 1, 6, 5, 7, 0, 0}, {0, 0, 7, 11, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, - {0, 0, 7, 5, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 7, 1, 1, 1, 7, 0, 0}, - {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 7, 2, 2, 2, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 2, 7, 0}, {0, 7, 5, 2, 2, 6, 2, 7, 0}, {0, 7, 2, 2, 2, 2, 2, 7, 0}, - {0, 0, 7, 2, 2, 2, 7, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 7, 3, 3, 3, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 10, 1, 3, 7, 0}, - {0, 0, 7, 1, 1, 1, 7, 0, 0}, {0, 0, 0, 7, 7, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 7, 11, 1, 11, 7, 0, 0}, - {0, 7, 1, 1, 1, 1, 3, 7, 0}, {0, 8, 1, 1, 1, 1, 3, 7, 0}, {0, 7, 1, 1, 1, 1, 3, 7, 0}, - {0, 0, 7, 11, 1, 11, 7, 0, 0}, {0, 0, 0, 7, 8, 7, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 4, 7, 7, 7, 4, 0, 0}, {0, 4, 7, 1, 1, 1, 7, 4, 0}, - {4, 7, 1, 1, 1, 1, 3, 7, 4}, {4, 7, 1, 1, 1, 1, 3, 7, 4}, {4, 7, 1, 1, 1, 1, 12, 7, 4}, - {0, 4, 7, 1, 1, 1, 7, 4, 0}, {0, 0, 4, 7, 7, 7, 4, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, - {0, 4, 1, 1, 1, 1, 1, 4, 0}, {0, 4, 1, 1, 1, 1, 1, 4, 0}, {0, 4, 1, 1, 1, 1, 1, 4, 0}, - {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, - {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, - {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, - {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 4, 1, 1, 1, 4, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, - {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 4, 4, 4, 0, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 0, 4, 4, 4, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 4, 1, 4, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0},}}; - - /** - * 3D matrix of integers representing the different blocks which make up the wizard tower. The blocks corresponding - * to each integer are as follows (note that some blocks change depending on the biome): - *

    - * 0 Nothing (keep existing block)
    - * 1 Air (remove existing block)
    - * 2 Floor (planks)
    - * 3 Bookshelf
    - * 4 Roof (stained clay)
    - * 5 Floor slab (lower half)
    - * 6 Floor slab (upper half)
    - * 7 Wall (cobblestone by default)
    - * 8 Glass pane
    - * 9 Door (metadata is handled by the built-in vanilla method)
    - * 10 Arcane workbench
    - * 11 Torch (metadata is handled separately depending on adjacent blocks)
    - * 12 Chest (only generates if the wizard is evil, otherwise places a bookshelf instead) - */ - private static final int[][][] towerBlueprintDouble = { - // x is horizontal, z is vertical, y is layers - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 1, 6, 5, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 9, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 5, 1, 1, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 7, 6, 1, 1, 7, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 11, 1, 11, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 7, 1, 1, 11, 7, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 5, 6, 1, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 7, 1, 1, 6, 7, 7, 7, 0, 0}, {0, 0, 0, 0, 7, 1, 1, 5, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 1, 6, 5, 7, 7, 7, 0, 0}, - {0, 0, 0, 0, 7, 11, 1, 1, 1, 1, 1, 7, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 7, 7, 0, 0}, - {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 5, 1, 1, 7, 7, 8, 7, 0}, - {0, 0, 0, 0, 7, 6, 1, 1, 1, 1, 1, 8, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 7, 8, 7, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 8, 7, 0, 4, 4, 4, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 7, 7, 7, 4}, - {0, 0, 0, 0, 7, 1, 1, 11, 7, 1, 1, 7, 4}, {0, 0, 0, 0, 7, 5, 6, 1, 7, 7, 7, 7, 4}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 4, 4, 4, 0}, - {0, 0, 0, 0, 7, 1, 1, 6, 7, 4, 1, 4, 0}, {0, 0, 0, 0, 7, 1, 1, 5, 7, 4, 4, 4, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 1, 6, 5, 7, 0, 4, 0, 0}, - {0, 0, 0, 0, 7, 11, 1, 1, 7, 4, 1, 4, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 4, 0, 0}, - {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 7, 5, 1, 1, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 4, 0, 0}, {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 7, 2, 2, 2, 7, 0, 0, 0, 0}, {0, 0, 0, 7, 1, 1, 1, 1, 2, 7, 0, 0, 0}, - {0, 0, 0, 7, 5, 2, 2, 6, 2, 7, 4, 0, 0}, {0, 0, 0, 7, 2, 2, 2, 2, 2, 7, 0, 0, 0}, - {0, 0, 0, 0, 7, 2, 2, 2, 7, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 7, 3, 3, 3, 7, 0, 0, 0, 0}, {0, 0, 0, 7, 1, 1, 1, 1, 3, 7, 0, 0, 0}, - {0, 0, 0, 7, 1, 1, 1, 1, 3, 7, 0, 0, 0}, {0, 0, 0, 7, 1, 1, 10, 1, 3, 7, 0, 0, 0}, - {0, 0, 0, 0, 7, 1, 1, 1, 7, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 7, 11, 1, 11, 7, 0, 0, 0, 0}, {0, 0, 0, 7, 1, 1, 1, 1, 3, 7, 0, 0, 0}, - {0, 0, 0, 8, 1, 1, 1, 1, 3, 7, 0, 0, 0}, {0, 0, 0, 7, 1, 1, 1, 1, 3, 7, 0, 0, 0}, - {0, 0, 0, 0, 7, 11, 1, 11, 7, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 7, 8, 7, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 7, 7, 7, 4, 0, 0, 0, 0}, - {0, 0, 0, 4, 7, 1, 1, 1, 7, 4, 0, 0, 0}, {0, 0, 4, 7, 1, 1, 1, 1, 3, 7, 4, 0, 0}, - {0, 0, 4, 7, 1, 1, 1, 1, 3, 7, 4, 0, 0}, {0, 0, 4, 7, 1, 1, 1, 1, 12, 7, 4, 0, 0}, - {0, 0, 0, 4, 7, 1, 1, 1, 7, 4, 0, 0, 0}, {0, 0, 0, 0, 4, 7, 7, 7, 4, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, {0, 0, 0, 4, 1, 1, 1, 1, 1, 4, 0, 0, 0}, - {0, 0, 0, 4, 1, 1, 1, 1, 1, 4, 0, 0, 0}, {0, 0, 0, 4, 1, 1, 1, 1, 1, 4, 0, 0, 0}, - {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, - {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 4, 1, 4, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 4, 1, 1, 1, 4, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 4, 1, 4, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 4, 1, 4, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 4, 1, 4, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},}}; - -} diff --git a/src/main/java/electroblob/wizardry/advancement/ArcaneWorkbenchTrigger.java b/src/main/java/electroblob/wizardry/advancement/ArcaneWorkbenchTrigger.java new file mode 100644 index 00000000..175f9cdf --- /dev/null +++ b/src/main/java/electroblob/wizardry/advancement/ArcaneWorkbenchTrigger.java @@ -0,0 +1,135 @@ +package electroblob.wizardry.advancement; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.advancements.critereon.AbstractCriterionInstance; +import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** Advancement trigger for things done in the arcane workbench. The majority of any + * ICriterionTrigger class is just boilerplate, and this is no exception. */ +public class ArcaneWorkbenchTrigger implements ICriterionTrigger { + + private final ResourceLocation id; + private final Map listeners = Maps.newHashMap(); + + public ArcaneWorkbenchTrigger(ResourceLocation id){ + this.id = id; + } + + public ResourceLocation getId(){ + return this.id; + } + + public void addListener(PlayerAdvancements advancements, Listener listener){ + + ArcaneWorkbenchTrigger.Listeners listeners = this.listeners.get(advancements); + + if(listeners == null){ + listeners = new ArcaneWorkbenchTrigger.Listeners(advancements); + this.listeners.put(advancements, listeners); + } + + listeners.add(listener); + } + + public void removeListener(PlayerAdvancements advancements, Listener listener){ + + ArcaneWorkbenchTrigger.Listeners listeners = this.listeners.get(advancements); + + if(listeners != null){ + listeners.remove(listener); + + if(listeners.isEmpty()){ + this.listeners.remove(advancements); + } + } + } + + public void removeAllListeners(PlayerAdvancements advancements){ + this.listeners.remove(advancements); + } + + public ArcaneWorkbenchTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){ + return new ArcaneWorkbenchTrigger.Instance(this.id, ItemPredicate.deserialize(json.get("item"))); + } + + public void trigger(EntityPlayerMP player, ItemStack stack){ + + ArcaneWorkbenchTrigger.Listeners listeners = this.listeners.get(player.getAdvancements()); + + if(listeners != null){ + listeners.trigger(stack); + } + } + + public static class Instance extends AbstractCriterionInstance { + + private final ItemPredicate item; + + public Instance(ResourceLocation criterionIn, ItemPredicate item){ + super(criterionIn); + this.item = item; + } + + public boolean test(ItemStack stack){ + return this.item.test(stack); + } + } + + static class Listeners { + + private final PlayerAdvancements playerAdvancements; + private final Set> listeners = Sets.newHashSet(); + + public Listeners(PlayerAdvancements advancements){ + this.playerAdvancements = advancements; + } + + public boolean isEmpty(){ + return this.listeners.isEmpty(); + } + + public void add(Listener listener){ + this.listeners.add(listener); + } + + public void remove(Listener listener){ + this.listeners.remove(listener); + } + + public void trigger(ItemStack stack){ + + List> list = null; + + for(Listener listener : this.listeners){ + + if(listener.getCriterionInstance().test(stack)){ + + if(list == null){ + list = Lists.newArrayList(); + } + + list.add(listener); + } + } + + if(list != null){ + for(Listener listener : list){ + listener.grantCriterion(this.playerAdvancements); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/util/CustomAdvancementTrigger.java b/src/main/java/electroblob/wizardry/advancement/CustomAdvancementTrigger.java similarity index 96% rename from src/main/java/electroblob/wizardry/util/CustomAdvancementTrigger.java rename to src/main/java/electroblob/wizardry/advancement/CustomAdvancementTrigger.java index 8fb2693a..21a1cf99 100644 --- a/src/main/java/electroblob/wizardry/util/CustomAdvancementTrigger.java +++ b/src/main/java/electroblob/wizardry/advancement/CustomAdvancementTrigger.java @@ -1,10 +1,9 @@ -package electroblob.wizardry.util; +package electroblob.wizardry.advancement; import com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; - import electroblob.wizardry.Wizardry; import net.minecraft.advancements.ICriterionInstance; import net.minecraft.advancements.ICriterionTrigger; @@ -34,7 +33,7 @@ public class CustomAdvancementTrigger implements ICriterionTrigger { + + private final ResourceLocation id; + private final Map listeners = Maps.newHashMap(); + + public SpellCastTrigger(ResourceLocation id){ + this.id = id; + } + + public ResourceLocation getId(){ + return this.id; + } + + public void addListener(PlayerAdvancements advancements, Listener listener){ + + SpellCastTrigger.Listeners listeners = this.listeners.get(advancements); + + if(listeners == null){ + listeners = new SpellCastTrigger.Listeners(advancements); + this.listeners.put(advancements, listeners); + } + + listeners.add(listener); + } + + public void removeListener(PlayerAdvancements advancements, Listener listener){ + + SpellCastTrigger.Listeners listeners = this.listeners.get(advancements); + + if(listeners != null){ + listeners.remove(listener); + + if(listeners.isEmpty()){ + this.listeners.remove(advancements); + } + } + } + + public void removeAllListeners(PlayerAdvancements advancements){ + this.listeners.remove(advancements); + } + + public SpellCastTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){ + return new SpellCastTrigger.Instance(this.id, SpellPredicate.deserialize(json.get("spell")), + ItemPredicate.deserialize(json.get("item"))); + } + + public void trigger(EntityPlayerMP player, Spell spell, ItemStack stack){ + + SpellCastTrigger.Listeners listeners = this.listeners.get(player.getAdvancements()); + + if(listeners != null){ + listeners.trigger(spell, stack); + } + } + + public static class Instance extends AbstractCriterionInstance { + + private final SpellPredicate spell; + private final ItemPredicate item; + + public Instance(ResourceLocation criterion, SpellPredicate spell, ItemPredicate item){ + super(criterion); + this.spell = spell; + this.item = item; + } + + public boolean test(Spell spell, ItemStack stack){ + return this.spell.test(spell) && item.test(stack); + } + } + + static class Listeners { + + private final PlayerAdvancements playerAdvancements; + private final Set> listeners = Sets.newHashSet(); + + public Listeners(PlayerAdvancements advancements){ + this.playerAdvancements = advancements; + } + + public boolean isEmpty(){ + return this.listeners.isEmpty(); + } + + public void add(Listener listener){ + this.listeners.add(listener); + } + + public void remove(Listener listener){ + this.listeners.remove(listener); + } + + public void trigger(Spell spell, ItemStack stack){ + + List> list = null; + + for(Listener listener : this.listeners){ + + if(listener.getCriterionInstance().test(spell, stack)){ + + if(list == null){ + list = Lists.newArrayList(); + } + + list.add(listener); + } + } + + if(list != null){ + for(Listener listener : list){ + listener.grantCriterion(this.playerAdvancements); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/advancement/SpellDiscoveryTrigger.java b/src/main/java/electroblob/wizardry/advancement/SpellDiscoveryTrigger.java new file mode 100644 index 00000000..f24fef36 --- /dev/null +++ b/src/main/java/electroblob/wizardry/advancement/SpellDiscoveryTrigger.java @@ -0,0 +1,143 @@ +package electroblob.wizardry.advancement; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.event.DiscoverSpellEvent; +import electroblob.wizardry.spell.Spell; +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.advancements.critereon.AbstractCriterionInstance; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.ResourceLocation; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** Advancement trigger that is triggered when a spell is discovered. The majority of any + * ICriterionTrigger class is just boilerplate, and this is no exception. */ +public class SpellDiscoveryTrigger implements ICriterionTrigger { + + private final ResourceLocation id; + private final Map listeners = Maps.newHashMap(); + + public SpellDiscoveryTrigger(ResourceLocation id){ + this.id = id; + } + + public ResourceLocation getId(){ + return this.id; + } + + public void addListener(PlayerAdvancements advancements, Listener listener){ + + SpellDiscoveryTrigger.Listeners listeners = this.listeners.get(advancements); + + if(listeners == null){ + listeners = new SpellDiscoveryTrigger.Listeners(advancements); + this.listeners.put(advancements, listeners); + } + + listeners.add(listener); + } + + public void removeListener(PlayerAdvancements advancements, Listener listener){ + + SpellDiscoveryTrigger.Listeners listeners = this.listeners.get(advancements); + + if(listeners != null){ + listeners.remove(listener); + + if(listeners.isEmpty()){ + this.listeners.remove(advancements); + } + } + } + + public void removeAllListeners(PlayerAdvancements advancements){ + this.listeners.remove(advancements); + } + + public SpellDiscoveryTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){ + + String s = JsonUtils.getString(json, "source"); + DiscoverSpellEvent.Source source = DiscoverSpellEvent.Source.byName(s); + if(source == null) throw new JsonSyntaxException("No such spell discovery source: " + s); + return new SpellDiscoveryTrigger.Instance(this.id, SpellPredicate.deserialize(json.get("spell")), source); + } + + public void trigger(EntityPlayerMP player, Spell spell, DiscoverSpellEvent.Source source){ + + SpellDiscoveryTrigger.Listeners listeners = this.listeners.get(player.getAdvancements()); + + if(listeners != null){ + listeners.trigger(spell, source); + } + } + + public static class Instance extends AbstractCriterionInstance { + + private final SpellPredicate spell; + private final DiscoverSpellEvent.Source source; + + public Instance(ResourceLocation criterion, SpellPredicate spell, DiscoverSpellEvent.Source source){ + super(criterion); + this.spell = spell; + this.source = source; + } + + public boolean test(Spell spell, DiscoverSpellEvent.Source source){ + return this.spell.test(spell) && source == this.source; + } + } + + static class Listeners { + + private final PlayerAdvancements playerAdvancements; + private final Set> listeners = Sets.newHashSet(); + + public Listeners(PlayerAdvancements advancements){ + this.playerAdvancements = advancements; + } + + public boolean isEmpty(){ + return this.listeners.isEmpty(); + } + + public void add(Listener listener){ + this.listeners.add(listener); + } + + public void remove(Listener listener){ + this.listeners.remove(listener); + } + + public void trigger(Spell spell, DiscoverSpellEvent.Source source){ + + List> list = null; + + for(Listener listener : this.listeners){ + + if(listener.getCriterionInstance().test(spell, source)){ + + if(list == null){ + list = Lists.newArrayList(); + } + + list.add(listener); + } + } + + if(list != null){ + for(Listener listener : list){ + listener.grantCriterion(this.playerAdvancements); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/advancement/SpellPredicate.java b/src/main/java/electroblob/wizardry/advancement/SpellPredicate.java new file mode 100644 index 00000000..24d6c694 --- /dev/null +++ b/src/main/java/electroblob/wizardry/advancement/SpellPredicate.java @@ -0,0 +1,117 @@ +package electroblob.wizardry.advancement; + +import com.google.common.collect.Streams; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.spell.Spell; +import net.minecraft.util.JsonUtils; + +import javax.annotation.Nullable; +import java.util.Arrays; + +/** Predicate used by advancement triggers to match spells. */ +public class SpellPredicate { + + public static final SpellPredicate ANY = new SpellPredicate(); + private final Spell spell; + private final Tier[] tiers; + private final Element[] elements; + + public SpellPredicate(){ + this.spell = null; + this.tiers = Tier.values(); + this.elements = Element.values(); + } + + public SpellPredicate(@Nullable Spell spell, Tier[] tiers, Element[] elements){ + this.spell = spell; + this.tiers = tiers; + this.elements = elements; + } + + public boolean test(Spell spell){ + + if(this.spell != null && spell != this.spell){ + return false; + }else if(!Arrays.asList(this.tiers).contains(spell.getTier())){ + return false; + }else if(!Arrays.asList(this.elements).contains(spell.getElement())){ + return false; + } + + return true; + } + + public static SpellPredicate deserialize(@Nullable JsonElement element){ + + if(element != null && !element.isJsonNull()){ + + JsonObject jsonobject = JsonUtils.getJsonObject(element, "spell"); + + Spell spell = null; + + if(jsonobject.has("spell")){ + + String s = JsonUtils.getString(jsonobject, "spell"); + spell = Spell.get(s); + + if(spell == null){ + throw new JsonSyntaxException("Unknown spell id '" + s + "'"); + } + } + + Tier[] tiers = Tier.values(); + + if(jsonobject.has("tiers")){ + try{ + JsonArray array = JsonUtils.getJsonArray(jsonobject, "tiers"); + tiers = Streams.stream(array) + .map(je -> Tier.fromName(JsonUtils.getString(je, "element of array tiers"))) + .toArray(Tier[]::new); + }catch(IllegalArgumentException e){ + throw new JsonSyntaxException("Incorrect spell predicate value", e); + } + } + + Element[] elements = Element.values(); + + if(jsonobject.has("elements")){ + try{ + JsonArray array = JsonUtils.getJsonArray(jsonobject, "elements"); + elements = Streams.stream(array) + .map(je -> Element.fromName(JsonUtils.getString(je, "element of array elements"))) + .toArray(Element[]::new); + }catch(IllegalArgumentException e){ + throw new JsonSyntaxException("Incorrect spell predicate value", e); + } + } + + return new SpellPredicate(spell, tiers, elements); + + }else{ + return ANY; + } + } + + public static SpellPredicate[] deserializeArray(@Nullable JsonElement element){ + + if(element != null && !element.isJsonNull()){ + + JsonArray jsonarray = JsonUtils.getJsonArray(element, "spells"); + SpellPredicate[] predicates = new SpellPredicate[jsonarray.size()]; + + for(int i = 0; i < predicates.length; ++i){ + predicates[i] = deserialize(jsonarray.get(i)); + } + + return predicates; + + }else{ + return new SpellPredicate[0]; + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/advancement/StructureTrigger.java b/src/main/java/electroblob/wizardry/advancement/StructureTrigger.java new file mode 100644 index 00000000..aedcd6a4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/advancement/StructureTrigger.java @@ -0,0 +1,136 @@ +package electroblob.wizardry.advancement; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import electroblob.wizardry.worldgen.WorldGenSurfaceStructure; +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.advancements.critereon.AbstractCriterionInstance; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.WorldServer; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** Copied from PositionTrigger and modified to work with wizardry's structures. The majority of any + * ICriterionTrigger class is just boilerplate, and this is no exception. */ +public class StructureTrigger implements ICriterionTrigger { + + private final ResourceLocation id; + private final Map listeners = Maps.newHashMap(); + + public StructureTrigger(ResourceLocation id){ + this.id = id; + } + + public ResourceLocation getId(){ + return this.id; + } + + public void addListener(PlayerAdvancements advancements, Listener listener){ + + StructureTrigger.Listeners listeners = this.listeners.get(advancements); + + if(listeners == null){ + listeners = new StructureTrigger.Listeners(advancements); + this.listeners.put(advancements, listeners); + } + + listeners.add(listener); + } + + public void removeListener(PlayerAdvancements advancements, Listener listener){ + + StructureTrigger.Listeners listeners = this.listeners.get(advancements); + + if(listeners != null){ + listeners.remove(listener); + + if(listeners.isEmpty()){ + this.listeners.remove(advancements); + } + } + } + + public void removeAllListeners(PlayerAdvancements advancements){ + this.listeners.remove(advancements); + } + + public StructureTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){ + return new StructureTrigger.Instance(this.id, JsonUtils.getString(json, "structure_type")); + } + + public void trigger(EntityPlayerMP player){ + + StructureTrigger.Listeners listeners = this.listeners.get(player.getAdvancements()); + + if(listeners != null){ + listeners.trigger(player.getServerWorld(), player.posX, player.posY, player.posZ); + } + } + + public static class Instance extends AbstractCriterionInstance { + + private final WorldGenSurfaceStructure structureType; + + public Instance(ResourceLocation criterionIn, String name){ + super(criterionIn); + this.structureType = WorldGenSurfaceStructure.byName(name); + } + + public boolean test(WorldServer world, double x, double y, double z){ + return structureType.isInsideStructure(world, x, y, z); + } + } + + static class Listeners { + + private final PlayerAdvancements playerAdvancements; + private final Set> listeners = Sets.newHashSet(); + + public Listeners(PlayerAdvancements advancements){ + this.playerAdvancements = advancements; + } + + public boolean isEmpty(){ + return this.listeners.isEmpty(); + } + + public void add(Listener listener){ + this.listeners.add(listener); + } + + public void remove(Listener listener){ + this.listeners.remove(listener); + } + + public void trigger(WorldServer world, double x, double y, double z){ + + List> list = null; + + for(Listener listener : this.listeners){ + + if(listener.getCriterionInstance().test(world, x, y, z)){ + + if(list == null){ + list = Lists.newArrayList(); + } + + list.add(listener); + } + } + + if(list != null){ + for(Listener listener : list){ + listener.grantCriterion(this.playerAdvancements); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/api/WizardryEnumHelper.java b/src/main/java/electroblob/wizardry/api/WizardryEnumHelper.java new file mode 100644 index 00000000..4c73f606 --- /dev/null +++ b/src/main/java/electroblob/wizardry/api/WizardryEnumHelper.java @@ -0,0 +1,96 @@ +package electroblob.wizardry.api; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.util.SpellProperties; +import net.minecraft.util.text.Style; +import net.minecraftforge.common.util.EnumHelper; + +/** + * This class contains methods similar to those in {@link EnumHelper} specific to wizardry's enum types. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +public final class WizardryEnumHelper { + + // Make sure these are updated if the relevant constructors are updated! + // Can't we do some kind of reflection to access them and generate these arrays? + private static final Class[] TIER_ARGUMENTS = new Class[]{Integer.class, Integer.class, Integer.class, Style.class, String.class}; + private static final Class[] ELEMENT_ARGUMENTS = new Class[]{Style.class, String.class, String.class}; + private static final Class[] SPELL_TYPE_ARGUMENTS = new Class[]{String.class}; + private static final Class[] SPELL_CONTEXT_ARGUMENTS = new Class[]{String.class}; + + /** + * Wrapper for the generic method {@link EnumHelper#addEnum(Class, String, Class[], Object...)} which is + * specifically for adding new tiers. Use this method in preference to the generic one in case the constructor + * parameters change for {@code Tier}. + *

    + * As of version 4.2, wizardry now has partial support for externally-added tiers; you'll need to do some of the + * legwork yourself though. + * + * @param codeName The name of the enum constant in the code. This will be returned if you call toString() on the + * resulting enum constant; other than that it doesn't really make much difference. + * @param maxCharge The maximum charge for wands of this tier. + * @param upgradeLimit The maximum total number of special upgrades that can be applied to wands of this tier. + * @param weight The weight of this tier in the standard weighting. + * @param colour The colour of text associated with this tier, as a style object. + * @param name The unlocalised name of this tier, as used in translation keys. + * @return The resulting {@code Tier} enum constant. + */ + public static Tier addTier(String codeName, int maxCharge, int upgradeLimit, int weight, Style colour, String name){ + return EnumHelper.addEnum(Tier.class, codeName, TIER_ARGUMENTS, maxCharge, upgradeLimit, weight, colour, name); + } + + /** + * Wrapper for the generic method {@link EnumHelper#addEnum(Class, String, Class[], Object...)} which is + * specifically for adding new elements. Use this method in preference to the generic one in case the constructor + * parameters change for {@code Element}. + *

    + * As of version 4.2, wizardry now has full support for externally-added elements. + * + * @param codeName The name of the enum constant in the code. This will be returned if you call toString() on the + * resulting enum constant; other than that it doesn't really make much difference. + * @param colour The colour of text associated with this element, as a style object. + * @param name The unlocalised name of this element, as used in translation keys. + * @param modID The mod ID of the mod that added this element, for icon rendering purposes. + * @return The resulting {@code Element} enum constant. + */ + // This is the only one that needs the mod ID argument because elements are the only ones that have icons + // For some reason Minecraft doesn't seem to care about the resource domain for lang files, it just pools them + public static Element addElement(String codeName, Style colour, String name, String modID){ + return EnumHelper.addEnum(Element.class, codeName, ELEMENT_ARGUMENTS, colour, name, modID); + } + + /** + * Wrapper for the generic method {@link EnumHelper#addEnum(Class, String, Class[], Object...)} which is + * specifically for adding new spell types. Use this method in preference to the generic one in case the constructor + * parameters change for {@code SpellType}. + *

    + * As of version 4.2, wizardry now has full support for externally-added spell types. + * + * @param codeName The name of the enum constant in the code. This will be returned if you call toString() on the + * resulting enum constant; other than that it doesn't really make much difference. + * @param name The unlocalised name of this spell type, as used in translation keys. + * @return The resulting {@code SpellType} enum constant. + */ + public static SpellType addSpellType(String codeName, String name){ + return EnumHelper.addEnum(SpellType.class, codeName, SPELL_TYPE_ARGUMENTS, name); + } + + /** + * Wrapper for the generic method {@link EnumHelper#addEnum(Class, String, Class[], Object...)} which is + * specifically for adding new spell contexts (for use in spell property JSON files). Use this method in preference + * to the generic one in case the constructor parameters change for {@code Context}. + * + * @param codeName The name of the enum constant in the code. This will be returned if you call toString() on the + * resulting enum constant; other than that it doesn't really make much difference. + * @param name The identifier for this spell context, as used in the JSON file. + * @return The resulting {@code Context} enum constant. + */ + public static SpellProperties.Context addSpellContext(String codeName, String name){ + return EnumHelper.addEnum(SpellProperties.Context.class, codeName, SPELL_CONTEXT_ARGUMENTS, name); + } + +} diff --git a/src/main/java/electroblob/wizardry/block/BlockArcaneWorkbench.java b/src/main/java/electroblob/wizardry/block/BlockArcaneWorkbench.java index d2407cff..8e76c803 100644 --- a/src/main/java/electroblob/wizardry/block/BlockArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/block/BlockArcaneWorkbench.java @@ -5,6 +5,7 @@ import electroblob.wizardry.WizardryGuiHandler; import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; +import net.minecraft.block.state.BlockFaceShape; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.InventoryHelper; @@ -51,6 +52,16 @@ public class BlockArcaneWorkbench extends BlockContainer { return false; } + @Override + public boolean isFullCube(IBlockState state){ + return false; + } + + @Override + public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){ + return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED; + } + @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ){ diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystal.java b/src/main/java/electroblob/wizardry/block/BlockCrystal.java new file mode 100644 index 00000000..2d0f4dd9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockCrystal.java @@ -0,0 +1,76 @@ +package electroblob.wizardry.block; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.block.Block; +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; +import net.minecraft.block.properties.PropertyEnum; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; + +import java.util.EnumMap; + +public class BlockCrystal extends Block { + + public static final PropertyEnum ELEMENT = PropertyEnum.create("element", Element.class); + + private static final EnumMap map_colours = new EnumMap<>(Element.class); + + static { + map_colours.put(Element.MAGIC, MapColor.PINK); + map_colours.put(Element.FIRE, MapColor.ORANGE_STAINED_HARDENED_CLAY); + map_colours.put(Element.ICE, MapColor.LIGHT_BLUE); + map_colours.put(Element.LIGHTNING, MapColor.CYAN); + map_colours.put(Element.NECROMANCY, MapColor.PURPLE); + map_colours.put(Element.EARTH, MapColor.GREEN); + map_colours.put(Element.SORCERY, MapColor.LIME); + map_colours.put(Element.HEALING, MapColor.YELLOW); + } + + public BlockCrystal(Material material){ + super(material); + this.setDefaultState(this.blockState.getBaseState().withProperty(ELEMENT, Element.MAGIC)); + this.setCreativeTab(WizardryTabs.WIZARDRY); + this.setHarvestLevel("pickaxe", 2); + } + + @Override + public int damageDropped(IBlockState state){ + return (state.getValue(ELEMENT)).ordinal(); + } + + @Override + public MapColor getMapColor(IBlockState state, IBlockAccess world, BlockPos pos){ + return map_colours.get(state.getProperties().get(ELEMENT)); + } + + @Override + public void getSubBlocks(CreativeTabs tab, NonNullList items){ + if(this.getCreativeTab() == tab){ + for(Element element : Element.values()){ + items.add(new ItemStack(this, 1, element.ordinal())); + } + } + } + + @Override + public IBlockState getStateFromMeta(int metadata){ + return this.getDefaultState().withProperty(ELEMENT, Element.values()[metadata]); + } + + @Override + public int getMetaFromState(IBlockState state){ + return (state.getValue(ELEMENT)).ordinal(); + } + + @Override + protected BlockStateContainer createBlockState(){ + return new BlockStateContainer(this, ELEMENT); + } +} diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java index a10aa77e..ed9a09d3 100644 --- a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java +++ b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java @@ -1,7 +1,5 @@ package electroblob.wizardry.block; -import java.util.Random; - import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; @@ -19,6 +17,8 @@ import net.minecraftforge.event.entity.player.BonemealEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.util.Random; + // Extending BlockBush allows me to remove nearly everything from this class. @Mod.EventBusSubscriber public class BlockCrystalFlower extends BlockBush { diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystalOre.java b/src/main/java/electroblob/wizardry/block/BlockCrystalOre.java index 916b6564..a96c9d1a 100644 --- a/src/main/java/electroblob/wizardry/block/BlockCrystalOre.java +++ b/src/main/java/electroblob/wizardry/block/BlockCrystalOre.java @@ -1,7 +1,5 @@ package electroblob.wizardry.block; -import java.util.Random; - import electroblob.wizardry.registry.WizardryItems; import net.minecraft.block.Block; import net.minecraft.block.SoundType; @@ -13,6 +11,8 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import java.util.Random; + public class BlockCrystalOre extends Block { public BlockCrystalOre(Material material){ diff --git a/src/main/java/electroblob/wizardry/block/BlockDryFrostedIce.java b/src/main/java/electroblob/wizardry/block/BlockDryFrostedIce.java new file mode 100644 index 00000000..8e80b5ae --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockDryFrostedIce.java @@ -0,0 +1,28 @@ +package electroblob.wizardry.block; + +import net.minecraft.block.BlockFrostedIce; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +import java.util.Random; + +/** Like {@link BlockFrostedIce}, but melting does not depend on light level or neighbouring blocks, and it just + * disappears instead of turning to water. */ +public class BlockDryFrostedIce extends BlockFrostedIce { + + @Override + protected void turnIntoWater(World world, BlockPos pos){ + world.destroyBlock(pos, false); + } + + @Override + public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand){ + if(rand.nextInt(3) == 0){ + this.slightlyMelt(worldIn, pos, state, rand, true); + }else{ + worldIn.scheduleUpdate(pos, this, MathHelper.getInt(rand, 20, 40)); + } + } +} diff --git a/src/main/java/electroblob/wizardry/block/BlockMagicLight.java b/src/main/java/electroblob/wizardry/block/BlockMagicLight.java index 77974eec..72dd8a5e 100644 --- a/src/main/java/electroblob/wizardry/block/BlockMagicLight.java +++ b/src/main/java/electroblob/wizardry/block/BlockMagicLight.java @@ -1,23 +1,31 @@ package electroblob.wizardry.block; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.tileentity.TileEntityMagicLight; -import net.minecraft.block.BlockContainer; +import net.minecraft.block.Block; +import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumBlockRenderType; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; -public class BlockMagicLight extends BlockContainer { +public class BlockMagicLight extends Block implements ITileEntityProvider { - private static final AxisAlignedBB AABB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + //private static final AxisAlignedBB AABB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); - public BlockMagicLight(Material par2Material){ - super(par2Material); + public BlockMagicLight(Material material){ + super(material); this.setLightLevel(1.0f); + this.setBlockUnbreakable(); } @Override @@ -28,13 +36,38 @@ public class BlockMagicLight extends BlockContainer { } @Override - public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){ - return AABB; + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ){ + // Let the player dispel any lights if they have the lantern charm, not just the permanent ones because that would be annoying! + if(player.getHeldItem(hand).getItem() instanceof ISpellCastingItem && ItemArtefact.isArtefactActive(player, WizardryItems.charm_light)){ + + world.setBlockToAir(pos); + return true; + + }else{ + return super.onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ); + } } +// @Override +// public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){ +// return AABB; +// } + @Override public boolean isCollidable(){ - return false; + // This method has nothing to do with entity movement, it's just for raytracing + return true; + } + + @Override + public boolean addDestroyEffects(World world, BlockPos pos, net.minecraft.client.particle.ParticleManager manager){ + if(world.getBlockState(pos).getBlock() == this) return true; // No break particles! + else return super.addDestroyEffects(world, pos, manager); + } + + @Override + public boolean hasTileEntity(IBlockState state){ + return true; } @Override diff --git a/src/main/java/electroblob/wizardry/block/BlockObsidianCrust.java b/src/main/java/electroblob/wizardry/block/BlockObsidianCrust.java new file mode 100644 index 00000000..269459bc --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockObsidianCrust.java @@ -0,0 +1,116 @@ +package electroblob.wizardry.block; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockObsidian; +import net.minecraft.block.properties.PropertyInteger; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +import java.util.Random; + +/** Like {@link net.minecraft.block.BlockFrostedIce}, but for lava instead of water. */ +// This is mostly copied from that class, with a few changes +public class BlockObsidianCrust extends BlockObsidian { + + public static final PropertyInteger AGE = PropertyInteger.create("age", 0, 3); + + public BlockObsidianCrust(){ + this.setDefaultState(this.blockState.getBaseState().withProperty(AGE, 0)); + } + + @Override + public int getMetaFromState(IBlockState state){ + return state.getValue(AGE); + } + + @Override + public IBlockState getStateFromMeta(int meta){ + return this.getDefaultState().withProperty(AGE, MathHelper.clamp(meta, 0, 3)); + } + + @Override + public void updateTick(World world, BlockPos pos, IBlockState state, Random random){ + if((random.nextInt(3) == 0 || this.countNeighbors(world, pos) < 4) && world.getLightFromNeighbors(pos) > 11 - state.getValue(AGE) - state.getLightOpacity()){ + this.slightlyMelt(world, pos, state, random, true); + }else{ + world.scheduleUpdate(pos, this, MathHelper.getInt(random, 20, 40)); + } + } + + @Override + public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos fromPos){ + if(block == this){ + int i = this.countNeighbors(world, pos); + + if(i < 2){ + this.melt(world, pos); + } + } + } + + private int countNeighbors(World world, BlockPos pos){ + + int i = 0; + + for(EnumFacing enumfacing : EnumFacing.values()){ + if(world.getBlockState(pos.offset(enumfacing)).getBlock() == this){ + ++i; + + if(i >= 4){ + return i; + } + } + } + + return i; + } + + protected void slightlyMelt(World world, BlockPos pos, IBlockState state, Random random, boolean meltNeighbours){ + + int i = state.getValue(AGE); + + if(i < 3){ + + world.setBlockState(pos, state.withProperty(AGE, i + 1), 2); + world.scheduleUpdate(pos, this, MathHelper.getInt(random, 20, 40)); + + }else{ + + this.melt(world, pos); + + if(meltNeighbours){ + + for(EnumFacing enumfacing : EnumFacing.values()){ + + BlockPos blockpos = pos.offset(enumfacing); + IBlockState iblockstate = world.getBlockState(blockpos); + + if(iblockstate.getBlock() == this){ + this.slightlyMelt(world, blockpos, iblockstate, random, false); + } + } + } + } + } + + protected void melt(World world, BlockPos pos){ + world.setBlockState(pos, Blocks.LAVA.getDefaultState()); + world.neighborChanged(pos, Blocks.LAVA, pos); + } + + @Override + protected BlockStateContainer createBlockState(){ + return new BlockStateContainer(this, AGE); + } + + @Override + public ItemStack getItem(World world, BlockPos pos, IBlockState state){ + return ItemStack.EMPTY; + } +} diff --git a/src/main/java/electroblob/wizardry/block/BlockPedestal.java b/src/main/java/electroblob/wizardry/block/BlockPedestal.java new file mode 100644 index 00000000..9da9c6f5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockPedestal.java @@ -0,0 +1,123 @@ +package electroblob.wizardry.block; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.tileentity.TileEntityShrineCore; +import net.minecraft.block.Block; +import net.minecraft.block.ITileEntityProvider; +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; +import net.minecraft.block.properties.PropertyBool; +import net.minecraft.block.properties.PropertyEnum; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.Explosion; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.EnumMap; + +public class BlockPedestal extends Block implements ITileEntityProvider { + + public static final PropertyEnum ELEMENT = PropertyEnum.create("element", Element.class, + Arrays.copyOfRange(Element.values(), 1, Element.values().length)); // Everything except MAGIC + + // A 'natural' pedestal is one that was generated as part of a structure, is unbreakable and has a tileentity + public static final PropertyBool NATURAL = PropertyBool.create("natural"); + + private static final EnumMap map_colours = new EnumMap<>(Element.class); + + static { + map_colours.put(Element.FIRE, MapColor.RED_STAINED_HARDENED_CLAY); + map_colours.put(Element.ICE, MapColor.LIGHT_BLUE_STAINED_HARDENED_CLAY); + map_colours.put(Element.LIGHTNING, MapColor.CYAN_STAINED_HARDENED_CLAY); + map_colours.put(Element.NECROMANCY, MapColor.PURPLE_STAINED_HARDENED_CLAY); + map_colours.put(Element.EARTH, MapColor.BROWN_STAINED_HARDENED_CLAY); + map_colours.put(Element.SORCERY, MapColor.GRAY); + map_colours.put(Element.HEALING, MapColor.YELLOW_STAINED_HARDENED_CLAY); + } + + public BlockPedestal(Material material){ + super(material); + this.setDefaultState(this.blockState.getBaseState().withProperty(ELEMENT, Element.FIRE).withProperty(NATURAL, false)); + this.setCreativeTab(WizardryTabs.WIZARDRY); + this.setHardness(1.5F); + this.setResistance(10.0F); + } + + @Override + public int damageDropped(IBlockState state){ + return state.getValue(ELEMENT).ordinal(); // Ignore the NATURAL state here, it's unobtainable + } + + @Override + public MapColor getMapColor(IBlockState state, IBlockAccess world, BlockPos pos){ + return map_colours.get(state.getProperties().get(ELEMENT)); + } + + @Override + public void getSubBlocks(CreativeTabs tab, NonNullList items){ + // Ignore the NATURAL state here, it's unobtainable + if(this.getCreativeTab() == tab){ + for(Element element : Arrays.copyOfRange(Element.values(), 1, Element.values().length)){ + items.add(new ItemStack(this, 1, element.ordinal())); + } + } + } + + @Override + public BlockRenderLayer getRenderLayer(){ + return BlockRenderLayer.CUTOUT; // Required to shade parts of the block faces differently to others + } + + @Override + public float getBlockHardness(IBlockState state, World world, BlockPos pos){ + return state.getValue(NATURAL) ? -1 : super.getBlockHardness(state, world, pos); + } + + @Override + public float getExplosionResistance(World world, BlockPos pos, @Nullable Entity exploder, Explosion explosion){ + return world.getBlockState(pos).getValue(NATURAL) ? 6000000.0F : super.getExplosionResistance(world, pos, exploder, explosion); + } + + @Override + public boolean hasTileEntity(IBlockState state){ + return state.getValue(NATURAL); // Only naturally-generated pedestals have a (shrine core) tile entity + } + + @Nullable + @Override + public TileEntity createNewTileEntity(World world, int meta){ + return new TileEntityShrineCore(); + } + + @Override + public IBlockState getStateFromMeta(int metadata){ + boolean natural = false; + if(metadata > ELEMENT.getAllowedValues().size()){ + natural = true; + metadata -= ELEMENT.getAllowedValues().size(); + } + return this.getDefaultState().withProperty(ELEMENT, Element.values()[metadata]).withProperty(NATURAL, natural); + } + + @Override + public int getMetaFromState(IBlockState state){ + return state.getValue(ELEMENT).ordinal() + (state.getValue(NATURAL) ? ELEMENT.getAllowedValues().size() : 0); + } + + @Override + protected BlockStateContainer createBlockState(){ + return new BlockStateContainer(this, ELEMENT, NATURAL); + } + +} diff --git a/src/main/java/electroblob/wizardry/block/BlockRunestone.java b/src/main/java/electroblob/wizardry/block/BlockRunestone.java new file mode 100644 index 00000000..996eaa52 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockRunestone.java @@ -0,0 +1,85 @@ +package electroblob.wizardry.block; + +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.block.Block; +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; +import net.minecraft.block.properties.PropertyEnum; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.ItemStack; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; + +import java.util.Arrays; +import java.util.EnumMap; + +public class BlockRunestone extends Block { + + public static final PropertyEnum ELEMENT = PropertyEnum.create("element", Element.class, + Arrays.copyOfRange(Element.values(), 1, Element.values().length)); // Everything except MAGIC + + private static final EnumMap map_colours = new EnumMap<>(Element.class); + + static { + map_colours.put(Element.FIRE, MapColor.RED_STAINED_HARDENED_CLAY); + map_colours.put(Element.ICE, MapColor.LIGHT_BLUE_STAINED_HARDENED_CLAY); + map_colours.put(Element.LIGHTNING, MapColor.CYAN_STAINED_HARDENED_CLAY); + map_colours.put(Element.NECROMANCY, MapColor.PURPLE_STAINED_HARDENED_CLAY); + map_colours.put(Element.EARTH, MapColor.BROWN_STAINED_HARDENED_CLAY); + map_colours.put(Element.SORCERY, MapColor.GRAY); + map_colours.put(Element.HEALING, MapColor.YELLOW_STAINED_HARDENED_CLAY); + } + + public BlockRunestone(Material material){ + super(material); + this.setDefaultState(this.blockState.getBaseState().withProperty(ELEMENT, Element.FIRE)); + this.setCreativeTab(WizardryTabs.WIZARDRY); + this.setHardness(1.5F); + this.setResistance(10.0F); + } + + @Override + public int damageDropped(IBlockState state){ + return state.getValue(ELEMENT).ordinal(); + } + + @Override + public MapColor getMapColor(IBlockState state, IBlockAccess world, BlockPos pos){ + return map_colours.get(state.getProperties().get(ELEMENT)); + } + + @Override + public void getSubBlocks(CreativeTabs tab, NonNullList items){ + if(this.getCreativeTab() == tab){ + for(Element element : Arrays.copyOfRange(Element.values(), 1, Element.values().length)){ + items.add(new ItemStack(this, 1, element.ordinal())); + } + } + } + + @Override + public BlockRenderLayer getRenderLayer(){ + return BlockRenderLayer.CUTOUT; // Required to shade parts of the block faces differently to others + } + + @Override + public IBlockState getStateFromMeta(int metadata){ + return this.getDefaultState().withProperty(ELEMENT, Element.values()[metadata]); + } + + @Override + public int getMetaFromState(IBlockState state){ + return state.getValue(ELEMENT).ordinal(); + } + + @Override + protected BlockStateContainer createBlockState(){ + return new BlockStateContainer(this, ELEMENT); + } + +} diff --git a/src/main/java/electroblob/wizardry/block/BlockSnare.java b/src/main/java/electroblob/wizardry/block/BlockSnare.java index 878826df..a10df677 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSnare.java +++ b/src/main/java/electroblob/wizardry/block/BlockSnare.java @@ -1,13 +1,13 @@ package electroblob.wizardry.block; -import java.util.Random; - +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.tileentity.TileEntityPlayerSave; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; -import net.minecraft.block.BlockContainer; +import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; @@ -25,8 +25,9 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; -// TODO: Apparently you shouldn't extend BlockContainer. I feel like BlockArcaneWorkbench should, but what about the rest? -public class BlockSnare extends BlockContainer { +import java.util.Random; + +public class BlockSnare extends Block implements ITileEntityProvider { private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0f, 0.0f, 0.0f, 1.0f, 0.0625f, 1.0f); @@ -58,10 +59,14 @@ public class BlockSnare extends BlockContainer { TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(pos); - if(WizardryUtilities.isValidTarget(tileentity.getCaster(), entity)){ - ((EntityLivingBase)entity).attackEntityFrom( - MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC), 6); - ((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 100, 2)); + if(AllyDesignationSystem.isValidTarget(tileentity.getCaster(), entity)){ + + entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC), + Spells.snare.getProperty(Spell.DAMAGE).floatValue()); + + ((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, + Spells.snare.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.snare.getProperty(Spell.EFFECT_STRENGTH).intValue())); world.destroyBlock(pos, false); } diff --git a/src/main/java/electroblob/wizardry/block/BlockSpectral.java b/src/main/java/electroblob/wizardry/block/BlockSpectral.java index 5724f610..fe34473a 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSpectral.java +++ b/src/main/java/electroblob/wizardry/block/BlockSpectral.java @@ -1,13 +1,11 @@ package electroblob.wizardry.block; -import java.util.Random; - import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.tileentity.TileEntityTimer; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.block.Block; -import net.minecraft.block.BlockContainer; +import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; @@ -24,10 +22,10 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on -// block break. +import java.util.Random; + @Mod.EventBusSubscriber -public class BlockSpectral extends BlockContainer { +public class BlockSpectral extends Block implements ITileEntityProvider { public BlockSpectral(Material material){ super(material); @@ -76,6 +74,11 @@ public class BlockSpectral extends BlockContainer { return 15; } + @Override + public boolean hasTileEntity(IBlockState state){ + return true; + } + @Override public TileEntity createNewTileEntity(World world, int metadata){ return new TileEntityTimer(1200); diff --git a/src/main/java/electroblob/wizardry/block/BlockStatue.java b/src/main/java/electroblob/wizardry/block/BlockStatue.java index 07956970..cf5b7dee 100644 --- a/src/main/java/electroblob/wizardry/block/BlockStatue.java +++ b/src/main/java/electroblob/wizardry/block/BlockStatue.java @@ -1,11 +1,9 @@ package electroblob.wizardry.block; -import java.util.Random; - import electroblob.wizardry.tileentity.TileEntityStatue; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; -import net.minecraft.block.BlockContainer; +import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; @@ -21,12 +19,16 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -public class BlockStatue extends BlockContainer { +import java.util.Random; + +public class BlockStatue extends Block implements ITileEntityProvider { private boolean isIce; - + /** The NBT tag name for storing the petrified flag (used for rendering) in the target's tag compound. */ - public static final String NBT_KEY = "petrified"; + public static final String PETRIFIED_NBT_KEY = "petrified"; + /** The NBT tag name for storing the frozen flag (used for rendering) in the target's tag compound. */ + public static final String FROZEN_NBT_KEY = "frozen"; public BlockStatue(Material material){ super(material); @@ -110,6 +112,11 @@ public class BlockStatue extends BlockContainer { return this.isIce ? EnumBlockRenderType.MODEL : EnumBlockRenderType.ENTITYBLOCK_ANIMATED; } + @Override + public boolean hasTileEntity(IBlockState state){ + return true; + } + @Override public TileEntity createNewTileEntity(World world, int metadata){ return new TileEntityStatue(this.isIce); @@ -150,7 +157,7 @@ public class BlockStatue extends BlockContainer { // This is only when position == 1 because world.destroyBlock calls this function for the other blocks. if(tileentity != null && tileentity.position == 1 && tileentity.creature != null){ - tileentity.creature.getEntityData().removeTag(BlockStatue.NBT_KEY); + tileentity.creature.getEntityData().removeTag(BlockStatue.PETRIFIED_NBT_KEY); tileentity.creature.isDead = false; world.spawnEntity(tileentity.creature); } @@ -198,7 +205,7 @@ public class BlockStatue extends BlockContainer { ((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration); } - if(!this.isIce) entity.getEntityData().setBoolean(NBT_KEY, true); + entity.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true); entity.setDead(); return true; } @@ -216,8 +223,8 @@ public class BlockStatue extends BlockContainer { if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ ((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(entity, 2, 2); } - - if(!this.isIce) entity.getEntityData().setBoolean(NBT_KEY, true); + + entity.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true); entity.setDead(); return true; } @@ -241,8 +248,8 @@ public class BlockStatue extends BlockContainer { if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){ ((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(entity, 3, 3); } - - if(!this.isIce) entity.getEntityData().setBoolean(NBT_KEY, true); + + entity.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true); entity.setDead(); return true; } diff --git a/src/main/java/electroblob/wizardry/block/BlockThorns.java b/src/main/java/electroblob/wizardry/block/BlockThorns.java new file mode 100644 index 00000000..0ceb6035 --- /dev/null +++ b/src/main/java/electroblob/wizardry/block/BlockThorns.java @@ -0,0 +1,181 @@ +package electroblob.wizardry.block; + +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.tileentity.TileEntityPlayerSaveTimed; +import electroblob.wizardry.util.AllyDesignationSystem; +import electroblob.wizardry.util.MagicDamage; +import net.minecraft.block.*; +import net.minecraft.block.BlockDoublePlant.EnumBlockHalf; +import net.minecraft.block.properties.PropertyEnum; +import net.minecraft.block.properties.PropertyInteger; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.DamageSource; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.Random; + +@Mod.EventBusSubscriber +public class BlockThorns extends BlockBush implements ITileEntityProvider { + + public static final int GROWTH_STAGES = 8; + + public static final PropertyInteger AGE = PropertyInteger.create("age", 0, GROWTH_STAGES-1); + public static final PropertyEnum HALF = PropertyEnum.create("half", EnumBlockHalf.class); + + public BlockThorns(){ + this.setDefaultState(this.blockState.getBaseState().withProperty(HALF, EnumBlockHalf.LOWER).withProperty(AGE, 7)); + this.setHardness(4); + this.setSoundType(SoundType.PLANT); + this.setCreativeTab(null); + } + + @Override + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){ + return FULL_BLOCK_AABB; + } + + @Override + public IBlockState getStateFromMeta(int meta){ + return this.getDefaultState().withProperty(HALF, EnumBlockHalf.values()[meta / GROWTH_STAGES]).withProperty(AGE, meta % GROWTH_STAGES); + } + + @Override + public int getMetaFromState(IBlockState state){ + return state.getValue(HALF).ordinal() * GROWTH_STAGES + state.getValue(AGE); + } + +// @Override +// public void updateTick(World world, BlockPos pos, IBlockState state, Random rand){ +// +// super.updateTick(world, pos, state, rand); +// +// // Update the state, including on the client, but don't do a block update since it's only visual +// if(state.getValue(AGE) < GROWTH_STAGES-1) world.setBlockState(pos, state.withProperty(AGE, state.getValue(AGE) + 1), 2); +// } + + @Override + protected BlockStateContainer createBlockState(){ + return new BlockStateContainer(this, HALF, AGE); + } + + public void placeAt(World world, BlockPos lowerPos, int flags){ + world.setBlockState(lowerPos, this.getDefaultState().withProperty(HALF, EnumBlockHalf.LOWER).withProperty(AGE, 0), flags); + world.setBlockState(lowerPos.up(), this.getDefaultState().withProperty(HALF, EnumBlockHalf.UPPER).withProperty(AGE, 0), flags); + } + + @Override + public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack){ + world.setBlockState(pos.up(), this.getDefaultState().withProperty(HALF, EnumBlockHalf.UPPER), 2); + } + + @Override + public void breakBlock(World world, BlockPos pos, IBlockState state){ + super.breakBlock(world, pos, state); + if(state.getValue(HALF) == EnumBlockHalf.LOWER){ + if(world.getBlockState(pos.up()).getBlock() == this){ + world.destroyBlock(pos.up(), false); + } + }else{ + if(world.getBlockState(pos.down()).getBlock() == this){ + world.destroyBlock(pos.down(), false); + } + } + } + + public boolean canBlockStay(World worldIn, BlockPos pos, IBlockState state){ + if(state.getValue(HALF) == BlockDoublePlant.EnumBlockHalf.UPPER){ + return worldIn.getBlockState(pos.down()).getBlock() == this; + }else{ + IBlockState iblockstate = worldIn.getBlockState(pos.up()); + return iblockstate.getBlock() == this && this.canSustainBush(worldIn.getBlockState(pos.down())); + } + } + +// @Override +// public IBlockState getActualState(IBlockState state, IBlockAccess world, BlockPos pos){ +// // Copied from BlockFlowerPot on authority of the Forge docs, which says this check is necessary +// SoundLoopSpellDispenser tileentity = world instanceof ChunkCache ? ((ChunkCache)world).getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK) : world.getTileEntity(pos); +// +// if(tileentity instanceof TileEntityPlayerSaveTimed){ +// state = state.withProperty(AGE, Math.min(7, ((TileEntityPlayerSaveTimed)tileentity).timer/2)); +// }else{ +// state = state.withProperty(AGE, 7); +// } +// +// return state; +// } + + @Override + public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){ + if(!world.isRemote){ + if(applyThornDamage(world, pos, entity)){ + entity.setInWeb(); + } + } + } + + private static boolean applyThornDamage(World world, BlockPos pos, Entity target){ + + DamageSource source = DamageSource.CACTUS; + + TileEntity tileentity = world.getTileEntity(pos); + + if(tileentity instanceof TileEntityPlayerSaveTimed){ + if(AllyDesignationSystem.isValidTarget(((TileEntityPlayerSaveTimed)tileentity).getCaster(), target)){ + source = MagicDamage.causeDirectMagicDamage(((TileEntityPlayerSaveTimed)tileentity).getCaster(), + MagicDamage.DamageType.MAGIC); + }else{ + return false; // Don't attack or slow allies of the caster + } + } + + if(world.getTotalWorldTime() % 20 == 0) target.attackEntityFrom(source, Spells.forest_of_thorns.getProperty(Spell.DAMAGE).floatValue()); + + return true; + } + + @Override + public Block.EnumOffsetType getOffsetType(){ + return Block.EnumOffsetType.XZ; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata){ + return new TileEntityPlayerSaveTimed(600); + } + + @Override + public boolean hasTileEntity(IBlockState state){ + return true; + } + + @Override public boolean isReplaceable(IBlockAccess world, BlockPos pos){ return false; } + @Override protected boolean canSustainBush(IBlockState state){ return state.isNormalCube(); } + @Override public Item getItemDropped(IBlockState state, Random rand, int fortune){ return Items.AIR; } + @Override public boolean canSilkHarvest(World world, BlockPos pos, IBlockState state, EntityPlayer player){ return false; } + + @SubscribeEvent + public static void onLeftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event){ + if(!event.getWorld().isRemote && event.getWorld().getTotalWorldTime() % 20 == 0 + && event.getWorld().getBlockState(event.getPos()).getBlock() == WizardryBlocks.thorns){ + applyThornDamage(event.getWorld(), event.getPos(), event.getEntity()); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java b/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java index 84c0c9c0..ea0595a1 100644 --- a/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java +++ b/src/main/java/electroblob/wizardry/block/BlockTransportationStone.java @@ -1,12 +1,16 @@ package electroblob.wizardry.block; -import java.util.Random; - -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.item.ItemArtefact; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.spell.Transportation; +import electroblob.wizardry.util.Location; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; @@ -20,6 +24,10 @@ import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + public class BlockTransportationStone extends Block { private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0625f * 5, 0, 0.0625f * 5, 0.0625f * 11, 0.0625f * 6, @@ -103,7 +111,7 @@ public class BlockTransportationStone extends Block { ItemStack stack = player.getHeldItem(hand); - if(stack.getItem() instanceof ItemWand){ + if(stack.getItem() instanceof ISpellCastingItem){ if(WizardData.get(player) != null){ WizardData data = WizardData.get(player); @@ -112,17 +120,59 @@ public class BlockTransportationStone extends Block { for(int z = -1; z <= 1; z++){ BlockPos pos1 = pos.add(x, 0, z); if(testForCircle(world, pos1)){ - data.setStoneCircleLocation(pos1, world.provider.getDimension()); - if(!world.isRemote) player.sendMessage( - new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.confirm", - Spells.transportation.getNameForTranslationFormatted())); + + Location here = new Location(pos1, player.dimension); + + List locations = data.getVariable(Transportation.LOCATIONS_KEY); + if(locations == null) data.setVariable(Transportation.LOCATIONS_KEY, locations = new ArrayList<>(Transportation.MAX_REMEMBERED_LOCATIONS)); + + if(ItemArtefact.isArtefactActive(player, WizardryItems.charm_transportation)){ + + if(locations.contains(here)){ + locations.remove(here); + if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.forget", here.pos.getX(), here.pos.getY(), here.pos.getZ(), here.dimension), true); + + }else{ + + locations.add(here); + if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.remember", here.pos.getX(), here.pos.getY(), here.pos.getZ(), here.dimension), true); + + if(locations.size() > Transportation.MAX_REMEMBERED_LOCATIONS){ + Location removed = locations.remove(0); + if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.forget", removed.pos.getX(), removed.pos.getY(), removed.pos.getZ(), removed.dimension), true); + } + } + + }else{ + if(locations.isEmpty()) locations.add(here); + else{ + locations.remove(here); // Prevents duplicates + locations.set(locations.size() - 1, here); + } + if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted()), true); + } + return true; } } } - if(!world.isRemote) - player.sendMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.invalid")); + if(!world.isRemote){ + player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.invalid"), true); + }else{ + + BlockPos centre = findMostLikelyCircle(world, pos); + // Displays particles in the required shape + for(int x = -1; x <= 1; x++){ + for(int z = -1; z <= 1; z++){ + if(x == 0 && z == 0) continue; + ParticleBuilder.create(ParticleBuilder.Type.PATH) + .pos(WizardryUtilities.getCentre(centre).add(x, -0.3125, z)).clr(0x86ff65) + .time(200).scale(2).spawn(world); + } + } + } + return true; } } @@ -136,12 +186,47 @@ public class BlockTransportationStone extends Block { for(int x = -1; x <= 1; x++){ for(int z = -1; z <= 1; z++){ + if(x == 0 && z == 0) continue; if(world.getBlockState(pos.add(x, 0, z)).getBlock() != WizardryBlocks.transportation_stone){ - if(x != 0 || z != 0) return false; + return false; } } } return true; } + + private static BlockPos findMostLikelyCircle(World world, BlockPos pos){ + + int bestSoFar = 0; + BlockPos result = null; + + for(int x = -1; x <= 1; x++){ + for(int z = -1; z <= 1; z++){ + if(x == 0 && z == 0) continue; + BlockPos pos1 = pos.add(x, 0, z); + int n = getCircleCompleteness(world, pos1); + if(n > bestSoFar){ + bestSoFar = n; + result = pos1; + } + } + } + + return result; + } + + private static int getCircleCompleteness(World world, BlockPos pos){ + + int n = 0; + + for(int x = -1; x <= 1; x++){ + for(int z = -1; z <= 1; z++){ + if(x == 0 && z == 0) continue; + if(world.getBlockState(pos.add(x, 0, z)).getBlock() == WizardryBlocks.transportation_stone) n++; + } + } + + return n; + } } diff --git a/src/main/java/electroblob/wizardry/block/BlockVanishingCobweb.java b/src/main/java/electroblob/wizardry/block/BlockVanishingCobweb.java index 131134db..c8532ced 100644 --- a/src/main/java/electroblob/wizardry/block/BlockVanishingCobweb.java +++ b/src/main/java/electroblob/wizardry/block/BlockVanishingCobweb.java @@ -1,9 +1,8 @@ package electroblob.wizardry.block; -import java.util.Random; - import electroblob.wizardry.tileentity.TileEntityTimer; -import net.minecraft.block.BlockContainer; +import net.minecraft.block.Block; +import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; @@ -17,15 +16,17 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on block break. -public class BlockVanishingCobweb extends BlockContainer { +import java.util.Random; + +public class BlockVanishingCobweb extends Block implements ITileEntityProvider { public BlockVanishingCobweb(Material material){ super(material); } @SideOnly(Side.CLIENT) - public BlockRenderLayer getBlockLayer(){ + @Override + public BlockRenderLayer getRenderLayer(){ return BlockRenderLayer.CUTOUT; } @@ -49,6 +50,11 @@ public class BlockVanishingCobweb extends BlockContainer { return false; } + @Override + public boolean hasTileEntity(IBlockState state){ + return true; + } + @Override public TileEntity createNewTileEntity(World world, int metadata){ return new TileEntityTimer(400); diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 910938eb..ee3b2be0 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -1,115 +1,54 @@ package electroblob.wizardry.client; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; - -import org.lwjgl.input.Keyboard; - import electroblob.wizardry.CommonProxy; -import electroblob.wizardry.SpellGlyphData; -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.audio.MovingSoundEntity; +import electroblob.wizardry.client.audio.SoundLoop; +import electroblob.wizardry.client.audio.SoundLoopSpell; import electroblob.wizardry.client.gui.GuiSpellDisplay; -import electroblob.wizardry.client.gui.GuiWizardHandbook; +import electroblob.wizardry.client.gui.config.NamedBooleanEntry; +import electroblob.wizardry.client.gui.config.SpellHUDSkinChooserEntry; +import electroblob.wizardry.client.gui.handbook.GuiWizardHandbook; import electroblob.wizardry.client.model.ModelWizardArmour; import electroblob.wizardry.client.particle.*; import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory; -import electroblob.wizardry.client.renderer.LayerStone; -import electroblob.wizardry.client.renderer.RenderArcaneWorkbench; -import electroblob.wizardry.client.renderer.RenderBlackHole; -import electroblob.wizardry.client.renderer.RenderBlank; -import electroblob.wizardry.client.renderer.RenderBubble; -import electroblob.wizardry.client.renderer.RenderDecay; -import electroblob.wizardry.client.renderer.RenderDecoy; -import electroblob.wizardry.client.renderer.RenderEvilWizard; -import electroblob.wizardry.client.renderer.RenderFireRing; -import electroblob.wizardry.client.renderer.RenderForceArrow; -import electroblob.wizardry.client.renderer.RenderHammer; -import electroblob.wizardry.client.renderer.RenderIceGiant; -import electroblob.wizardry.client.renderer.RenderIceSpike; -import electroblob.wizardry.client.renderer.RenderLightningDisc; -import electroblob.wizardry.client.renderer.RenderMagicArrow; -import electroblob.wizardry.client.renderer.RenderMagicLight; -import electroblob.wizardry.client.renderer.RenderPhoenix; -import electroblob.wizardry.client.renderer.RenderProjectile; -import electroblob.wizardry.client.renderer.RenderSigil; -import electroblob.wizardry.client.renderer.RenderSpiritHorse; -import electroblob.wizardry.client.renderer.RenderSpiritWolf; -import electroblob.wizardry.client.renderer.RenderStatue; -import electroblob.wizardry.client.renderer.RenderWizard; +import electroblob.wizardry.client.renderer.*; +import electroblob.wizardry.command.SpellEmitter; +import electroblob.wizardry.data.DispenserCastingData; +import electroblob.wizardry.data.SpellEmitterData; +import electroblob.wizardry.data.SpellGlyphData; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.entity.EntityShield; -import electroblob.wizardry.entity.construct.EntityArrowRain; -import electroblob.wizardry.entity.construct.EntityBlackHole; -import electroblob.wizardry.entity.construct.EntityBlizzard; -import electroblob.wizardry.entity.construct.EntityBubble; -import electroblob.wizardry.entity.construct.EntityDecay; -import electroblob.wizardry.entity.construct.EntityEarthquake; -import electroblob.wizardry.entity.construct.EntityFireRing; -import electroblob.wizardry.entity.construct.EntityFireSigil; -import electroblob.wizardry.entity.construct.EntityForcefield; -import electroblob.wizardry.entity.construct.EntityFrostSigil; -import electroblob.wizardry.entity.construct.EntityHailstorm; -import electroblob.wizardry.entity.construct.EntityHammer; -import electroblob.wizardry.entity.construct.EntityHealAura; -import electroblob.wizardry.entity.construct.EntityIceSpike; -import electroblob.wizardry.entity.construct.EntityLightningSigil; -import electroblob.wizardry.entity.construct.EntityTornado; -import electroblob.wizardry.entity.living.EntityDecoy; -import electroblob.wizardry.entity.living.EntityEvilWizard; -import electroblob.wizardry.entity.living.EntityIceGiant; -import electroblob.wizardry.entity.living.EntityIceWraith; -import electroblob.wizardry.entity.living.EntityLightningWraith; -import electroblob.wizardry.entity.living.EntityPhoenix; -import electroblob.wizardry.entity.living.EntityShadowWraith; -import electroblob.wizardry.entity.living.EntitySpiritHorse; -import electroblob.wizardry.entity.living.EntitySpiritWolf; -import electroblob.wizardry.entity.living.EntityStormElemental; -import electroblob.wizardry.entity.living.EntityWizard; -import electroblob.wizardry.entity.living.ISpellCaster; -import electroblob.wizardry.entity.living.ISummonedCreature; -import electroblob.wizardry.entity.projectile.EntityDarknessOrb; -import electroblob.wizardry.entity.projectile.EntityDart; -import electroblob.wizardry.entity.projectile.EntityFirebolt; -import electroblob.wizardry.entity.projectile.EntityFirebomb; -import electroblob.wizardry.entity.projectile.EntityForceArrow; -import electroblob.wizardry.entity.projectile.EntityForceOrb; -import electroblob.wizardry.entity.projectile.EntityIceCharge; -import electroblob.wizardry.entity.projectile.EntityIceLance; -import electroblob.wizardry.entity.projectile.EntityIceShard; -import electroblob.wizardry.entity.projectile.EntityLightningArrow; -import electroblob.wizardry.entity.projectile.EntityLightningDisc; -import electroblob.wizardry.entity.projectile.EntityMagicMissile; -import electroblob.wizardry.entity.projectile.EntityPoisonBomb; -import electroblob.wizardry.entity.projectile.EntitySmokeBomb; -import electroblob.wizardry.entity.projectile.EntitySpark; -import electroblob.wizardry.entity.projectile.EntitySparkBomb; -import electroblob.wizardry.entity.projectile.EntityThunderbolt; +import electroblob.wizardry.entity.construct.*; +import electroblob.wizardry.entity.living.*; +import electroblob.wizardry.entity.projectile.*; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent.Source; +import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration; import electroblob.wizardry.item.ItemScroll; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.item.ItemWand; -import electroblob.wizardry.packet.PacketCastContinuousSpell; -import electroblob.wizardry.packet.PacketCastSpell; -import electroblob.wizardry.packet.PacketNPCCastSpell; -import electroblob.wizardry.packet.PacketPlayerSync.Message; -import electroblob.wizardry.packet.PacketTransportation; +import electroblob.wizardry.packet.*; +import electroblob.wizardry.potion.PotionSlowTime; import electroblob.wizardry.registry.Spells; -import electroblob.wizardry.spell.Clairvoyance; -import electroblob.wizardry.spell.None; -import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.*; import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; import electroblob.wizardry.tileentity.TileEntityMagicLight; +import electroblob.wizardry.tileentity.TileEntityShrineCore; import electroblob.wizardry.tileentity.TileEntityStatue; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WandHelper; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiMerchant; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.renderer.entity.RenderBlaze; +import net.minecraft.client.renderer.entity.RenderHusk; +import net.minecraft.client.renderer.entity.RenderSkeleton; import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.IReloadableResourceManager; import net.minecraft.client.resources.IResourceManager; @@ -119,19 +58,33 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntityBlaze; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.ContainerMerchant; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.village.MerchantRecipeList; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Property; import net.minecraftforge.fml.client.config.GuiConfigEntries.NumberSliderEntry; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.client.registry.RenderingRegistry; +import org.lwjgl.input.Keyboard; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * The client proxy for wizardry. @@ -145,7 +98,7 @@ public class ClientProxy extends CommonProxy { public static MixedFontRenderer mixedFontRenderer; /** Static particle factory map */ - private static Map factories; + private static final Map factories = new HashMap<>(); // Key Bindings public static final KeyBinding NEXT_SPELL = new KeyBinding("key." + Wizardry.MODID + ".next_spell", Keyboard.KEY_N, "key.categories." + Wizardry.MODID); @@ -154,6 +107,9 @@ public class ClientProxy extends CommonProxy { // Armour Model public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f); + /** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style)}). */ + private static final int TOOLTIP_WRAP_WIDTH = 140; + // SECTION Registry // =============================================================================================================== @@ -178,9 +134,18 @@ public class ClientProxy extends CommonProxy { public void registerResourceReloadListeners(){ IResourceManager manager = Minecraft.getMinecraft().getResourceManager(); if(manager instanceof IReloadableResourceManager){ - ((IReloadableResourceManager)manager).registerReloadListener(GuiSpellDisplay::loadSkins); - ((IReloadableResourceManager)manager).registerReloadListener(GuiWizardHandbook::loadHandbookFile); - } + ((IReloadableResourceManager)manager).registerReloadListener(GuiSpellDisplay::loadSkins); + ((IReloadableResourceManager)manager).registerReloadListener(GuiWizardHandbook::loadHandbookFile); + } + } + +// @Override +// public void registerSoundEventListener(){ +// Minecraft.getMinecraft().getSoundHandler().addListener(ContinuousSpellSoundEntity::soundPlayed); +// } + + public void registerAtlasMarkers(){ + WizardryAntiqueAtlasIntegration.registerMarkers(); } // SECTION Misc @@ -196,16 +161,35 @@ public class ClientProxy extends CommonProxy { property.setConfigEntryClass(SpellHUDSkinChooserEntry.class); } + @Override + public void setToNamedBooleanEntry(Property property){ + property.setConfigEntryClass(NamedBooleanEntry.class); + } + @Override public World getTheWorld(){ return Minecraft.getMinecraft().world; } @Override - public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){ - Minecraft.getMinecraft().getSoundHandler().playSound(new MovingSoundEntity(entity, sound, volume, pitch, repeat)); + public void playMovingSound(Entity entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){ + Minecraft.getMinecraft().getSoundHandler().playSound(new MovingSoundEntity<>(entity, sound, category, volume, pitch, repeat)); } + @Override + public void playSpellSoundLoop(EntityLivingBase entity, Spell spell, SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, float pitch){ + SoundLoop.addLoop(new SoundLoopSpell.SoundLoopSpellEntity(start, loop, end, spell, entity, volume, pitch)); + } + + @Override + public void playSpellSoundLoop(World world, double x, double y, double z, Spell spell, SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, float pitch, int duration){ + if(duration == -1){ + SoundLoop.addLoop(new SoundLoopSpell.SoundLoopSpellDispenser(start, loop, end, spell, world, x, y, z, volume, pitch)); + }else{ + SoundLoop.addLoop(new SoundLoopSpell.SoundLoopSpellPosTimed(start, loop, end, spell, duration, x, y, z, volume, pitch)); + } + } + @Override public Set getSpellHUDSkins(){ return GuiSpellDisplay.getSkinKeys(); @@ -214,6 +198,40 @@ public class ClientProxy extends CommonProxy { // SECTION Items // =============================================================================================================== + @Override + public boolean shouldDisplayDiscovered(Spell spell, ItemStack stack){ + + EntityPlayerSP player = Minecraft.getMinecraft().player; + + if(player == null) return false; + + // Displayed recipe + if(Minecraft.getMinecraft().currentScreen instanceof GuiMerchant){ + // It doesn't actually matter if the recipe is selected or not, since the itemstack will only ever + // match one of them anyway - and we'd have to reflect into GuiMerchant to get the selected recipe + MerchantRecipeList recipes = ((GuiMerchant)Minecraft.getMinecraft().currentScreen).getMerchant().getRecipes(player); + if(recipes != null && recipes.stream().anyMatch(r -> r.getItemToSell() == stack)){ + // Spell books are always discovered when wizards are selling them + return true; + } + } + + // Recipe output slot + // Required or players would be able to find out what the spell is without actually completing the trade + if(player.openContainer instanceof ContainerMerchant){ + + if(((ContainerMerchant)player.openContainer).getMerchantInventory().getStackInSlot(2) == stack){ + return true; + } + } + + if(!Wizardry.settings.discoveryMode) return true; + if(player.isCreative()) return true; + if(WizardData.get(player) != null && WizardData.get(player).hasSpellBeenDiscovered(spell)) return true; + + return false; + } + @Override public FontRenderer getFontRenderer(ItemStack stack){ @@ -222,12 +240,10 @@ public class ClientProxy extends CommonProxy { if(stack.getItem() instanceof ItemWand){ spell = WandHelper.getCurrentSpell(stack); }else if(stack.getItem() instanceof ItemSpellBook || stack.getItem() instanceof ItemScroll){ - spell = Spell.get(stack.getItemDamage()); + spell = Spell.byMetadata(stack.getItemDamage()); } - if(Minecraft.getMinecraft().player != null && Wizardry.settings.discoveryMode && WizardData.get(Minecraft.getMinecraft().player) != null - && !Minecraft.getMinecraft().player.capabilities.isCreativeMode - && !WizardData.get(Minecraft.getMinecraft().player).hasSpellBeenDiscovered(spell)){ + if(!shouldDisplayDiscovered(spell, stack)){ return mixedFontRenderer; } @@ -237,14 +253,14 @@ public class ClientProxy extends CommonProxy { @Override public String getScrollDisplayName(ItemStack scroll){ - Spell spell = Spell.get(scroll.getItemDamage()); + Spell spell = Spell.byMetadata(scroll.getItemDamage()); EntityPlayer player = Minecraft.getMinecraft().player; boolean discovered = true; // It seems that this method is called when the world is loading, before thePlayer has been initialised. // If the player is null, the spell is assumed to be discovered. - if(player != null && Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null + if(player != null && Wizardry.settings.discoveryMode && !player.isCreative() && WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){ discovered = false; } @@ -265,37 +281,50 @@ public class ClientProxy extends CommonProxy { return super.getConjuredBowDurability(stack); } + @Override + public void addMultiLineDescription(List tooltip, String key, Style style){ + String description = style.getFormattingCode() + I18n.format(key); + tooltip.addAll(Minecraft.getMinecraft().fontRenderer.listFormattedStringToWidth(description, TOOLTIP_WRAP_WIDTH)); + } + // SECTION Particles // =============================================================================================================== + /** Use {@link ParticleWizardry#registerParticle(ResourceLocation, IWizardryParticleFactory)}, this is internal. */ + // I mean, it does exactly the same thing but I might want to make it do something else in future... + public static void addParticleFactory(ResourceLocation name, IWizardryParticleFactory factory){ + factories.put(name, factory); + } + @Override - public void initParticleFactories(){ - - factories = new HashMap<>(); - - factories.put(Type.BEAM, ParticleBeam::new); - factories.put(Type.BUFF, ParticleBuff::new); - factories.put(Type.DARK_MAGIC, ParticleDarkMagic::new); - factories.put(Type.DUST, ParticleDust::new); - factories.put(Type.FLASH, ParticleFlash::new); - factories.put(Type.ICE, ParticleIce::new); - factories.put(Type.LEAF, ParticleLeaf::new); - factories.put(Type.LIGHTNING, ParticleLightning::new); - factories.put(Type.LIGHTNING_PULSE, ParticleLightningPulse::new); - factories.put(Type.MAGIC_BUBBLE, ParticleMagicBubble::new); - factories.put(Type.MAGIC_FIRE, ParticleMagicFlame::new); - factories.put(Type.PATH, ParticlePath::new); - factories.put(Type.SCORCH, ParticleScorch::new); - factories.put(Type.SNOW, ParticleSnow::new); - factories.put(Type.SPARK, ParticleSpark::new); - factories.put(Type.SPARKLE, ParticleSparkle::new); + public void registerParticles(){ + // I'll be a good programmer and use the API method rather than the one above. Lead by example, as they say... + ParticleWizardry.registerParticle(Type.BEAM, ParticleBeam::new); + ParticleWizardry.registerParticle(Type.BUFF, ParticleBuff::new); + ParticleWizardry.registerParticle(Type.DARK_MAGIC, ParticleDarkMagic::new); + ParticleWizardry.registerParticle(Type.DUST, ParticleDust::new); + ParticleWizardry.registerParticle(Type.FLASH, ParticleFlash::new); + ParticleWizardry.registerParticle(Type.ICE, ParticleIce::new); + ParticleWizardry.registerParticle(Type.LEAF, ParticleLeaf::new); + ParticleWizardry.registerParticle(Type.LIGHTNING, ParticleLightning::new); + ParticleWizardry.registerParticle(Type.LIGHTNING_PULSE, ParticleLightningPulse::new); + ParticleWizardry.registerParticle(Type.MAGIC_BUBBLE, ParticleMagicBubble::new); + ParticleWizardry.registerParticle(Type.MAGIC_FIRE, ParticleMagicFlame::new); + ParticleWizardry.registerParticle(Type.PATH, ParticlePath::new); + ParticleWizardry.registerParticle(Type.SCORCH, ParticleScorch::new); + ParticleWizardry.registerParticle(Type.SNOW, ParticleSnow::new); + ParticleWizardry.registerParticle(Type.SPARK, ParticleSpark::new); + ParticleWizardry.registerParticle(Type.SPARKLE, ParticleSparkle::new); + ParticleWizardry.registerParticle(Type.SPHERE, ParticleSphere::new); + ParticleWizardry.registerParticle(Type.SUMMON, ParticleSummon::new); + ParticleWizardry.registerParticle(Type.VINE, ParticleVine::new); } @Override - public ParticleWizardry createParticle(Type type, World world, double x, double y, double z){ + public ParticleWizardry createParticle(ResourceLocation type, World world, double x, double y, double z){ IWizardryParticleFactory factory = factories.get(type); if(factory == null){ - Wizardry.logger.warn("Unrecognised particle type %s ! Ensure the particle is properly registered.", type); + Wizardry.logger.warn("Unrecognised particle type {} ! Ensure the particle is properly registered.", type); return null; } return factory.createParticle(world, x, y, z); @@ -315,14 +344,12 @@ public class ClientProxy extends CommonProxy { World world = Minecraft.getMinecraft().world; Entity caster = world.getEntityByID(message.casterID); - Spell spell = Spell.get(message.spellID); + Spell spell = Spell.byNetworkID(message.spellID); // Should always be true if(caster instanceof EntityPlayer){ ((EntityPlayer)caster).setActiveHand(message.hand); - // Duration isn't needed because it only ever affects things server-side, and anything that is - // seen client-side gets synced elsewhere. spell.cast(world, (EntityPlayer)caster, message.hand, 0, message.modifiers); Source source = Source.OTHER; @@ -337,19 +364,34 @@ public class ClientProxy extends CommonProxy { // No need to check if the spell succeeded, because the packet is only ever sent when it succeeds. // The handler for this event now deals with discovery. - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post((EntityPlayer)caster, spell, message.modifiers, source)); + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(source, spell, (EntityPlayer)caster, message.modifiers)); }else{ Wizardry.logger.warn("Recieved a PacketCastSpell, but the caster ID was not the ID of a player"); } } + @Override + public void handleCastSpellAtPosPacket(PacketCastSpellAtPos.Message message){ + + World world = Minecraft.getMinecraft().world; + Spell spell = Spell.byNetworkID(message.spellID); + + spell.cast(world, message.position.x, message.position.y, message.position.z, message.direction, 0, message.duration, message.modifiers); + + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.COMMAND, spell, world, message.position.x, message.position.y, message.position.z, message.direction, message.modifiers)); + + if(spell.isContinuous){ + SpellEmitter.add(spell, world, message.position.x, message.position.y, message.position.z, message.direction, message.duration, message.modifiers); + } + } + @Override public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){ World world = Minecraft.getMinecraft().world; Entity caster = world.getEntityByID(message.casterID); - Spell spell = Spell.get(message.spellID); + Spell spell = Spell.byNetworkID(message.spellID); // Should always be true if(caster instanceof EntityPlayer){ @@ -359,7 +401,7 @@ public class ClientProxy extends CommonProxy { if(data.isCasting()){ WizardData.get((EntityPlayer)caster).stopCastingContinuousSpell(); }else{ - WizardData.get((EntityPlayer)caster).startCastingContinuousSpell(spell, message.modifiers); + WizardData.get((EntityPlayer)caster).startCastingContinuousSpell(spell, message.modifiers, message.duration); } } }else{ @@ -373,7 +415,7 @@ public class ClientProxy extends CommonProxy { World world = Minecraft.getMinecraft().world; Entity caster = world.getEntityByID(message.casterID); Entity target = message.targetID == -1 ? null : world.getEntityByID(message.targetID); - Spell spell = Spell.get(message.spellID); + Spell spell = Spell.byNetworkID(message.spellID); // Should always be true if(caster instanceof EntityLiving){ @@ -382,7 +424,7 @@ public class ClientProxy extends CommonProxy { spell.cast(world, (EntityLiving)caster, message.hand, 0, (EntityLivingBase)target, message.modifiers); // Again, no need to check if the spell succeeded, because the packet is only ever sent when it // succeeds. - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post((EntityLiving)caster, spell, message.modifiers, Source.NPC)); + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.NPC, spell, (EntityLiving)caster, message.modifiers)); } if(caster instanceof ISpellCaster){ @@ -391,10 +433,41 @@ public class ClientProxy extends CommonProxy { ((EntityLiving)caster).setAttackTarget((EntityLivingBase)target); } } - }else{ + }else if(caster != null){ Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving"); } } + + @Override + public void handleDispenserCastSpellPacket(PacketDispenserCastSpell.Message message){ + + World world = Minecraft.getMinecraft().world; + + if(world.getTileEntity(message.pos) instanceof TileEntityDispenser){ // Should always be true + + Spell spell = Spell.byNetworkID(message.spellID); + + spell.cast(world, message.x, message.y, message.z, message.direction, 0, -1, message.modifiers); + // No need to check if the spell succeeded, because the packet is only ever sent when it succeeds. + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.DISPENSER, spell, world, message.x, message.y, + message.z, message.direction, message.modifiers)); + + if(spell.isContinuous || spell instanceof None){ + + DispenserCastingData data = DispenserCastingData.get((TileEntityDispenser)world.getTileEntity(message.pos)); + + if(spell.isContinuous){ + data.startCasting(spell, message.x, message.y, message.z, message.duration, message.modifiers); + }else{ + data.stopCasting(); + } + } + + }else{ + Wizardry.logger.warn("Recieved a PacketDispenserCastSpell, but no tileEntity was found at the supplied location."); + } + + } @Override public void handleTransportationPacket(PacketTransportation.Message message){ @@ -402,78 +475,150 @@ public class ClientProxy extends CommonProxy { World world = Minecraft.getMinecraft().world; Entity caster = world.getEntityByID(message.casterID); // Moved from when the packet is sent to when it is received; fixes the sound not playing in first person. - caster.playSound(SoundEvents.BLOCK_PORTAL_TRAVEL, 1, 1); + caster.playSound(WizardrySounds.SPELL_TRANSPORTATION_TRAVEL, 1, 1); for(int i = 0; i < 20; i++){ double radius = 1; - double angle = world.rand.nextDouble() * Math.PI * 2; - double x = caster.posX + radius * Math.cos(angle); + float angle = world.rand.nextFloat() * (float)Math.PI * 2; + double x = caster.posX + radius * MathHelper.cos(angle); double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2; - double z = caster.posZ + radius * Math.sin(angle); + double z = caster.posZ + radius * MathHelper.sin(angle); ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.02, 0).clr(0.6f, 1, 0.6f) .time(80 + world.rand.nextInt(10)).spawn(world); } for(int i = 0; i < 20; i++){ double radius = 1; - double angle = world.rand.nextDouble() * Math.PI * 2; - double x = caster.posX + radius * Math.cos(angle); + float angle = world.rand.nextFloat() * (float)Math.PI * 2; + double x = caster.posX + radius * MathHelper.cos(angle); double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2; - double z = caster.posZ + radius * Math.sin(angle); + double z = caster.posZ + radius * MathHelper.sin(angle); world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, x, y, z, 0, 0.02, 0); } for(int i = 0; i < 20; i++){ double radius = 1; - double angle = world.rand.nextDouble() * Math.PI * 2; - double x = caster.posX + radius * Math.cos(angle); + float angle = world.rand.nextFloat() * (float)Math.PI * 2; + double x = caster.posX + radius * MathHelper.cos(angle); double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2; - double z = caster.posZ + radius * Math.sin(angle); + double z = caster.posZ + radius * MathHelper.sin(angle); world.spawnParticle(EnumParticleTypes.ENCHANTMENT_TABLE, x, y, z, 0, 0.02, 0); } } @Override - public void handlePlayerSyncPacket(Message message){ + public void handlePlayerSyncPacket(PacketPlayerSync.Message message){ - WizardData properties = WizardData.get(Minecraft.getMinecraft().player); + WizardData data = WizardData.get(Minecraft.getMinecraft().player); - if(properties != null){ + if(data != null){ - properties.spellsDiscovered = message.spellsDiscovered; + data.synchronisedRandom.setSeed(message.seed); + data.spellsDiscovered = message.spellsDiscovered; + + message.spellData.forEach(data::setVariable); if(message.selectedMinionID == -1){ - properties.selectedMinion = null; + data.selectedMinion = null; }else{ Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.selectedMinionID); if(entity instanceof ISummonedCreature){ - properties.selectedMinion = new WeakReference((ISummonedCreature)entity); + data.selectedMinion = new WeakReference<>((ISummonedCreature)entity); }else{ - properties.selectedMinion = null; + data.selectedMinion = null; } } } } @Override - public void handleGlyphDataPacket(electroblob.wizardry.packet.PacketGlyphData.Message message){ + public void handleGlyphDataPacket(PacketGlyphData.Message message){ SpellGlyphData data = SpellGlyphData.get(Minecraft.getMinecraft().world); - data.randomNames = new HashMap(); - data.randomDescriptions = new HashMap(); + data.randomNames = new HashMap<>(); + data.randomDescriptions = new HashMap<>(); for(Spell spell : Spell.getSpells(Spell.allSpells)){ // -1 because the none spell isn't included - data.randomNames.put(spell, message.names.get(spell.id() - 1)); - data.randomDescriptions.put(spell, message.descriptions.get(spell.id() - 1)); + // This is a case where we must use the network ID, not the metadata + data.randomNames.put(spell, message.names.get(spell.networkID() - 1)); + data.randomDescriptions.put(spell, message.descriptions.get(spell.networkID() - 1)); } } @Override - public void handleClairvoyancePacket(electroblob.wizardry.packet.PacketClairvoyance.Message message){ + public void handleEmitterDataPacket(PacketEmitterData.Message message){ + message.emitters.forEach(e -> e.setWorld(Minecraft.getMinecraft().world)); // Do this as soon as possible! + SpellEmitterData data = SpellEmitterData.get(Minecraft.getMinecraft().world); + // We shouldn't need to clear the emitters because when a player logs in or changes dimension the client world + // is wiped anyway, so the call to get() above should result in a fresh SpellEmitterData instance + message.emitters.forEach(data::add); + } + + @Override + public void handleClairvoyancePacket(PacketClairvoyance.Message message){ Clairvoyance.spawnPathPaticles(Minecraft.getMinecraft().world, message.path, message.durationMultiplier); } + @Override + public void handleAdvancementSyncPacket(PacketSyncAdvancements.Message message){ + GuiWizardHandbook.updateUnlockStatus(message.showToasts, message.completedAdvancements); + } + + @Override + public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){ + Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.hostID); + if(entity instanceof EntityLivingBase) PotionSlowTime.unblockNearbyEntities((EntityLivingBase)entity); + else Wizardry.logger.warn("Received a PacketEndSlowTime, but the entity ID did not match any living entity"); + } + + @Override + public void handleResurrectionPacket(PacketResurrection.Message message){ + Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.playerID); + if(entity instanceof EntityPlayer){ + ((Resurrection)Spells.resurrection).resurrect((EntityPlayer)entity); + if(entity == Minecraft.getMinecraft().player){ + Minecraft.getMinecraft().world.spawnEntity(entity); + Minecraft.getMinecraft().displayGuiScreen(null); + } + } + else Wizardry.logger.warn("Received a PacketResurrection, but the entity ID did not match any player"); + } + + @Override + public void handlePossessionPacket(PacketPossession.Message message){ + + Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.playerID); + + if(entity instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)entity; + + if(message.targetID == -1){ + ((Possession)Spells.possession).endPossession(player); + }else{ + Entity target = Minecraft.getMinecraft().world.getEntityByID(message.targetID); + if(target instanceof EntityLiving){ + ((Possession)Spells.possession).possess(player, (EntityLiving)target, message.duration); + player.sendStatusMessage(new TextComponentTranslation("spell." + Spells.possession.getRegistryName() + + ".success", Minecraft.getMinecraft().gameSettings.keyBindSneak.getDisplayName()), true); + } + else Wizardry.logger.warn("Received a PacketPossession, but the target ID did not match any living entity"); + } + } + else Wizardry.logger.warn("Received a PacketPossession, but the player ID did not match any player"); + } + + public void handleConquerShrinePacket(PacketConquerShrine.Message message){ + + TileEntity tileEntity = Minecraft.getMinecraft().world.getTileEntity(new BlockPos(message.x, message.y, message.z)); + + if(tileEntity instanceof TileEntityShrineCore){ + ((TileEntityShrineCore)tileEntity).conquer(); + + }else Wizardry.logger.warn("Received a PacketConquerShrine, but there was no shrine core at the position sent"); + } + // SECTION Rendering // =============================================================================================================== @@ -486,6 +631,7 @@ public class ClientProxy extends CommonProxy { @Override public void initialiseLayers(){ LayerStone.initialiseLayers(); + LayerFrost.initialiseLayers(); } @Override @@ -495,6 +641,12 @@ public class ClientProxy extends CommonProxy { // Yet another advantage to the new system: turns out you don't even need to register the renderer if you // just want the vanilla one for the mob you're extending. + // Luckily for us, the vanilla husk renderer is only parametrised to EntityZombie + RenderingRegistry.registerEntityRenderingHandler(EntityHuskMinion.class, RenderHusk::new); + // This now extends AbstractSkeleton so we need to bind the renderer ourselves + RenderingRegistry.registerEntityRenderingHandler(EntitySkeletonMinion.class, RenderSkeleton::new); + RenderingRegistry.registerEntityRenderingHandler(EntityStrayMinion.class, RenderStrayMinion::new); + // An anonymous class in a lambda expression! No point writing a separate class really, is there? RenderingRegistry.registerEntityRenderingHandler(EntityLightningWraith.class, manager -> new RenderBlaze(manager){ @Override @@ -536,7 +688,7 @@ public class ClientProxy extends CommonProxy { // Throwables RenderingRegistry.registerEntityRenderingHandler(EntitySparkBomb.class, - manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/entity/spark_bomb.png"), false)); + manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/spark_bomb.png"), false)); RenderingRegistry.registerEntityRenderingHandler(EntityFirebomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/firebomb.png"), false)); RenderingRegistry.registerEntityRenderingHandler(EntityPoisonBomb.class, @@ -555,6 +707,14 @@ public class ClientProxy extends CommonProxy { manager -> new RenderLightningDisc(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 2.0f)); RenderingRegistry.registerEntityRenderingHandler(EntitySmokeBomb.class, manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/smoke_bomb.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityEmber.class, + manager -> new RenderProjectile(manager, 0.15f, new ResourceLocation(Wizardry.MODID, "textures/entity/ember.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityMagicFireball.class, + manager -> new RenderProjectile(manager, 0.7f, new ResourceLocation(Wizardry.MODID, "textures/entity/fireball.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityLargeMagicFireball.class, + manager -> new RenderProjectile(manager, 1.5f, new ResourceLocation(Wizardry.MODID, "textures/entity/fireball.png"), false)); + RenderingRegistry.registerEntityRenderingHandler(EntityIceball.class, + manager -> new RenderProjectile(manager, 0.7f, new ResourceLocation(Wizardry.MODID, "textures/entity/iceball.png"), false)); // Effects and constructs RenderingRegistry.registerEntityRenderingHandler(EntityBlackHole.class, RenderBlackHole::new); @@ -562,13 +722,14 @@ public class ClientProxy extends CommonProxy { RenderingRegistry.registerEntityRenderingHandler(EntityBubble.class, RenderBubble::new); RenderingRegistry.registerEntityRenderingHandler(EntityHammer.class, RenderHammer::new); RenderingRegistry.registerEntityRenderingHandler(EntityIceSpike.class, RenderIceSpike::new); + RenderingRegistry.registerEntityRenderingHandler(EntityForcefield.class, RenderForcefield::new); + //RenderingRegistry.registerEntityRenderingHandler(EntityContainmentField.class, RenderContainmentField::new); // Stuff that doesn't render RenderingRegistry.registerEntityRenderingHandler(EntityBlizzard.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityTornado.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityArrowRain.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityShadowWraith.class, RenderBlank::new); - RenderingRegistry.registerEntityRenderingHandler(EntityForcefield.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityThunderbolt.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityStormElemental.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityEarthquake.class, RenderBlank::new); @@ -586,6 +747,8 @@ public class ClientProxy extends CommonProxy { RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class, manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f)); RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new); + RenderingRegistry.registerEntityRenderingHandler(EntityCombustionRune.class, + manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/combustion_rune.png"), 2.0f, true)); // TESRs ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench()); diff --git a/src/main/java/electroblob/wizardry/client/DrawingUtils.java b/src/main/java/electroblob/wizardry/client/DrawingUtils.java index 382fba75..20b99a60 100644 --- a/src/main/java/electroblob/wizardry/client/DrawingUtils.java +++ b/src/main/java/electroblob/wizardry/client/DrawingUtils.java @@ -1,19 +1,13 @@ package electroblob.wizardry.client; -import org.lwjgl.opengl.GL11; - import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.RenderItem; -import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.opengl.GL11; /** * Utility class containing some useful static methods for drawing GUIs. Previously these were spread across the main @@ -23,7 +17,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; * @since Wizardry 4.2 * @see MixedFontRenderer */ -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public final class DrawingUtils { /** @@ -130,6 +124,31 @@ public final class DrawingUtils { tessellator.draw(); } + /** + * Mixes the two given opaque colours in the proportion specified. + * @param colour1 The first colour to mix, as a 6-digit hexadecimal. + * @param colour2 The second colour to mix, as a 6-digit hexadecimal. + * @param proportion The proportion of the second colour; will be clamped to between 0 and 1. + * @return The resulting colour, as a 6-digit hexadecimal. + */ + public static int mix(int colour1, int colour2, float proportion){ + + proportion = MathHelper.clamp(proportion, 0, 1); + + int r1 = colour1 >> 16 & 255; + int g1 = colour1 >> 8 & 255; + int b1 = colour1 & 255; + int r2 = colour2 >> 16 & 255; + int g2 = colour2 >> 8 & 255; + int b2 = colour2 & 255; + + int r = (int)(r1 + (r2-r1) * proportion); + int g = (int)(g1 + (g2-g1) * proportion); + int b = (int)(b1 + (b2-b1) * proportion); + + return (r << 16) + (g << 8) + b; + } + /** * Makes the given opaque colour translucent with the given opacity. * @param colour An integer colour code, should be a 6-digit hexadecimal (i.e. opaque). diff --git a/src/main/java/electroblob/wizardry/client/MixedFontRenderer.java b/src/main/java/electroblob/wizardry/client/MixedFontRenderer.java index ee098490..ff637a1c 100644 --- a/src/main/java/electroblob/wizardry/client/MixedFontRenderer.java +++ b/src/main/java/electroblob/wizardry/client/MixedFontRenderer.java @@ -5,15 +5,13 @@ import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.settings.GameSettings; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; /** * Font renderer that renders parts of strings surrounded by '#' (without quotes) in the SGA instead of normal text. * * @since Wizardry 1.1 */ -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class MixedFontRenderer extends FontRenderer { public MixedFontRenderer(GameSettings p_i1035_1_, ResourceLocation p_i1035_2_, TextureManager p_i1035_3_, diff --git a/src/main/java/electroblob/wizardry/client/MovingSoundEntity.java b/src/main/java/electroblob/wizardry/client/MovingSoundEntity.java deleted file mode 100644 index 0fdd1165..00000000 --- a/src/main/java/electroblob/wizardry/client/MovingSoundEntity.java +++ /dev/null @@ -1,52 +0,0 @@ -package electroblob.wizardry.client; - -import net.minecraft.client.audio.MovingSound; -import net.minecraft.entity.Entity; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.math.MathHelper; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -// Copied from MovingSoundMinecart; if it ever breaks between updates take a look at that. -@SideOnly(Side.CLIENT) -public class MovingSoundEntity extends MovingSound { - private final Entity source; - private float distance = 0.0F; - - public MovingSoundEntity(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){ - // Uses BLOCKS because that's the closest thing to inanimate entities. Could use NEUTRAL like - // MovingSoundMinecart. - super(sound, SoundCategory.BLOCKS); - this.source = entity; - this.repeat = repeat; - this.volume = volume; - this.pitch = pitch; - this.repeatDelay = 0; - } - - /** - * Updates the JList with a new model. - */ - @Override - public void update(){ - if(this.source.isDead && repeat){ - this.donePlaying = true; - }else{ - this.xPosF = (float)this.source.posX; - this.yPosF = (float)this.source.posY; - this.zPosF = (float)this.source.posZ; - float f = MathHelper.sqrt(this.source.motionX * this.source.motionX - + this.source.motionY * this.source.motionY + this.source.motionZ * this.source.motionZ); - - // Is this something to do with the Doppler effect? - if((double)f >= 0.01D){ - this.distance = MathHelper.clamp(this.distance + 0.0025F, 0.0F, 1.0F); - this.volume = 0.0F + MathHelper.clamp(f, 0.0F, 0.5F) * 0.7F; - }else{ - // this.pitch = 0.0F; - // this.volume = 0.0F; - } - } - } -} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java index b06ef376..a024f95e 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryClientEventHandler.java @@ -1,51 +1,52 @@ package electroblob.wizardry.client; -import org.lwjgl.opengl.GL11; - -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockMagicLight; import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.data.DispenserCastingData; +import electroblob.wizardry.data.SpellEmitterData; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.item.ItemArtefact; import electroblob.wizardry.item.ItemSpectralBow; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.spell.Flight; -import electroblob.wizardry.spell.ShadowWard; -import electroblob.wizardry.spell.Shield; -import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; -import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.spell.*; +import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiMerchant; -import net.minecraft.client.gui.inventory.GuiContainer; 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.RenderItem; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.item.EntityArmorStand; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.village.MerchantRecipe; -import net.minecraftforge.client.event.FOVUpdateEvent; -import net.minecraftforge.client.event.GuiContainerEvent; -import net.minecraftforge.client.event.RenderGameOverlayEvent; -import net.minecraftforge.client.event.RenderLivingEvent; -import net.minecraftforge.client.event.RenderPlayerEvent; -import net.minecraftforge.client.event.RenderWorldLastEvent; -import net.minecraftforge.client.event.TextureStitchEvent; -import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraft.world.World; +import net.minecraftforge.client.event.*; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; + +import java.lang.reflect.Method; /** * Event handler responsible for client-side only events, mostly rendering. @@ -53,13 +54,10 @@ import net.minecraftforge.fml.relauncher.SideOnly; * @author Electroblob * @since Wizardry 1.0 */ -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT) public final class WizardryClientEventHandler { - private static final ResourceLocation shieldTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/shield.png"); - private static final ResourceLocation wingTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/wing.png"); - private static final ResourceLocation shadowWardTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/shadow_ward.png"); private static final ResourceLocation sixthSenseTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/sixth_sense.png"); private static final ResourceLocation sixthSenseOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/sixth_sense_overlay.png"); private static final ResourceLocation frostOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/frost_overlay.png"); @@ -73,6 +71,12 @@ public final class WizardryClientEventHandler { private static int blinkEffectTimer; /** The number of ticks the blink effect lasts for. */ private static final int BLINK_EFFECT_DURATION = 8; + + private static final Method unpressKey; + + static { + unpressKey = ObfuscationReflectionHelper.findMethod(KeyBinding.class, "func_74505_d", void.class); + } /** Starts the first person blink overlay effect. */ public static void playBlinkEffect(){ @@ -80,21 +84,97 @@ public final class WizardryClientEventHandler { } @SubscribeEvent - public static void onLivingUpdateEvent(LivingUpdateEvent event){ - if(event.getEntity() == Minecraft.getMinecraft().player){ + public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){ + + if(event.player == Minecraft.getMinecraft().player){ + if(blinkEffectTimer > 0) blinkEffectTimer--; + + // Only seems to work here... +// EntityLiving victim = Possession.getPossessee(Minecraft.getMinecraft().player); +// if(victim != null && victim.getHeldItemMainhand().isEmpty()){ +// Minecraft.getMinecraft().player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY); +// } + + // Reset shaders if their respective potions aren't active + // This is a player so the potion effects are synced by vanilla + if(Minecraft.getMinecraft().entityRenderer.getShaderGroup() != null){ + + String activeShader = Minecraft.getMinecraft().entityRenderer.getShaderGroup().getShaderGroupName(); + + if((activeShader.equals(SlowTime.SHADER.toString()) && !Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.slow_time)) + || (activeShader.equals(SixthSense.SHADER.toString()) && !Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.sixth_sense)) + || (activeShader.equals(Transience.SHADER.toString()) && !Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.transience))){ + + if(activeShader.equals(SixthSense.SHADER.toString()) + || activeShader.equals(Transience.SHADER.toString())) playBlinkEffect(); + + Minecraft.getMinecraft().entityRenderer.stopUseShader(); + } + } } } @SubscribeEvent - public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + public static void onRenderHandEvent(RenderHandEvent event){ - event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_CRYSTAL); - event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_UPGRADE); + EntityLiving victim = Possession.getPossessee(Minecraft.getMinecraft().player); -// for(int i=0; i<7; i++){ -// event.getMap().registerSprite(new ResourceLocation(Wizardry.MODID, "particle/ice_" + i)); -// } + if(victim != null){ + + victim.rotationYawHead = Minecraft.getMinecraft().player.rotationYaw; + + if(Minecraft.getMinecraft().player.getHeldItemMainhand().isEmpty()){ + event.setCanceled(true); + } + } + } + + // This event is called every tick, not just when a movement key is pressed + @SubscribeEvent + public static void onInputUpdateEvent(InputUpdateEvent event){ + // Prevents the player moving when paralysed + if(event.getEntityPlayer().isPotionActive(WizardryPotions.paralysis)){ + event.getMovementInput().moveForward = 0; + event.getMovementInput().moveStrafe = 0; + event.getMovementInput().jump = false; + event.getMovementInput().sneak = false; + } + } + + @SubscribeEvent + public static void onClientTickEvent(TickEvent.ClientTickEvent event){ + + if(event.phase == TickEvent.Phase.END && !net.minecraft.client.Minecraft.getMinecraft().isGamePaused()){ + + World world = net.minecraft.client.Minecraft.getMinecraft().world; + + if(world == null) return; + + for(TileEntity tileentity : world.loadedTileEntityList){ + if(tileentity instanceof TileEntityDispenser){ + if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){ + DispenserCastingData.get((TileEntityDispenser)tileentity).update(); + } + } + } + + SpellEmitterData.update(world); + } + } + + @SubscribeEvent + public static void onMouseEvent(MouseEvent event){ + + // Prevents the player looking around when paralysed + if(Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.paralysis) + && Minecraft.getMinecraft().inGameHasFocus){ + event.setCanceled(true); + Minecraft.getMinecraft().player.prevRotationYaw = 0; + Minecraft.getMinecraft().player.prevRotationPitch = 0; + Minecraft.getMinecraft().player.rotationYaw = 0; + Minecraft.getMinecraft().player.rotationPitch = 0; + } } @SubscribeEvent @@ -121,11 +201,26 @@ public final class WizardryClientEventHandler { event.setNewfov(event.getFov() + f * f * 0.7f); } } - + + @SubscribeEvent + public static void onDrawBlockHighlightEvent(DrawBlockHighlightEvent event){ + // Hide the block outline for magic light blocks unless the player can dispel them + if(event.getTarget().typeOfHit == RayTraceResult.Type.BLOCK + && event.getPlayer().world.getBlockState(event.getTarget().getBlockPos()).getBlock() instanceof BlockMagicLight){ + + if((!(event.getPlayer().getHeldItemMainhand().getItem() instanceof ISpellCastingItem) + && !(event.getPlayer().getHeldItemOffhand().getItem() instanceof ISpellCastingItem)) + || !ItemArtefact.isArtefactActive(event.getPlayer(), WizardryItems.charm_light)){ + + event.setCanceled(true); + } + } + } + // Brute-force fix for crystals not showing up when a wizard is given a spell book in the trade GUI. @SubscribeEvent public static void onGuiDrawForegroundEvent(GuiContainerEvent.DrawForeground event){ - + if(event.getGuiContainer() instanceof GuiMerchant){ GuiMerchant gui = (GuiMerchant)event.getGuiContainer(); @@ -138,81 +233,35 @@ public final class WizardryClientEventHandler { for(MerchantRecipe trade : gui.getMerchant().getRecipes(Minecraft.getMinecraft().player)){ if(trade.getItemToBuy().getItem() == WizardryItems.spell_book && trade.getSecondItemToBuy().isEmpty()){ Slot slot = gui.inventorySlots.getSlot(2); - // Uses reflection to draw the itemstack // It still doesn't look quite right because the slot highlight is behind the item, but it'll do // until/unless I find a better solution. - renderItemAndTooltip(gui, trade.getItemToSell(), slot.xPos, slot.yPos, event.getMouseX(), event.getMouseY(), + DrawingUtils.drawItemAndTooltip(gui, trade.getItemToSell(), slot.xPos, slot.yPos, event.getMouseX(), event.getMouseY(), gui.getSlotUnderMouse() == slot); } } } } } - - private static void renderItemAndTooltip(GuiContainer gui, ItemStack stack, int x, int y, int mouseX, int mouseY, boolean tooltip){ - - RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); - GlStateManager.pushMatrix(); - RenderHelper.enableGUIStandardItemLighting(); - GlStateManager.disableLighting(); - GlStateManager.enableRescaleNormal(); - GlStateManager.enableColorMaterial(); - GlStateManager.enableLighting(); - renderItem.zLevel = 100.0F; - - if(!stack.isEmpty()){ - renderItem.renderItemAndEffectIntoGUI(stack, x, y); - renderItem.renderItemOverlays(Minecraft.getMinecraft().fontRenderer, stack, x, y); - - if(tooltip){ - gui.drawHoveringText(gui.getItemToolTip(stack), mouseX + gui.getXSize()/2 - gui.width/2, - mouseY + gui.getYSize()/2 - gui.height/2); - } - } - - GlStateManager.popMatrix(); - GlStateManager.enableLighting(); - GlStateManager.enableDepth(); - RenderHelper.enableStandardItemLighting(); - } - - // Third person - @SubscribeEvent - public static void onRenderPlayerEvent(RenderPlayerEvent.Post event){ - renderShieldIfActive(event.getEntityPlayer()); - renderWingsIfActive(event.getEntityPlayer(), event.getPartialRenderTick()); - renderShadowWardIfActive(event.getEntityPlayer()); - } - - // First person - @SubscribeEvent - public static void onRenderWorldLastEvent(RenderWorldLastEvent event){ - // Now only fires in first person. - if(Minecraft.getMinecraft().gameSettings.thirdPersonView == 0){ - renderShieldFirstPerson(Minecraft.getMinecraft().player); - renderShadowWardFirstPerson(Minecraft.getMinecraft().player); - } - } @SubscribeEvent public static void onRenderLivingEvent(RenderLivingEvent.Post event){ Minecraft mc = Minecraft.getMinecraft(); - WizardData properties = WizardData.get(mc.player); + WizardData data = WizardData.get(mc.player); RenderManager renderManager = event.getRenderer().getRenderManager(); ItemStack wand = mc.player.getHeldItemMainhand(); - if(!(wand.getItem() instanceof ItemWand)){ + if(!(wand.getItem() instanceof ISpellCastingItem)){ wand = mc.player.getHeldItemOffhand(); } // Target selection pointer - if(mc.player.isSneaking() && wand.getItem() instanceof ItemWand && WizardryUtilities.isLiving(event.getEntity()) - && properties != null && properties.selectedMinion != null){ + if(mc.player.isSneaking() && wand.getItem() instanceof ISpellCastingItem && WizardryUtilities.isLiving(event.getEntity()) + && data != null && data.selectedMinion != null){ // -> Moved this in here so it isn't called every tick - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(mc.world, mc.player, 16, false); + RayTraceResult rayTrace = RayTracer.standardEntityRayTrace(mc.world, mc.player, 16, false); if(rayTrace != null && rayTrace.entityHit == event.getEntity()){ @@ -256,7 +305,7 @@ public final class WizardryClientEventHandler { } // Summoned creature selection pointer - if(properties != null && properties.selectedMinion != null && properties.selectedMinion.get() == event.getEntity()){ + if(data != null && data.selectedMinion != null && data.selectedMinion.get() == event.getEntity()){ Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); @@ -297,8 +346,9 @@ public final class WizardryClientEventHandler { } // Sixth sense - if(mc.player.isPotionActive(WizardryPotions.sixth_sense) && !(event.getEntity() instanceof EntityArmorStand) && event.getEntity() != mc.player - && mc.player.getActivePotionEffect(WizardryPotions.sixth_sense) != null && event.getEntity().getDistance(mc.player) < 20 + if(mc.player.isPotionActive(WizardryPotions.sixth_sense) && !(event.getEntity() instanceof EntityArmorStand) + && event.getEntity() != mc.player && mc.player.getActivePotionEffect(WizardryPotions.sixth_sense) != null + && event.getEntity().getDistance(mc.player) < Spells.sixth_sense.getProperty(Spell.EFFECT_RADIUS).floatValue() * (1 + mc.player.getActivePotionEffect(WizardryPotions.sixth_sense).getAmplifier() * Constants.RANGE_INCREASE_PER_LEVEL)){ Tessellator tessellator = Tessellator.getInstance(); @@ -413,322 +463,4 @@ public final class WizardryClientEventHandler { GlStateManager.popMatrix(); } - // FIXME: Something in here is making the first person shadow ward rather translucent. - private static void renderShadowWardFirstPerson(EntityPlayer entityplayer){ - ItemStack wand = entityplayer.getActiveItemStack(); - if(WizardData.get(entityplayer) != null && WizardData.get(entityplayer).currentlyCasting() instanceof ShadowWard - || (entityplayer.isHandActive() && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand - && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){ - - GlStateManager.pushMatrix(); - - GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GlStateManager.shadeModel(GL11.GL_SMOOTH); - GlStateManager.disableLighting(); - GlStateManager.disableAlpha(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); - - GlStateManager.translate(0, 1.2, 0); - GlStateManager.rotate(-entityplayer.rotationYaw, 0, 1, 0); - GlStateManager.rotate(entityplayer.rotationPitch, 1, 0, 0); - - Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture); - - GlStateManager.pushMatrix(); - - GlStateManager.translate(0, 0, 1.2); - GlStateManager.rotate(entityplayer.world.getWorldTime() * -2, 0, 0, 1); - GlStateManager.scale(1.1, 1.1, 1.1); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - - buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); - buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); - buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); - buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); - - tessellator.draw(); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - - buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); - buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); - buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); - buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); - - tessellator.draw(); - - GlStateManager.popMatrix(); - - GlStateManager.shadeModel(GL11.GL_FLAT); - GlStateManager.enableLighting(); - GlStateManager.disableBlend(); - - GlStateManager.popMatrix(); - - } - } - - private static void renderShadowWardIfActive(EntityPlayer entityplayer){ - ItemStack wand = entityplayer.getActiveItemStack(); - if(WizardData.get(entityplayer).currentlyCasting() instanceof ShadowWard - || (entityplayer.isHandActive() && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand - && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){ - - GlStateManager.pushMatrix(); - - GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GlStateManager.disableLighting(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); - - GlStateManager.rotate(180, 0, 1, 0); - GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0); - - Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - GlStateManager.translate(0, 1.2, 0); - GlStateManager.rotate(entityplayer.world.getWorldTime() * -2, 0, 0, 1); - GlStateManager.scale(1.1, 1.1, 1.1); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - - buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); - buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); - buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); - buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); - - tessellator.draw(); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - - buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); - buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); - buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); - buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); - - tessellator.draw(); - - GlStateManager.enableLighting(); - GlStateManager.disableBlend(); - - GlStateManager.popMatrix(); - - } - } - - private static void renderWingsIfActive(EntityPlayer entityplayer, float partialTickTime){ - ItemStack wand = entityplayer.getActiveItemStack(); - if(WizardData.get(entityplayer).currentlyCasting() instanceof Flight - || (entityplayer.isHandActive() && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand - && WandHelper.getCurrentSpell(wand) instanceof Flight)){ - - GlStateManager.pushMatrix(); - - GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GlStateManager.disableLighting(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); - - // GlStateManager.rotate(-entityplayer.rotationYawHead, 0, 1, 0); - GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0); - // GlStateManager.rotate(180, 1, 0, 0); - - Minecraft.getMinecraft().renderEngine.bindTexture(wingTexture); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - GlStateManager.pushMatrix(); - - GlStateManager.translate(0.1, 0.4, -0.15); - GlStateManager.rotate(20 + 20 * (float)Math.sin(entityplayer.world.getWorldTime() * 0.3), 0, 1, 0); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - - buffer.pos(0, 2, 0).tex(0, 0).endVertex(); - buffer.pos(2, 2, 0).tex(1, 0).endVertex(); - buffer.pos(2, 0, 0).tex(1, 1).endVertex(); - buffer.pos(0, 0, 0).tex(0, 1).endVertex(); - - tessellator.draw(); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - - buffer.pos(0, 2, 0).tex(0, 0).endVertex(); - buffer.pos(0, 0, 0).tex(0, 1).endVertex(); - buffer.pos(2, 0, 0).tex(1, 1).endVertex(); - buffer.pos(2, 2, 0).tex(1, 0).endVertex(); - - tessellator.draw(); - - GlStateManager.popMatrix(); - - GlStateManager.pushMatrix(); - - GlStateManager.translate(-0.1, 0.4, -0.15); - GlStateManager.rotate(-200 - 20 * (float)Math.sin(entityplayer.world.getWorldTime() * 0.3), 0, 1, 0); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - - buffer.pos(0, 2, 0).tex(0, 0).endVertex(); - buffer.pos(2, 2, 0).tex(1, 0).endVertex(); - buffer.pos(2, 0, 0).tex(1, 1).endVertex(); - buffer.pos(0, 0, 0).tex(0, 1).endVertex(); - - tessellator.draw(); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - - buffer.pos(0, 2, 0).tex(0, 0).endVertex(); - buffer.pos(0, 0, 0).tex(0, 1).endVertex(); - buffer.pos(2, 0, 0).tex(1, 1).endVertex(); - buffer.pos(2, 2, 0).tex(1, 0).endVertex(); - - tessellator.draw(); - - GlStateManager.popMatrix(); - - GlStateManager.enableLighting(); - GlStateManager.disableBlend(); - - GlStateManager.popMatrix(); - } - } - - private static void renderShieldFirstPerson(EntityPlayer entityplayer){ - ItemStack wand = entityplayer.getActiveItemStack(); - if(WizardData.get(entityplayer) != null && WizardData.get(entityplayer).shield != null - && (WizardData.get(entityplayer).currentlyCasting() instanceof Shield - || (entityplayer.isHandActive() && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand - && WandHelper.getCurrentSpell(wand) instanceof Shield))){ - - GlStateManager.pushMatrix(); - - GlStateManager.disableCull(); - GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA); - GlStateManager.shadeModel(GL11.GL_SMOOTH); - GlStateManager.disableLighting(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); - - GlStateManager.translate(0, 1.4, 0); - - GlStateManager.rotate(-entityplayer.rotationYaw, 0, 1, 0); - GlStateManager.rotate(entityplayer.rotationPitch, 1, 0, 0); - - GlStateManager.translate(0, 0, 0.8); - - Tessellator tessellator = Tessellator.getInstance(); - - Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture); - - renderShield(tessellator); - - GlStateManager.enableLighting(); - - GlStateManager.shadeModel(GL11.GL_FLAT); - GlStateManager.enableCull(); - GlStateManager.disableBlend(); - // RenderHelper.enableStandardItemLighting(); - - GlStateManager.popMatrix(); - } - } - - private static void renderShieldIfActive(EntityPlayer entityplayer){ - ItemStack wand = entityplayer.getActiveItemStack(); - if(WizardData.get(entityplayer).shield != null && (WizardData.get(entityplayer).currentlyCasting() instanceof Shield - || (entityplayer.isHandActive() && wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand - && WandHelper.getCurrentSpell(wand) instanceof Shield))){ - - GlStateManager.pushMatrix(); - - GlStateManager.disableCull(); - GlStateManager.enableBlend(); - // For some reason, the old blend function (GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA) caused the inner - // edges to appear black, so I have changed it to this, which looks very slightly different. - GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA); - GlStateManager.shadeModel(GL11.GL_SMOOTH); - GlStateManager.disableLighting(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); - - GlStateManager.translate(0, 1.3, 0); - - // GlStateManager.rotate(180, 0, 1, 0); - GlStateManager.rotate(-entityplayer.renderYawOffset, 0, 1, 0); - // GlStateManager.rotate(-entityplayer.rotationPitch, 1, 0, 0); - - GlStateManager.translate(0, 0, 0.8); - - Tessellator tessellator = Tessellator.getInstance(); - - Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture); - - renderShield(tessellator); - - GlStateManager.enableLighting(); - - GlStateManager.shadeModel(GL11.GL_FLAT); - GlStateManager.enableCull(); - GlStateManager.disableBlend(); - // RenderHelper.enableStandardItemLighting(); - - GlStateManager.popMatrix(); - } - } - - private static void renderShield(Tessellator tessellator){ - - BufferBuilder buffer = tessellator.getBuffer(); - - double widthOuter = 0.6d; - double heightOuter = 0.7d; - double widthInner = 0.3d; - double heightInner = 0.4d; - double depth = 0.2d; - - buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); - - buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex(); - buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); - buffer.pos(-widthInner, heightOuter, -depth).tex(0.2, 0).color(0, 0, 0, 255).endVertex(); - buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); - - buffer.pos(widthInner, heightOuter, -depth).tex(0.8, 0).color(0, 0, 0, 255).endVertex(); - buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); - buffer.pos(widthOuter, heightInner, -depth).tex(1, 0.2).color(0, 0, 0, 255).endVertex(); - buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); - - buffer.pos(widthOuter, -heightInner, -depth).tex(1, 0.8).color(0, 0, 0, 255).endVertex(); - buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); - buffer.pos(widthInner, -heightOuter, -depth).tex(0.8, 1).color(0, 0, 0, 255).endVertex(); - buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); - - buffer.pos(-widthInner, -heightOuter, -depth).tex(0.2, 1).color(0, 0, 0, 255).endVertex(); - buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); - buffer.pos(-widthOuter, -heightInner, -depth).tex(0, 0.8).color(0, 0, 0, 255).endVertex(); - buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); - - buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex(); - buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); - - tessellator.draw(); - - buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); - - buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); - buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); - buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); - buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); - - tessellator.draw(); - } - } diff --git a/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java b/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java index ce212de8..7b98aca0 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java @@ -1,14 +1,11 @@ package electroblob.wizardry.client; -import org.lwjgl.input.Keyboard; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.gui.GuiSpellDisplay; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.packet.PacketControlInput; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.WandHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.entity.player.EntityPlayer; @@ -16,72 +13,54 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.client.event.MouseEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.InputEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; /** Event handler class responsible for handling wizardry's controls. */ -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT) public class WizardryControlHandler { static boolean NkeyPressed = false; static boolean BkeyPressed = false; - static boolean NkeyAlreadyPressed = false; - static boolean BkeyAlreadyPressed = false; + // Changed to a tick event to allow mouse button keybinds + // The 'lag' that happened previously was actually because the code only fired when a keyboard key was pressed! @SubscribeEvent - public static void onKeyInput(InputEvent.KeyInputEvent event){ + public static void onTickEvent(TickEvent.ClientTickEvent event){ - // Key pressed - if(Keyboard.getEventKeyState()){ + if(event.phase == TickEvent.Phase.END) return; // Only really needs to be once per tick - if(Wizardry.proxy instanceof ClientProxy){ - - EntityPlayer player = Minecraft.getMinecraft().player; - ItemStack wand = player.getHeldItemMainhand(); + if(Wizardry.proxy instanceof ClientProxy){ - if(!(wand.getItem() instanceof ItemWand)){ - wand = player.getHeldItemOffhand(); - // If the player isn't holding a wand, then nothing else needs to be done. - if(!(wand.getItem() instanceof ItemWand)) return; - } + EntityPlayer player = Minecraft.getMinecraft().player; - if(ClientProxy.NEXT_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){ + if(player != null){ + + ItemStack wand = getWandInUse(player); + if(wand == null) return; + + if(ClientProxy.NEXT_SPELL.isKeyDown() && Minecraft.getMinecraft().inGameHasFocus){ if(!NkeyPressed){ NkeyPressed = true; - }else{ - NkeyAlreadyPressed = true; - } - if(!NkeyAlreadyPressed){ selectNextSpell(wand); } + }else{ + NkeyPressed = false; } - if(ClientProxy.PREVIOUS_SPELL.isPressed() && Minecraft.getMinecraft().inGameHasFocus){ + if(ClientProxy.PREVIOUS_SPELL.isKeyDown() && Minecraft.getMinecraft().inGameHasFocus){ if(!BkeyPressed){ BkeyPressed = true; - }else{ - BkeyAlreadyPressed = true; - } - if(!BkeyAlreadyPressed){ + // Packet building selectPreviousSpell(wand); } + }else{ + BkeyPressed = false; } } } - - // Key released - else{ - if(NkeyPressed){ - NkeyPressed = false; - NkeyAlreadyPressed = false; - }else if(BkeyPressed){ - BkeyPressed = false; - BkeyAlreadyPressed = false; - } - } } // Shift-scrolling to change spells @@ -89,16 +68,11 @@ public class WizardryControlHandler { public static void onMouseEvent(MouseEvent event){ EntityPlayer player = Minecraft.getMinecraft().player; - ItemStack wand = player.getHeldItemMainhand(); - - if(!(wand.getItem() instanceof ItemWand)){ - wand = player.getHeldItemOffhand(); - // If the player isn't holding a wand, then nothing else needs to be done. - if(!(wand.getItem() instanceof ItemWand)) return; - } + ItemStack wand = getWandInUse(player); + if(wand == null) return; if(Minecraft.getMinecraft().inGameHasFocus && !wand.isEmpty() && event.getDwheel() != 0 && player.isSneaking() - && Wizardry.settings.enableShiftScrolling){ + && Wizardry.settings.shiftScrolling){ event.setCanceled(true); @@ -111,15 +85,28 @@ public class WizardryControlHandler { } } } + + private static ItemStack getWandInUse(EntityPlayer player){ + + ItemStack wand = player.getHeldItemMainhand(); + + // Only bother sending packets if the player is holding a spellcasting item with more than one spell slot + if(!(wand.getItem() instanceof ISpellCastingItem) || ((ISpellCastingItem)wand.getItem()).getSpells(wand).length < 2){ + wand = player.getHeldItemOffhand(); + if(!(wand.getItem() instanceof ISpellCastingItem) || ((ISpellCastingItem)wand.getItem()).getSpells(wand).length < 2) return null; + } + + return wand; + } private static void selectNextSpell(ItemStack wand){ // Packet building IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY); WizardryPacketHandler.net.sendToServer(msg); // GUI switch animation - WandHelper.selectNextSpell(wand); // Makes sure the spell is set immediately for the client + ((ISpellCastingItem)wand.getItem()).selectNextSpell(wand); // Makes sure the spell is set immediately for the client GuiSpellDisplay.playSpellSwitchAnimation(true); - Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.SELECT_SPELL, 1)); + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1)); } private static void selectPreviousSpell(ItemStack wand){ @@ -127,8 +114,8 @@ public class WizardryControlHandler { IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY); WizardryPacketHandler.net.sendToServer(msg); // GUI switch animation - WandHelper.selectPreviousSpell(wand); // Makes sure the spell is set immediately for the client + ((ISpellCastingItem)wand.getItem()).selectPreviousSpell(wand); // Makes sure the spell is set immediately for the client GuiSpellDisplay.playSpellSwitchAnimation(false); - Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.SELECT_SPELL, 1)); + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1)); } } diff --git a/src/main/java/electroblob/wizardry/client/audio/MovingSoundEntity.java b/src/main/java/electroblob/wizardry/client/audio/MovingSoundEntity.java new file mode 100644 index 00000000..11291f26 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/audio/MovingSoundEntity.java @@ -0,0 +1,35 @@ +package electroblob.wizardry.client.audio; + +import net.minecraft.client.audio.MovingSound; +import net.minecraft.entity.Entity; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; + +// Copied from MovingSoundMinecart; if it ever breaks between updates take a look at that. +//@SideOnly(Side.CLIENT) +public class MovingSoundEntity extends MovingSound { + + protected final T source; + protected float distance = 0.0F; + + public MovingSoundEntity(T entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){ + super(sound, category); + this.source = entity; + this.repeat = repeat; + this.volume = volume; + this.pitch = pitch; + this.repeatDelay = 0; + } + + @Override + public void update(){ + + if(this.source.isDead){ + this.donePlaying = true; + }else{ + this.xPosF = (float)this.source.posX; + this.yPosF = (float)this.source.posY; + this.zPosF = (float)this.source.posZ; + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/audio/SoundLoop.java b/src/main/java/electroblob/wizardry/client/audio/SoundLoop.java new file mode 100644 index 00000000..651fb7fb --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/audio/SoundLoop.java @@ -0,0 +1,94 @@ +package electroblob.wizardry.client.audio; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.ISound; +import net.minecraft.util.ITickable; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.relauncher.Side; + +import java.util.HashSet; +import java.util.Set; + +/** + * Instances of this class represent a set of sounds which together form a looped sound: start, loop and end. + * Currently this is only used for continuous spell sounds in wizardry itself, but feel free to make your own + * implementations - this class will take care of the internals. + * + * @since Wizardry 4.2 + * @author Electroblob + */ +// See MusicTicker, this is the same idea of just storing the sounds statically client-side and ticking them +@Mod.EventBusSubscriber(Side.CLIENT) +public abstract class SoundLoop implements ITickable { + + private static final Set activeLoops = new HashSet<>(); + + private final ISound start; + private final ISound loop; + private final ISound end; + + private boolean looping = false; + private boolean needsRemoving = false; + + public SoundLoop(SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, ISoundFactory factory){ + // The reason I've gone to the effort of having a factory for these is that we need SoundLoop to have control + // over which sounds are repeated and which aren't whilst keeping them private. + this.start = factory.create(start, category, false); + this.loop = factory.create(loop, category, true); + this.end = factory.create(end, category, false); + } + + @Override + public void update(){ + // Check every tick if the start sound is done playing and if so, start the loop sound + if(!looping && !Minecraft.getMinecraft().getSoundHandler().isSoundPlaying(start)){ + Minecraft.getMinecraft().getSoundHandler().playSound(loop); + looping = true; + } + } + + /** Stops the loop part of the sound immediately and starts playing the end part. This may be called from subclasses + * or externally depending on the implementation. */ + // For continuous spell sounds it's internally + public void endLoop(){ + Minecraft.getMinecraft().getSoundHandler().stopSound(start); + Minecraft.getMinecraft().getSoundHandler().stopSound(loop); + Minecraft.getMinecraft().getSoundHandler().playSound(end); + // Can't modify activeLoops directly since we'll probably be calling this method from update(), which is + // during iteration of activeLoops so it could cause a ConcurrentModificationException + this.markForRemoval(); + } + + /** Marks this sound loop to be removed next tick. */ + protected void markForRemoval(){ + this.needsRemoving = true; + } + + // Static methods + + public static void addLoop(SoundLoop loop){ + activeLoops.add(loop); + // Do this here rather than in the constructor in case someone wants to play the loop later or reuse it + Minecraft.getMinecraft().getSoundHandler().playSound(loop.start); + } + + @SubscribeEvent + public static void tick(TickEvent.ClientTickEvent event){ + // Using the END phase means we can check for stopped sounds as soon as they are stopped (effectively), + // meaning we don't get the 'cut' between the start and loop sounds + // FIXME: Apparently this only works for dispensers. What the heck is the difference?! + if(event.phase == TickEvent.Phase.END){ + activeLoops.forEach(SoundLoop::update); + activeLoops.removeIf(s -> s.needsRemoving); + } + } + + @FunctionalInterface + public interface ISoundFactory { + ISound create(SoundEvent sound, SoundCategory category, boolean repeat); + } +} diff --git a/src/main/java/electroblob/wizardry/client/audio/SoundLoopSpell.java b/src/main/java/electroblob/wizardry/client/audio/SoundLoopSpell.java new file mode 100644 index 00000000..bb4d9b44 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/audio/SoundLoopSpell.java @@ -0,0 +1,117 @@ +package electroblob.wizardry.client.audio; + +import electroblob.wizardry.data.DispenserCastingData; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.audio.PositionedSound; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityDispenser; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +/** Abstract base class for sound loops associated with spells; see subclasses below for implementations. */ +public abstract class SoundLoopSpell extends SoundLoop { + + private final Spell spell; + + public SoundLoopSpell(SoundEvent start, SoundEvent loop, SoundEvent end, ISoundFactory factory, Spell spell){ + super(start, loop, end, WizardrySounds.SPELLS, factory); + this.spell = spell; + } + + @Override + public void update(){ + // This may be a bit overkill but I might as well put functionality in superclasses where possible + if(stillCasting(spell)){ + // This can't called in the same tick as endLoop because otherwise, if the spell casting stops during the + // same tick as the transition to the loop sound it will try and stop the loop immediately after it has + // started - and for whatever reason, this causes the 'Channel null in method stop' error. + super.update(); + }else{ + endLoop(); + } + } + + protected abstract boolean stillCasting(Spell spell); + + /** Implements a sound loop for continuous spells cast by entities. */ + public static class SoundLoopSpellEntity extends SoundLoopSpell { + + private final EntityLivingBase source; + + public SoundLoopSpellEntity(SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell, EntityLivingBase source, float volume, float pitch){ + super(start, loop, end, (sound, category, repeat) -> new MovingSoundEntity<>(source, sound, category, volume, pitch, repeat), spell); + this.source = source; + } + + @Override + protected boolean stillCasting(Spell spell){ + return WizardryUtilities.isCasting(source, spell); + } + } + + public static abstract class SoundLoopSpellPosition extends SoundLoopSpell { + + public SoundLoopSpellPosition (SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell, + double x, double y, double z, float sndVolume, float sndPitch){ + // Huh, I actually found a use for a non-static initialiser block - hence the double curly brackets... + super(start, loop, end, (sound, category, r) -> new PositionedSound(sound, category){{ + // ...et voila, we can just set protected fields as we please using external variables + this.xPosF = (float)x; + this.yPosF = (float)y; + this.zPosF = (float)z; + this.repeat = r; + this.volume = sndVolume; + this.pitch = sndPitch; + }}, spell); + } + } + + /** Implements a sound loop for continuous spells cast by dispensers. */ + public static class SoundLoopSpellDispenser extends SoundLoopSpellPosition { + + private final TileEntityDispenser source; + + public SoundLoopSpellDispenser(SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell, World world, + double x, double y, double z, float sndVolume, float sndPitch){ + super(start, loop, end, spell, x, y, z, sndVolume, sndPitch); + + TileEntity tileentity = world.getTileEntity(new BlockPos(x, y, z)); + + if(tileentity instanceof TileEntityDispenser) this.source = (TileEntityDispenser)tileentity; + else throw new NullPointerException(String.format("Playing continuous spell sound: no dispenser found at %s, %s, %s", x, y, z)); + } + + @Override + protected boolean stillCasting(Spell spell){ + return DispenserCastingData.get(source).currentlyCasting() == spell; + } + + } + + /** Implements a sound loop for continuous spells cast at a position (via commands). */ + public static class SoundLoopSpellPosTimed extends SoundLoopSpellPosition { + + private int timeLeft; + + public SoundLoopSpellPosTimed(SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell, int duration, + double x, double y, double z, float sndVolume, float sndPitch){ + super(start, loop, end, spell, x, y, z, sndVolume, sndPitch); + this.timeLeft = duration; + } + + @Override + public void update(){ + super.update(); + timeLeft--; + } + + @Override + protected boolean stillCasting(Spell spell){ + return timeLeft > 0; + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java index 43d1a5c2..9fe07cb1 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiArcaneWorkbench.java @@ -1,23 +1,27 @@ package electroblob.wizardry.client.gui; -import org.lwjgl.input.Keyboard; - -import electroblob.wizardry.SpellGlyphData; -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.constants.Element; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.data.SpellGlyphData; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.IManaStoringItem; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.item.IWorkbenchItem; import electroblob.wizardry.packet.PacketControlInput; import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.IInventory; @@ -25,131 +29,260 @@ import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.relauncher.Side; +import org.lwjgl.input.Keyboard; +@Mod.EventBusSubscriber(Side.CLIENT) public class GuiArcaneWorkbench extends GuiContainer { private GuiButton applyBtn; - private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, + public static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png"); private IInventory playerInventory; private IInventory arcaneWorkbenchInventory; - private final int tooltipWidth = 164; + private static final int TOOLTIP_WIDTH = 164; - // We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it. - // For calculations, we use the size without the tooltip. - private final int xSizeNoTip = 176; + /** We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it. + * For calculations, we use the size without the tooltip, which is stored in this constant. */ + private static final int MAIN_GUI_WIDTH = 176; + + private static final int RUNE_LEFT = 38; + private static final int RUNE_TOP = 22; + private static final int RUNE_WIDTH = 100; + private static final int RUNE_HEIGHT = 100; + + private static final int HALO_DIAMETER = 156; + + private static final int TEXTURE_WIDTH = 512; + private static final int TEXTURE_HEIGHT = 256; + + private int animationTimer = 0; + private static final int ANIMATION_DURATION = 20; public GuiArcaneWorkbench(InventoryPlayer invPlayer, TileEntityArcaneWorkbench entity){ super(new ContainerArcaneWorkbench(invPlayer, entity)); this.playerInventory = invPlayer; this.arcaneWorkbenchInventory = entity; - xSize = xSizeNoTip; + xSize = MAIN_GUI_WIDTH; ySize = 220; } + // Huh, didn't realise this method existed. Pretty neat. @Override - public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_){ - - this.drawDefaultBackground(); - - // Tests if there is a wand in the workbench and edits the positioning accordingly - if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots - .getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){ - xSize = xSizeNoTip + tooltipWidth; - guiLeft = (this.width - this.xSize) / 2; - this.applyBtn.x = (this.width - tooltipWidth) / 2 + 48; - }else{ - xSize = xSizeNoTip; - guiLeft = (this.width - this.xSize) / 2; - this.applyBtn.x = this.width / 2 + 48; - } - - if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){ - this.applyBtn.enabled = true; - }else{ - this.applyBtn.enabled = false; - } - - super.drawScreen(p_73863_1_, p_73863_2_, p_73863_3_); - - // Required now, or item mouseover tooltips won't render. - this.renderHoveredToolTip(p_73863_1_, p_73863_2_); + public void updateScreen(){ + if(animationTimer > 0) animationTimer--; } @Override - public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY){ + public void drawScreen(int mouseX, int mouseY, float partialTicks){ - GlStateManager.color(1F, 1F, 1F, 1F); + this.drawDefaultBackground(); + + GlStateManager.color(1, 1, 1, 1); // Just in case + + Slot slot = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT); + + // Tests if there is a wand in the workbench and edits the positioning accordingly + if(slot.getHasStack() && slot.getStack().getItem() instanceof IWorkbenchItem + && ((IWorkbenchItem)slot.getStack().getItem()).showTooltip(slot.getStack())){ + xSize = MAIN_GUI_WIDTH + TOOLTIP_WIDTH; + guiLeft = (this.width - this.xSize) / 2; + this.applyBtn.x = (this.width - TOOLTIP_WIDTH) / 2 + 64; + }else{ + xSize = MAIN_GUI_WIDTH; + guiLeft = (this.width - this.xSize) / 2; + this.applyBtn.x = this.width / 2 + 64; + } + + this.applyBtn.enabled = slot.getHasStack(); + + super.drawScreen(mouseX, mouseY, partialTicks); + + // Required now, or item mouseover tooltips won't render. + this.renderHoveredToolTip(mouseX, mouseY); + } + + @Override + public void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY){ + + GlStateManager.color(1, 1, 1, 1); Minecraft.getMinecraft().renderEngine.bindTexture(texture); + + // Animation + + // Grey background + DrawingUtils.drawTexturedRect(guiLeft + RUNE_LEFT, guiTop + RUNE_TOP, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, 0, + RUNE_WIDTH, RUNE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT); + + // Yellow 'halo' + if(animationTimer > 0){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + + int x = guiLeft + RUNE_LEFT + RUNE_WIDTH/2; + int y = guiTop + RUNE_TOP + RUNE_HEIGHT/2; + + float scale = (animationTimer + partialTicks)/ANIMATION_DURATION; + scale = (float)(1 - Math.pow(1-scale, 1.4f)); // Makes it slower at the start and speed up + GlStateManager.scale(scale, scale, 1); + GlStateManager.translate(x/scale, y/scale, 0); + + DrawingUtils.drawTexturedRect(-HALO_DIAMETER /2, -HALO_DIAMETER /2, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, RUNE_HEIGHT, + HALO_DIAMETER, HALO_DIAMETER, TEXTURE_WIDTH, TEXTURE_HEIGHT); + + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + } // Main inventory DrawingUtils.drawTexturedRect(guiLeft, guiTop, 0, 0, MAIN_GUI_WIDTH, ySize, TEXTURE_WIDTH, TEXTURE_HEIGHT); + float opacity = (animationTimer + partialTicks)/ANIMATION_DURATION; + // Changing slots for(int i = 0; i < ContainerArcaneWorkbench.CRYSTAL_SLOT; i++){ + Slot slot = this.inventorySlots.getSlot(i); - if(slot.xPos >= 0 && slot.yPos >= 0) - this.drawTexturedModalRect(guiLeft + slot.xPos - 10, guiTop + slot.yPos - 10, 0, 220, 36, 36); + + if(slot.xPos >= 0 && slot.yPos >= 0){ + // Slot background + DrawingUtils.drawTexturedRect(guiLeft + slot.xPos - 10, guiTop + slot.yPos - 10, 0, 220, 36, 36, TEXTURE_WIDTH, TEXTURE_HEIGHT); + + // Slot animation + // IDEA: Somehow replace with intelligent check for whether the spell actually got applied + if(animationTimer > 0 && slot.getHasStack()){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.color(1, 1, 1, opacity); + + DrawingUtils.drawTexturedRect(guiLeft + slot.xPos - 10, guiTop + slot.yPos - 10, 36, 220, 36, 36, TEXTURE_WIDTH, TEXTURE_HEIGHT); + + GlStateManager.color(1, 1, 1, 1); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + } + } + } + + // Crystal + upgrade slot animations + if(animationTimer > 0){ + + Slot crystals = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CRYSTAL_SLOT); + Slot upgrades = this.inventorySlots.getSlot(ContainerArcaneWorkbench.UPGRADE_SLOT); + + if(crystals.getHasStack()){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.color(1, 1, 1, opacity); + + DrawingUtils.drawTexturedRect(guiLeft + crystals.xPos - 8, guiTop + crystals.yPos - 8, + MAIN_GUI_WIDTH + TOOLTIP_WIDTH + RUNE_WIDTH, 0, 32, 32, TEXTURE_WIDTH, TEXTURE_HEIGHT); + + GlStateManager.color(1, 1, 1, 1); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + } + + if(upgrades.getHasStack()){ + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.color(1, 1, 1, opacity); + + DrawingUtils.drawTexturedRect(guiLeft + upgrades.xPos - 8, guiTop + upgrades.yPos - 8, + MAIN_GUI_WIDTH + TOOLTIP_WIDTH + RUNE_WIDTH, 0, 32, 32, TEXTURE_WIDTH, TEXTURE_HEIGHT); + + GlStateManager.color(1, 1, 1, 1); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + } } // Tooltip only drawn if there is a wand - if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots - .getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){ + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){ - // Tooltip box - drawTexturedModalRect(guiLeft + xSizeNoTip, guiTop, xSizeNoTip, 0, 256 - xSizeNoTip - 4, ySize); - drawTexturedModalRect(guiLeft + 252, guiTop, xSizeNoTip + 4, 0, tooltipWidth - 2 * (256 - xSizeNoTip - 4), ySize); - drawTexturedModalRect(guiLeft + xSize - (256 - xSizeNoTip - 4), guiTop, xSizeNoTip + 4, 0, - 256 - xSizeNoTip - 4, ySize); + ItemStack stack = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack(); - ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack(); - - Spell[] spells = WandHelper.getSpells(wand); - - int i = 0; - - for(Spell spell : spells){ - - boolean discovered = true; - - if(!this.mc.player.capabilities.isCreativeMode && WizardData.get(this.mc.player) != null){ - discovered = WizardData.get(this.mc.player).hasSpellBeenDiscovered(spell); - } - // As of Wizardry 1.2, the icons have been split off into their own texture files to allow for add-on - // mods to add their own. - Minecraft.getMinecraft().renderEngine - .bindTexture(discovered ? spell.element.getIcon() : Element.MAGIC.getIcon()); - - // Renders the little element icon - DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + 5, guiTop + 34 + 10 * i++, 8, 8); + if(!(stack.getItem() instanceof IWorkbenchItem)){ + Wizardry.logger.warn("Invalid item in central slot of arcane workbench, how did that get there?!"); + return; } - int x = 0; - int y = guiTop + 50 + spells.length * 10; + if(((IWorkbenchItem)stack.getItem()).showTooltip(stack)){ - // Look how much shorter this is with the WandHelper class! - for(Item item : WandHelper.getSpecialUpgrades()){ + // Tooltip box + DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH, guiTop, MAIN_GUI_WIDTH, 0, TOOLTIP_WIDTH, ySize, TEXTURE_WIDTH, TEXTURE_HEIGHT); - int level = WandHelper.getUpgradeLevel(wand, item); + int y = guiTop + 20; - if(level > 0){ - ItemStack stack = new ItemStack(item, level); - GlStateManager.enableDepth(); - this.itemRender.renderItemAndEffectIntoGUI(stack, guiLeft + xSizeNoTip + 6 + x, y); - this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack, guiLeft + xSizeNoTip + 6 + x, y, - null); - x += 18; - GlStateManager.disableDepth(); + if(stack.getItem() instanceof IManaStoringItem && ((IManaStoringItem)stack.getItem()).showManaInWorkbench(this.mc.player, stack)){ + y += 14; + } + + if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).showSpellsInWorkbench(this.mc.player, stack)){ + + Spell[] spells = ((ISpellCastingItem)stack.getItem()).getSpells(stack); + + GlStateManager.enableBlend(); + + for(Spell spell : spells){ + + boolean discovered = true; + + if(!this.mc.player.isCreative() && WizardData.get(this.mc.player) != null){ + discovered = WizardData.get(this.mc.player).hasSpellBeenDiscovered(spell); + } + // As of Wizardry 1.2, the icons have been split off into their own texture files to allow for add-on + // mods to add their own. + Minecraft.getMinecraft().renderEngine + .bindTexture(discovered ? spell.getElement().getIcon() : Element.MAGIC.getIcon()); + + // Renders the little element icon + DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + 5, y, 8, 8); + + y += 10; + } + } + + GlStateManager.disableBlend(); + + int x = 0; + y += 16; + + // Look how much shorter this is with the WandHelper class! + for(Item item : WandHelper.getSpecialUpgrades()){ + + int level = WandHelper.getUpgradeLevel(stack, item); + + if(level > 0){ + ItemStack stack1 = new ItemStack(item, level); + GlStateManager.enableDepth(); + this.itemRender.renderItemAndEffectIntoGUI(stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y); + this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y, + null); + x += 18; + GlStateManager.disableDepth(); + } } } } Minecraft.getMinecraft().renderEngine.bindTexture(texture); - // Fixes the bug that caused the slot hightlight to render opaque. I don't know why it works, it just works! + // Fixes the bug that caused the slot highlight to render opaque. I don't know why it works, it just works! GlStateManager.disableBlend(); GlStateManager.enableAlpha(); } @@ -157,64 +290,86 @@ public class GuiArcaneWorkbench extends GuiContainer { @Override protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){ + GlStateManager.color(1, 1, 1, 1); // Just in case + this.fontRenderer .drawString(this.arcaneWorkbenchInventory.hasCustomName() ? this.arcaneWorkbenchInventory.getName() : I18n.format(this.arcaneWorkbenchInventory.getName()), 8, 6, 4210752); this.fontRenderer.drawString(this.playerInventory.hasCustomName() ? this.playerInventory.getName() : I18n.format(this.playerInventory.getName()), 8, this.ySize - 96 + 2, 4210752); - if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots - .getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){ + if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){ - ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack(); + ItemStack stack = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack(); - this.fontRenderer.drawStringWithShadow("\u00A7f" + wand.getDisplayName(), xSizeNoTip + 6, 6, 0); - this.fontRenderer.drawStringWithShadow( - "\u00A77" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.mana") + " " - + (wand.getMaxDamage() - wand.getItemDamage()) + "/" + wand.getMaxDamage(), - xSizeNoTip + 6, 20, 0); - - Spell[] spells = WandHelper.getSpells(wand); - - int y = 34; - - for(Spell spell : spells){ - - boolean discovered = true; - - if(!this.mc.player.capabilities.isCreativeMode && WizardData.get(this.mc.player) != null){ - discovered = WizardData.get(this.mc.player).hasSpellBeenDiscovered(spell); - } - - if(discovered){ - this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), xSizeNoTip + 16, y, 0); - }else{ - this.mc.standardGalacticFontRenderer.drawStringWithShadow( - "\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), xSizeNoTip + 16, y, 0); - } - y += 10; + if(!(stack.getItem() instanceof IWorkbenchItem)){ + Wizardry.logger.warn("Invalid item in central slot of arcane workbench, how did that get there?!"); + return; } - if(WandHelper.getTotalUpgrades(wand) > 0){ + if(((IWorkbenchItem)stack.getItem()).showTooltip(stack)){ - this.fontRenderer.drawStringWithShadow( - "\u00A7f" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.upgrades"), xSizeNoTip + 6, y + 6, 0); + int y = 6; - int x = 0; - y = 50 + spells.length * 10; - // Wand upgrade tooltips - for(Item item : WandHelper.getSpecialUpgrades()){ + this.fontRenderer.drawStringWithShadow("\u00A7f" + stack.getDisplayName(), MAIN_GUI_WIDTH + 6, y, 0); - int level = WandHelper.getUpgradeLevel(wand, item); + if(stack.getItem() instanceof IManaStoringItem && ((IManaStoringItem)stack.getItem()).showManaInWorkbench(this.mc.player, stack)){ + y += 14; + this.fontRenderer.drawStringWithShadow( + "\u00A77" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.mana") + + " " + ((IManaStoringItem)stack.getItem()).getMana(stack) + "/" + + ((IManaStoringItem)stack.getItem()).getManaCapacity(stack), + MAIN_GUI_WIDTH + 6, y, 0); + } - if(level > 0){ - // The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is - // relative to the GUI but the POINT isn't. - if(isPointInRegion(xSizeNoTip + 6 + x, y, 16, 16, mouseX, mouseY)){ - ItemStack stack = new ItemStack(item, level); - this.renderToolTip(stack, mouseX - guiLeft, mouseY - guiTop); + y += 14; + + if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).showSpellsInWorkbench(this.mc.player, stack)){ + + Spell[] spells = ((ISpellCastingItem)stack.getItem()).getSpells(stack); + + for(Spell spell : spells){ + + boolean discovered = true; + + if(!this.mc.player.isCreative() && WizardData.get(this.mc.player) != null){ + discovered = WizardData.get(this.mc.player).hasSpellBeenDiscovered(spell); + } + + if(discovered){ + this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + 16, y, 0); + }else{ + this.mc.standardGalacticFontRenderer.drawStringWithShadow( + "\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), MAIN_GUI_WIDTH + 16, y, 0); + } + y += 10; + } + } + + if(WandHelper.getTotalUpgrades(stack) > 0){ + + y += 6; + + this.fontRenderer.drawStringWithShadow("\u00A7f" + I18n.format("container." + + Wizardry.MODID + ":arcane_workbench.upgrades"), MAIN_GUI_WIDTH + 6, y, 0); + + int x = 0; + y += 10; + + // Wand upgrade tooltips + for(Item item : WandHelper.getSpecialUpgrades()){ + + int level = WandHelper.getUpgradeLevel(stack, item); + + if(level > 0){ + // The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is + // relative to the GUI but the POINT isn't. + if(isPointInRegion(MAIN_GUI_WIDTH + 6 + x, y, 16, 16, mouseX, mouseY)){ + ItemStack stack1 = new ItemStack(item, level); + this.renderToolTip(stack1, mouseX - guiLeft, mouseY - guiTop); + } + x += 18; } - x += 18; } } } @@ -228,7 +383,7 @@ public class GuiArcaneWorkbench extends GuiContainer { this.guiTop = (this.height - this.ySize) / 2; Keyboard.enableRepeatEvents(true); this.buttonList.clear(); - this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 48, this.height / 2 + 3)); + this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3)); } @Override @@ -244,8 +399,51 @@ public class GuiArcaneWorkbench extends GuiContainer { // Packet building IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.APPLY_BUTTON); WizardryPacketHandler.net.sendToServer(msg); + // Sound + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord( + WizardrySounds.BLOCK_ARCANE_WORKBENCH_SPELLBIND, 1)); + // Animation + animationTimer = 20; } } } + private class GuiButtonApply extends GuiButton { + + public GuiButtonApply(int id, int x, int y){ + super(id, x, y, 16, 16, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.apply")); + } + + @Override + public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){ + + // Whether the button is highlighted + this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; + + int k = 72; + int l = 220; + //int colour = 14737632; + + if(this.enabled){ + if(this.hovered){ + k += this.width * 2; + //colour = 16777120; + } + }else{ + k += this.width; + //colour = 10526880; + } + + DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, 512, 256); + //this.drawCenteredString(minecraft.fontRenderer, this.displayString, this.x + this.width / 2, + // this.y + (this.height - 8) / 2, colour); + } + } + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_CRYSTAL); + event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_UPGRADE); + } + } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java b/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java index a65e71da..7156bb36 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiButtonInvisible.java @@ -2,10 +2,8 @@ package electroblob.wizardry.client.gui; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class GuiButtonInvisible extends GuiButton { public GuiButtonInvisible(int id, int x, int y, int width, int height){ diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiButtonResurrect.java b/src/main/java/electroblob/wizardry/client/gui/GuiButtonResurrect.java new file mode 100644 index 00000000..bf50192c --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/GuiButtonResurrect.java @@ -0,0 +1,90 @@ +package electroblob.wizardry.client.gui; + +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.packet.PacketControlInput; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.spell.Resurrection; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiGameOver; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.relauncher.Side; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class GuiButtonResurrect extends GuiButton { + + private static int timeSinceDeath = -1; + + private final String translationKey; + + public GuiButtonResurrect(int id, int x, int y, String translationKey){ + super(id, x, y, I18n.format(translationKey + "_wait", Resurrection.getRemainingWaitTime(timeSinceDeath))); + this.translationKey = translationKey; + } + + @Override + public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks){ + int waitTime = Resurrection.getRemainingWaitTime(timeSinceDeath); + this.enabled = waitTime == 0; + this.displayString = I18n.format(translationKey + (waitTime == 0 ? "_ready" : "_wait"), waitTime); + super.drawButton(mc, mouseX, mouseY, partialTicks); + } + + // Event handlers + + @SubscribeEvent + public static void onClientTickEvent(TickEvent.ClientTickEvent event){ + if(event.phase == TickEvent.Phase.START && timeSinceDeath >= 0) timeSinceDeath++; + } + + @SubscribeEvent + public static void onGuiScreenInitEvent(GuiScreenEvent.InitGuiEvent event){ + + if(event.getGui() instanceof GuiGameOver && ItemArtefact.isArtefactActive(Minecraft.getMinecraft().player, WizardryItems.amulet_resurrection) + && WizardryUtilities.getHotbar(Minecraft.getMinecraft().player).stream().anyMatch(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player))){ + + event.getButtonList().add(new GuiButtonResurrect(event.getButtonList().size(), event.getGui().width / 2 - 100, + event.getGui().height / 4 + 120, "spell." + Spells.resurrection.getRegistryName() + ".button")); + timeSinceDeath = 0; + } + } + + @SubscribeEvent + public static void onGuiScreenActionPerformedEvent(GuiScreenEvent.ActionPerformedEvent event){ + + if(event.getGui() instanceof GuiGameOver){ + + ItemStack stack = WizardryUtilities.getHotbar(Minecraft.getMinecraft().player).stream() + .filter(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player)).findFirst().orElse(null); + + if(stack != null){ + + if(event.getButton() instanceof GuiButtonResurrect && timeSinceDeath >= 0){ + // Cast resurrection on the client player and notify the server to do the same + // ISpellCastingItem#canCast already checked in Resurrection#canStackResurrect + ((ISpellCastingItem)stack.getItem()).cast(stack, Spells.resurrection, Minecraft.getMinecraft().player, EnumHand.MAIN_HAND, 0, new SpellModifiers()); + WizardryPacketHandler.net.sendToServer(new PacketControlInput.Message(PacketControlInput.ControlType.RESURRECT_BUTTON)); + + }else if(!Minecraft.getMinecraft().world.getGameRules().getBoolean("keepInventory")){ + // Any other button drops the wand (N.B. this should be inside the stack != null check or it'll send + // packets unnecessarily and generate incorrect warnings + WizardryPacketHandler.net.sendToServer(new PacketControlInput.Message(PacketControlInput.ControlType.CANCEL_RESURRECT)); + } + + timeSinceDeath = -1; + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java index 0b2bb487..306abffb 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellBook.java @@ -1,25 +1,34 @@ package electroblob.wizardry.client.gui; -import org.lwjgl.input.Keyboard; - -import electroblob.wizardry.SpellGlyphData; -import electroblob.wizardry.WizardData; +import com.google.common.collect.ImmutableMap; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.SpellGlyphData; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; + +import java.util.Map; public class GuiSpellBook extends GuiScreen { private int xSize, ySize; private Spell spell; - private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/spellbook.png"); + private static final Map textures = ImmutableMap.of( + Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"), + Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"), + Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"), + Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png")); public GuiSpellBook(Spell spell){ super(); @@ -39,45 +48,47 @@ public class GuiSpellBook extends GuiScreen { EntityPlayer player = Minecraft.getMinecraft().player; boolean discovered = true; - if(Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null + if(Wizardry.settings.discoveryMode && !player.isCreative() && WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){ discovered = false; } + GlStateManager.color(1, 1, 1, 1); // Just in case + // Draws spell illustration on opposite page, underneath the book so it shows through the hole. Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon()); DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128); - Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.tier)); + Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.getTier())); DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256); super.drawScreen(par1, par2, par3); if(discovered){ this.fontRenderer.drawString(spell.getDisplayName(), xPos + 17, yPos + 15, 0); - this.fontRenderer.drawString(spell.type.getDisplayName(), xPos + 17, yPos + 26, 0x777777); + this.fontRenderer.drawString(spell.getType().getDisplayName(), xPos + 17, yPos + 26, 0x777777); }else{ this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(spell, player.world), xPos + 17, yPos + 15, 0); - this.mc.standardGalacticFontRenderer.drawString(spell.type.getDisplayName(), xPos + 17, yPos + 26, + this.mc.standardGalacticFontRenderer.drawString(spell.getType().getDisplayName(), xPos + 17, yPos + 26, 0x777777); } - this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0); + //this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0); - if(spell.tier == Tier.BASIC){ + if(spell.getTier() == Tier.NOVICE){ // Basic is usually white but this doesn't show up. - this.fontRenderer.drawString("Tier: \u00A77" + Tier.BASIC.getDisplayName(), xPos + 17, yPos + 45, 0); + this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0); }else{ - this.fontRenderer.drawString("Tier: " + spell.tier.getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0); + this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0); } - String element = "Element: " + spell.element.getFormattingCode() + spell.element.getDisplayName(); + String element = "Element: " + spell.getElement().getFormattingCode() + spell.getElement().getDisplayName(); if(!discovered) element = "Element: ?"; this.fontRenderer.drawString(element, xPos + 17, yPos + 57, 0); - String manaCost = "Mana Cost: " + spell.cost; - if(spell.isContinuous) manaCost = "Mana Cost: " + spell.cost + "/second"; + String manaCost = "Mana Cost: " + spell.getCost(); + if(spell.isContinuous) manaCost = "Mana Cost: " + spell.getCost() + "/second"; if(!discovered) manaCost = "Mana Cost: ?"; this.fontRenderer.drawString(manaCost, xPos + 17, yPos + 69, 0); @@ -93,10 +104,18 @@ public class GuiSpellBook extends GuiScreen { super.initGui(); Keyboard.enableRepeatEvents(true); this.buttonList.clear(); + + this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1)); } public void onGuiClosed(){ super.onGuiClosed(); Keyboard.enableRepeatEvents(false); } + + @Override + public boolean doesGuiPauseGame(){ + return Wizardry.settings.booksPauseGame; + } + } diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java index 6d2a0c6d..85e2aa61 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java +++ b/src/main/java/electroblob/wizardry/client/gui/GuiSpellDisplay.java @@ -1,30 +1,17 @@ package electroblob.wizardry.client.gui; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; - import electroblob.wizardry.Settings; -import electroblob.wizardry.SpellGlyphData; -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.ClientProxy; import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.client.MixedFontRenderer; -import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.data.SpellGlyphData; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.registry.Spells; -import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.WandHelper; @@ -37,14 +24,22 @@ import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResourceManager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHandSide; import net.minecraft.util.JsonUtils; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.*; +import java.util.Map.Entry; + @Mod.EventBusSubscriber(Side.CLIENT) public class GuiSpellDisplay { @@ -53,8 +48,9 @@ public class GuiSpellDisplay { /** A map which stores all loaded HUD skin objects. This gets wiped on resource pack reload and repopulated with * mappings as specified by {@code _index.json} (these stack between resource packs). The keys in the map correspond * to the keys in {@code _index.json}, and are sorted in that order, with skins belonging to resource packs sorted - * from lowest to highest priority. The skins in the base mod will therefore always be first. */ - private static final Map skins = new LinkedHashMap<>(12); // 12 is the number of skins packaged with the mod + * from lowest to highest priority. The skins in the base mod will therefore always be first. (It should be noted, + * however, that in the gui itself the skins are always sorted in alphabetical order for some reason.) */ + private static final Map skins = new LinkedHashMap<>(14); // 14 is the number of skins packaged with the mod private static final Gson gson = new Gson(); @@ -66,6 +62,9 @@ public class GuiSpellDisplay { private static final float SPELL_NAME_SCALE = 0.5f; /** Opacity of the next/previous spell names, as a fraction. */ private static final float SPELL_NAME_OPACITY = 0.3f; + + private static final int HALF_HOTBAR_WIDTH = 97; // Half the width of the hotbar, plus a bit for clearance + private static final int OFFHAND_SLOT_WIDTH = 29; // Width of the offhand slot plus the gap between it and the hotbar /** Controls the spell switching animation. Positive when switching to the next spell, negative when switching to * the previous spell. Decremented in magnitude by 1 each tick until it reaches 0 again. */ @@ -103,14 +102,18 @@ public class GuiSpellDisplay { EntityPlayer player = mc.player; + if(player.isSpectator()) return; // Spectators shouldn't have the spell HUD! + // If the player has a wand in each hand, only displays for the one in the main hand. ItemStack wand = player.getHeldItemMainhand(); + boolean mainHand = true; - if(!(wand.getItem() instanceof ItemWand)){ + if(!(wand.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)wand.getItem()).showSpellHUD(player, wand))){ wand = player.getHeldItemOffhand(); - // If the player isn't holding a wand, then nothing else needs to be done. - if(!(wand.getItem() instanceof ItemWand)) return; + mainHand = false; + // If the player isn't holding a spellcasting item that shows the HUD, then nothing else needs to be done. + if(!(wand.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)wand.getItem()).showSpellHUD(player, wand))) return; } int width = event.getResolution().getScaledWidth(); @@ -118,6 +121,11 @@ public class GuiSpellDisplay { boolean flipX = Wizardry.settings.spellHUDPosition.flipX; boolean flipY = Wizardry.settings.spellHUDPosition.flipY; + + if(Wizardry.settings.spellHUDPosition.dynamic){ + // ............. | This bit is true if the wand is on the left, false if it is on the right + flipX = flipX == ((mainHand ? player.getPrimaryHand() : player.getPrimaryHand().opposite()) == EnumHandSide.LEFT); + } Skin skin = skins.get(Wizardry.settings.spellHUDSkin); @@ -134,13 +142,32 @@ public class GuiSpellDisplay { return; } } + + GlStateManager.pushMatrix(); // 'Origin' of the spell hud (bottom left corner of the actual texture, always in the corner of the screen) int x = flipX ? width : 0; int y = flipY ? 0: height; + // The space available to render the spell HUD + float xSpace = (float)(width/2 - HALF_HOTBAR_WIDTH); + if(!player.getHeldItemOffhand().isEmpty() + // Tests whether the offhand slot is rendered on the same side of the hotbar as the spell HUD + && (player.getPrimaryHand() == EnumHandSide.LEFT) == flipX){ + xSpace -= OFFHAND_SLOT_WIDTH; + } + + // If the skin is at the bottom and the screen width is too small, scale it to avoid the hotbar and offhand + if(!flipY && skin.getWidth() > xSpace){ // width/2 - 91 - 29 taken from GuiInGame line 547 + float scale = xSpace / skin.getWidth(); + GlStateManager.scale(scale, scale, 1); + x = MathHelper.ceil(x/scale); + y = MathHelper.ceil(y/scale); + } + Spell spell = WandHelper.getCurrentSpell(wand); int cooldown = WandHelper.getCurrentCooldown(wand); + int maxCooldown = WandHelper.getCurrentMaxCooldown(wand); if(event.getType() == RenderGameOverlayEvent.ElementType.TEXT){ @@ -155,16 +182,9 @@ public class GuiSpellDisplay { }else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){ - float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(wand, WizardryItems.cooldown_upgrade) * Constants.COOLDOWN_REDUCTION_PER_LEVEL; - - if(player.isPotionActive(WizardryPotions.font_of_mana)){ - // Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously - cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier(); - } - boolean discovered = true; - if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){ + if(!player.isCreative() && WizardData.get(player) != null){ discovered = WizardData.get(player).hasSpellBeenDiscovered(spell); } @@ -172,31 +192,23 @@ public class GuiSpellDisplay { float progress = 1; // Doesn't really matter what progress is when in creative, but we might as well avoid the calculation. - if(!player.capabilities.isCreativeMode && !spell.isContinuous){ + if(!player.isCreative() && !spell.isContinuous){ // Subtracted partial tick time to make it smoother - progress = (spell.cooldown * cooldownMultiplier - (float)cooldown + event.getPartialTicks()) - /(spell.cooldown * cooldownMultiplier); + progress = maxCooldown == 0 ? 1 : (maxCooldown - (float)cooldown + event.getPartialTicks()) / maxCooldown; } - skin.drawBackground(x, y, flipX, flipY, icon, progress, player.capabilities.isCreativeMode); + skin.drawBackground(x, y, flipX, flipY, icon, progress, player.isCreative()); } + + GlStateManager.popMatrix(); } /** - * Makes the given opaque colour translucent with the given opacity. - * @param colour An integer colour code, should be a 6-digit hexadecimal (i.e. opaque). - * @param opacity The opacity to apply to the given colour, as a fraction between 0 and 1. - * @return The resulting integer colour code, which will be an 8-digit hexadecimal. - */ - private static int makeTranslucent(int colour, float opacity){ - return colour + ((int)(0xff * opacity * 0x01000000)); - } - - /** Gets the name of the given spell, with formatted added according to its cooldown and whether the given player + * Gets the name of the given spell, with formatting added according to its cooldown and whether the given player * has discovered it. * @param spell The spell to get the name of. - * @param The player to test for having discovered the given spell. + * @param player The player to test for having discovered the given spell. * @param cooldown The spell's current cooldown. * @return The spell name, with relevant formatting added, for use with the {@link MixedFontRenderer}. */ @@ -204,12 +216,12 @@ public class GuiSpellDisplay { boolean discovered = true; - if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){ + if(!player.isCreative() && WizardData.get(player) != null){ discovered = WizardData.get(player).hasSpellBeenDiscovered(spell); } // Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect - String format = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.element.getFormattingCode(); + String format = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.getElement().getFormattingCode(); if(!discovered) format = "\u00A79"; String name = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.world); @@ -274,10 +286,15 @@ public class GuiSpellDisplay { } } - /** Instances of this class represent individual HUD skins, complete with texture and all necessary metadata. This + /** + * Instances of this class represent individual HUD skins, complete with texture and all necessary metadata. This * class serves to separate the logic behind the spell HUD from its actual rendering. * All information and processing done within this class relates only to the actual drawing; spells and such like - * must be queried outside of this class and fed into the methods as appropriate. */ + * must be queried outside of this class and fed into the methods as appropriate. + * + * @author Electroblob + * @since Wizardry 4.2 + */ public static class Skin { /** The texture file for this skin. */ diff --git a/src/main/java/electroblob/wizardry/client/EntityNameEntry.java b/src/main/java/electroblob/wizardry/client/gui/config/EntityNameEntry.java similarity index 90% rename from src/main/java/electroblob/wizardry/client/EntityNameEntry.java rename to src/main/java/electroblob/wizardry/client/gui/config/EntityNameEntry.java index e6b647f5..483c23cb 100644 --- a/src/main/java/electroblob/wizardry/client/EntityNameEntry.java +++ b/src/main/java/electroblob/wizardry/client/gui/config/EntityNameEntry.java @@ -1,21 +1,17 @@ -package electroblob.wizardry.client; - -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; +package electroblob.wizardry.client.gui.config; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.I18n; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.client.config.GuiButtonExt; -import net.minecraftforge.fml.client.config.GuiEditArray; -import net.minecraftforge.fml.client.config.GuiEditArrayEntries; +import net.minecraftforge.fml.client.config.*; import net.minecraftforge.fml.client.config.GuiEditArrayEntries.StringEntry; -import net.minecraftforge.fml.client.config.GuiSelectString; -import net.minecraftforge.fml.client.config.IConfigElement; import net.minecraftforge.fml.common.registry.EntityEntry; import net.minecraftforge.fml.common.registry.ForgeRegistries; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + /** * [NYI] Intended as a way of choosing entities by name from all those currently registered, within the config file, so * that users don't have to look up the entity IDs. I can't get this to work correctly at the moment. diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiConfigWizardry.java b/src/main/java/electroblob/wizardry/client/gui/config/GuiConfigWizardry.java similarity index 90% rename from src/main/java/electroblob/wizardry/client/gui/GuiConfigWizardry.java rename to src/main/java/electroblob/wizardry/client/gui/config/GuiConfigWizardry.java index 7e7fc01e..7f76ad1d 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiConfigWizardry.java +++ b/src/main/java/electroblob/wizardry/client/gui/config/GuiConfigWizardry.java @@ -1,7 +1,4 @@ -package electroblob.wizardry.client.gui; - -import java.util.ArrayList; -import java.util.List; +package electroblob.wizardry.client.gui.config; import electroblob.wizardry.Settings; import electroblob.wizardry.Wizardry; @@ -15,6 +12,9 @@ import net.minecraftforge.fml.client.config.GuiConfigEntries; import net.minecraftforge.fml.client.config.GuiConfigEntries.CategoryEntry; import net.minecraftforge.fml.client.config.IConfigElement; +import java.util.ArrayList; +import java.util.List; + public class GuiConfigWizardry extends GuiConfig { public GuiConfigWizardry(GuiScreen parent){ @@ -33,7 +33,8 @@ public class GuiConfigWizardry extends GuiConfig { configList.add(new DummyCategoryElement("clientConfig", "config." + Wizardry.MODID + ".category." + Settings.CLIENT_CATEGORY, ClientCategory.class)); configList.add(new DummyCategoryElement("spellsConfig", "config." + Wizardry.MODID + ".category." + Settings.SPELLS_CATEGORY, SpellsCategory.class)); configList.add(new DummyCategoryElement("resistancesConfig", "config." + Wizardry.MODID + ".category." + Settings.RESISTANCES_CATEGORY, ResistancesCategory.class)); - + configList.add(new DummyCategoryElement("compatibilityConfig", "config." + Wizardry.MODID + ".category." + Settings.COMPATIBILITY_CATEGORY, CompatibilityCategory.class)); + configList.addAll(new ConfigElement(Wizardry.settings.getConfigCategory(Configuration.CATEGORY_GENERAL)).getChildElements()); return configList; @@ -41,7 +42,7 @@ public class GuiConfigWizardry extends GuiConfig { // The reason this system is so convoluted is that it's designed for use with the @Config annotation. The problem is, // I'm not sure whether that will play well with the load phases. Hmmm... - + public static abstract class CategoryBase extends CategoryEntry { public CategoryBase(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ @@ -77,6 +78,36 @@ public class GuiConfigWizardry extends GuiConfig { @Override protected String getCategory() { return Settings.GAMEPLAY_CATEGORY; } } + + /** Worldgen category of the config gui. */ + public static class WorldgenCategory extends CategoryBase { + + public WorldgenCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ + super(owningScreen, owningEntryList, prop); + } + + @Override protected String getCategory() { return Settings.WORLDGEN_CATEGORY; } + } + + /** Commands category of the config gui. */ + public static class CommandsCategory extends CategoryBase { + + public CommandsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ + super(owningScreen, owningEntryList, prop); + } + + @Override protected String getCategory() { return Settings.COMMANDS_CATEGORY; } + } + + /** Client category of the config gui. */ + public static class ClientCategory extends CategoryBase { + + public ClientCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ + super(owningScreen, owningEntryList, prop); + } + + @Override protected String getCategory() { return Settings.CLIENT_CATEGORY; } + } /** Spells category of the config gui. */ public static class SpellsCategory extends CategoryBase { @@ -97,34 +128,14 @@ public class GuiConfigWizardry extends GuiConfig { @Override protected String getCategory() { return Settings.RESISTANCES_CATEGORY; } } - - /** Worldgen category of the config gui. */ - public static class WorldgenCategory extends CategoryBase { - - public WorldgenCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ - super(owningScreen, owningEntryList, prop); - } - - @Override protected String getCategory() { return Settings.WORLDGEN_CATEGORY; } - } - - /** Client category of the config gui. */ - public static class ClientCategory extends CategoryBase { - - public ClientCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ - super(owningScreen, owningEntryList, prop); - } - - @Override protected String getCategory() { return Settings.CLIENT_CATEGORY; } - } - + /** Commands category of the config gui. */ - public static class CommandsCategory extends CategoryBase { - - public CommandsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ + public static class CompatibilityCategory extends CategoryBase { + + public CompatibilityCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ super(owningScreen, owningEntryList, prop); } - - @Override protected String getCategory() { return Settings.COMMANDS_CATEGORY; } + + @Override protected String getCategory() { return Settings.COMPATIBILITY_CATEGORY; } } } diff --git a/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java b/src/main/java/electroblob/wizardry/client/gui/config/GuiSelectHUDSkin.java similarity index 95% rename from src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java rename to src/main/java/electroblob/wizardry/client/gui/config/GuiSelectHUDSkin.java index 92a1fbe8..985d1594 100644 --- a/src/main/java/electroblob/wizardry/client/gui/GuiSelectHUDSkin.java +++ b/src/main/java/electroblob/wizardry/client/gui/config/GuiSelectHUDSkin.java @@ -1,12 +1,8 @@ -package electroblob.wizardry.client.gui; - -import java.util.Map; - -import javax.annotation.Nullable; +package electroblob.wizardry.client.gui.config; import com.google.common.collect.Lists; - import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.gui.GuiSpellDisplay; import electroblob.wizardry.client.gui.GuiSpellDisplay.Skin; import electroblob.wizardry.registry.Spells; import net.minecraft.client.gui.GuiButton; @@ -16,6 +12,9 @@ import net.minecraft.client.resources.I18n; import net.minecraftforge.fml.client.config.GuiSelectString; import net.minecraftforge.fml.client.config.IConfigElement; +import javax.annotation.Nullable; +import java.util.Map; + public class GuiSelectHUDSkin extends GuiSelectString { public GuiSelectHUDSkin(GuiScreen parentScreen, IConfigElement configElement, int slotIndex, Map selectableValues, Object currentValue, boolean enabled){ @@ -50,7 +49,7 @@ public class GuiSelectHUDSkin extends GuiSelectString { if(this.currentValue instanceof String){ - this.drawString(this.fontRenderer, I18n.format("config." + Wizardry.MODID + ":spell_hud_skin.preview"), 170, 44, 0xffffff); + this.drawString(this.fontRenderer, I18n.format("config." + Wizardry.MODID + ".spell_hud_skin.preview"), 170, 44, 0xffffff); int previewLeft = 170; int previewRight = width-10; diff --git a/src/main/java/electroblob/wizardry/client/gui/config/NamedBooleanEntry.java b/src/main/java/electroblob/wizardry/client/gui/config/NamedBooleanEntry.java new file mode 100644 index 00000000..0e9fd5ed --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/config/NamedBooleanEntry.java @@ -0,0 +1,93 @@ +package electroblob.wizardry.client.gui.config; + +import net.minecraft.client.resources.I18n; +import net.minecraftforge.fml.client.config.GuiConfig; +import net.minecraftforge.fml.client.config.GuiConfigEntries; +import net.minecraftforge.fml.client.config.GuiUtils; +import net.minecraftforge.fml.client.config.IConfigElement; + +/** + * Same as {@link net.minecraftforge.fml.client.config.GuiConfigEntries.BooleanEntry}, but instead of simply + * displaying 'true' or 'false', allows the two display strings to be specified in the lang file. + */ +// BooleanEntry's constructors are private, so I had to copy the whole goddamn class to change one method. Thanks Forge. +public class NamedBooleanEntry extends GuiConfigEntries.ButtonEntry { + + protected final boolean beforeValue; + protected boolean currentValue; + + private static final String DEFAULT_KEY = "config.ebwizardry.generic"; + + public NamedBooleanEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement configElement){ + super(owningScreen, owningEntryList, configElement); + this.beforeValue = Boolean.valueOf(configElement.get().toString()); + this.currentValue = beforeValue; + this.btnValue.enabled = enabled(); + updateValueButtonText(); + } + + // This is the only method that's any different + @Override + public void updateValueButtonText(){ + + String langKey = configElement.getLanguageKey() + "." + currentValue; + this.btnValue.displayString = I18n.format(langKey); + // If the key is unspecified, it defaults to the generic 'Enabled'/'Disabled' keys and adds a red/green colour + if(this.btnValue.displayString.equals(langKey)){ + this.btnValue.displayString = I18n.format(DEFAULT_KEY + "." + currentValue); + btnValue.packedFGColour = currentValue ? GuiUtils.getColorCode('a', true) : GuiUtils.getColorCode('c', true); + } + } + + // Everything from here down is the same as BooleanEntry + + @Override + public void valueButtonPressed(int slotIndex){ + if(enabled()) currentValue = !currentValue; + } + + @Override + public boolean isDefault(){ + return currentValue == Boolean.valueOf(configElement.getDefault().toString()); + } + + @Override + public void setToDefault(){ + if(enabled()){ + currentValue = Boolean.valueOf(configElement.getDefault().toString()); + updateValueButtonText(); + } + } + + @Override + public boolean isChanged(){ + return currentValue != beforeValue; + } + + @Override + public void undoChanges(){ + if(enabled()){ + currentValue = beforeValue; + updateValueButtonText(); + } + } + + @Override + public boolean saveConfigElement(){ + if(enabled() && isChanged()){ + configElement.set(currentValue); + return configElement.requiresMcRestart(); + } + return false; + } + + @Override + public Boolean getCurrentValue(){ + return currentValue; + } + + @Override + public Boolean[] getCurrentValues(){ + return new Boolean[]{getCurrentValue()}; + } +} diff --git a/src/main/java/electroblob/wizardry/client/SpellHUDSkinChooserEntry.java b/src/main/java/electroblob/wizardry/client/gui/config/SpellHUDSkinChooserEntry.java similarity index 85% rename from src/main/java/electroblob/wizardry/client/SpellHUDSkinChooserEntry.java rename to src/main/java/electroblob/wizardry/client/gui/config/SpellHUDSkinChooserEntry.java index a6872673..e2ddb3ed 100644 --- a/src/main/java/electroblob/wizardry/client/SpellHUDSkinChooserEntry.java +++ b/src/main/java/electroblob/wizardry/client/gui/config/SpellHUDSkinChooserEntry.java @@ -1,10 +1,5 @@ -package electroblob.wizardry.client; +package electroblob.wizardry.client.gui.config; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; - -import electroblob.wizardry.client.gui.GuiSelectHUDSkin; import electroblob.wizardry.client.gui.GuiSpellDisplay; import net.minecraftforge.client.gui.ForgeGuiFactory.ForgeConfigGui.ModIDEntry; import net.minecraftforge.fml.client.config.GuiConfig; @@ -12,17 +7,19 @@ import net.minecraftforge.fml.client.config.GuiConfigEntries; import net.minecraftforge.fml.client.config.GuiConfigEntries.SelectValueEntry; import net.minecraftforge.fml.client.config.IConfigElement; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + /** * Custom config GUI for spell HUD skin selection; displays a list of all the loaded skins and a preview of the currently * selected skin. based off of {@link ModIDEntry} from Forge. */ public class SpellHUDSkinChooserEntry extends SelectValueEntry { - public SpellHUDSkinChooserEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop) - { + public SpellHUDSkinChooserEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){ super(owningScreen, owningEntryList, prop, getSelectableValues()); - if (this.selectableValues.size() == 0) - this.btnValue.enabled = false; + if(this.selectableValues.size() == 0) this.btnValue.enabled = false; } private static Map getSelectableValues(){ diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/Contents.java b/src/main/java/electroblob/wizardry/client/gui/handbook/Contents.java index 2ef67821..1853e5a1 100644 --- a/src/main/java/electroblob/wizardry/client/gui/handbook/Contents.java +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/Contents.java @@ -27,6 +27,7 @@ class Contents { // Final fields are mandatory, the rest are optional final String id; + final Section section; private boolean hyperlinks = true; private boolean pageNumbers = true; private String separator = "."; @@ -37,10 +38,14 @@ class Contents { private final List
    entries; - private Contents(String id){ + private List
    visibleEntries; + + private Contents(String id, Section section){ this.id = id; + this.section = section; this.entries = new ArrayList<>(); this.buttons = new ArrayList<>(); + this.visibleEntries = new ArrayList<>(); } /** Returns an unmodifiable, flattened collection of all the buttons in this contents. */ @@ -83,26 +88,29 @@ class Contents { for(int page : visiblePages){ - if(page >= 0 && page < entries.size() / maxLineNumber + 1){ + if(page >= 0 && page < visibleEntries.size() / maxLineNumber + 1){ int x = left + (GuiWizardHandbook.isRightPage(startPage + page) ? GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : GuiWizardHandbook.TEXT_INSET_X); int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT; - for(Section entry : this.entries){ + for(Section entry : this.visibleEntries){ - int nameWidth = font.getStringWidth(entry.title); + if(entry.isUnlocked()){ - String dotsAndNumber = " " + entry.startPage; + int nameWidth = font.getStringWidth(entry.title); - while(font.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - nameWidth - 2){ - dotsAndNumber = separator + dotsAndNumber; + String dotsAndNumber = " " + entry.startPage; + + while(font.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - nameWidth - 2){ + dotsAndNumber = separator + dotsAndNumber; + } + + font.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - font.getStringWidth(dotsAndNumber), y, DrawingUtils.BLACK, false); + + if(!hyperlinks) font.drawString(entry.title, x, y, DrawingUtils.BLACK, false); + + y += font.FONT_HEIGHT; } - - font.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - font.getStringWidth(dotsAndNumber), y, DrawingUtils.BLACK, false); - - if(!hyperlinks) font.drawString(entry.title, x, y, DrawingUtils.BLACK, false); - - y += font.FONT_HEIGHT; } } } @@ -124,6 +132,10 @@ class Contents { this.buttons.clear(); + this.visibleEntries = new ArrayList<>(entries); // Need to copy the collection first! + + this.visibleEntries.removeIf(s -> !s.isUnlocked()); + if(hyperlinks){ // FONT_HEIGHT may change between fonts, so this is calculated here. With the default font it's 14. @@ -134,12 +146,12 @@ class Contents { List list = new ArrayList<>(maxLineNumber); - for(Section entry : this.entries){ + for(Section entry : this.visibleEntries){ int x = GuiWizardHandbook.isRightPage(startPage) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X; int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT; - list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, "")); + list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, "", maxLineNumber-startLine, GuiWizardHandbook.isRightPage(startPage))); startLine++; @@ -156,21 +168,22 @@ class Contents { // Returning this is kind of trivial at the moment but if we ever wanted to add a header or something, // it would be more useful. - return entries.size(); + return visibleEntries.size(); } /** * Parses the given JSON object and constructs a new {@code Contents} from it, setting all the relevant fields * and references. * + * @param parent The parent section for this contents. * @param json A JSON object representing the contents to be constructed. This must contain at least an "id" * string. * @return The resulting {@code Contents} object. * @throws JsonSyntaxException if at any point the JSON object is found to be invalid. */ - static Contents fromJson(JsonObject json){ + static Contents fromJson(Section parent, JsonObject json){ - Contents contents = new Contents(JsonUtils.getString(json, "id")); + Contents contents = new Contents(JsonUtils.getString(json, "id"), parent); contents.hyperlinks = JsonUtils.getBoolean(json, "hyperlinks", true); contents.pageNumbers = JsonUtils.getBoolean(json, "page_numbers", true); diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/CraftingRecipe.java b/src/main/java/electroblob/wizardry/client/gui/handbook/CraftingRecipe.java index ecaf5105..a7b32212 100644 --- a/src/main/java/electroblob/wizardry/client/gui/handbook/CraftingRecipe.java +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/CraftingRecipe.java @@ -1,43 +1,38 @@ package electroblob.wizardry.client.gui.handbook; +import com.google.common.collect.Streams; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; import electroblob.wizardry.client.DrawingUtils; -import electroblob.wizardry.spell.Mine; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.recipebook.GuiRecipeBook; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.Ingredient; -import net.minecraft.stats.RecipeBook; import net.minecraft.util.JsonUtils; -import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; class CraftingRecipe { - static final int WIDTH = 111, HEIGHT = 56; + static final int BORDER = 7; + static final int TEXTURE_INSET_X = 40, TEXTURE_INSET_Y = 190; + static final int WIDTH = 121, HEIGHT = 66; // Final fields are mandatory, the rest are optional - private final ResourceLocation location; + private final ResourceLocation[] locations; // Derived fields, not specifically defined in JSON - private IRecipe recipe; + private List recipes; private final Set instances = new HashSet<>(); - private CraftingRecipe(ResourceLocation location){ - this.location = location; + private CraftingRecipe(ResourceLocation[] locations){ + this.locations = locations; } /** @@ -60,9 +55,14 @@ class CraftingRecipe { * the recipes aren't necessarily loaded at that point. */ void load(){ - this.recipe = CraftingManager.getRecipe(location); + recipes = new ArrayList<>(locations.length); - if(recipe == null) throw new JsonSyntaxException("No such recipe: " + location); + for(ResourceLocation location : locations){ + + IRecipe recipe = CraftingManager.getRecipe(location); + if(recipe == null) throw new JsonSyntaxException("No such recipe: " + location); + recipes.add(recipe); + } } /** @@ -75,9 +75,12 @@ class CraftingRecipe { * @param top The y coordinate of the top of the GUI. */ void draw(FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top){ + + int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000; + for(int[] instance : instances){ if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){ - renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], this.recipe); + renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], recipes.get(index % recipes.size())); } } } @@ -92,9 +95,12 @@ class CraftingRecipe { * @param top The y coordinate of the top of the GUI. */ void drawTooltips(GuiWizardHandbook gui, FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top, int mouseX, int mouseY){ + + int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000; + for(int[] instance : instances){ if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){ - renderCraftingTooltips(gui, itemRenderer, left + instance[1], top + instance[2], mouseX, mouseY, this.recipe); + renderCraftingTooltips(gui, itemRenderer, left + instance[1], top + instance[2], mouseX, mouseY, recipes.get(index % recipes.size())); } } } @@ -103,15 +109,16 @@ class CraftingRecipe { * Parses the given JSON object and constructs a new {@code Image} from it, setting all the relevant fields * and references. * - * @param json A JSON object representing the image to be constructed. This must contain at least a "location" + * @param json A JSON object representing the image to be constructed. This must contain at least a "locations" * string. * @return The resulting {@code Image} object. * @throws JsonSyntaxException if at any point the JSON object is found to be invalid. */ static CraftingRecipe fromJson(JsonObject json){ - ResourceLocation location = new ResourceLocation(JsonUtils.getString(json, "location")); - return new CraftingRecipe(location); + ResourceLocation[] locations = Streams.stream(JsonUtils.getJsonArray(json, "locations")) + .map(je -> new ResourceLocation(je.getAsString())).toArray(ResourceLocation[]::new); + return new CraftingRecipe(locations); } static void populate(Map map, JsonObject json){ @@ -135,17 +142,15 @@ class CraftingRecipe { GlStateManager.color(1, 1, 1, 1); Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture); - DrawingUtils.drawTexturedRect(x - 2, y - 2, 60, 190, WIDTH, HEIGHT, 512, 256); + DrawingUtils.drawTexturedRect(x, y, TEXTURE_INSET_X, TEXTURE_INSET_Y, WIDTH, HEIGHT, GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT); GlStateManager.pushMatrix(); RenderHelper.enableGUIStandardItemLighting(); GlStateManager.disableLighting(); GlStateManager.enableRescaleNormal(); GlStateManager.enableColorMaterial(); - GlStateManager.enableLighting(); itemRenderer.zLevel = 100.0F; - // TODO: There may be a better way of doing this int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000; int i = 0; @@ -155,8 +160,8 @@ class CraftingRecipe { if(ingredient != Ingredient.EMPTY){ ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length]; if(!stack.isEmpty()){ - itemRenderer.renderItemAndEffectIntoGUI(stack, x + 18 * (i%3), y + 18 * (i/3)); - itemRenderer.renderItemOverlays(font, stack, x + 18 * (i%3), y + 18 * (i/3)); + itemRenderer.renderItemAndEffectIntoGUI(stack, x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3)); + itemRenderer.renderItemOverlays(font, stack, x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3)); } } @@ -164,16 +169,15 @@ class CraftingRecipe { } if(!result.isEmpty()){ - itemRenderer.renderItemAndEffectIntoGUI(result, x + 86, y + 18); - itemRenderer.renderItemOverlays(font, result, x + 86, y + 18); + itemRenderer.renderItemAndEffectIntoGUI(result, x + BORDER + 86, y + BORDER + 18); + itemRenderer.renderItemOverlays(font, result, x + BORDER + 86, y + BORDER + 18); } GlStateManager.popMatrix(); - GlStateManager.enableLighting(); GlStateManager.enableDepth(); GlStateManager.disableColorMaterial(); itemRenderer.zLevel = 0.0F; - //RenderHelper.enableStandardItemLighting(); + RenderHelper.disableStandardItemLighting(); } @@ -187,9 +191,7 @@ class CraftingRecipe { GlStateManager.enableRescaleNormal(); GlStateManager.enableColorMaterial(); itemRenderer.zLevel = 0.0F; - GlStateManager.disableLighting(); - // TODO: There may be a better way of doing this int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000; int i = 0; @@ -198,7 +200,7 @@ class CraftingRecipe { if(ingredient != Ingredient.EMPTY){ ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length]; - if(!stack.isEmpty() && isPointInRegion(x + 18 * (i%3), y + 18 * (i/3), 16, 16, mouseX, mouseY)){ + if(!stack.isEmpty() && isPointInRegion(x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3), 16, 16, mouseX, mouseY)){ gui.renderToolTip(stack, mouseX, mouseY); } } @@ -206,15 +208,14 @@ class CraftingRecipe { i++; } - if(!result.isEmpty() && isPointInRegion(x + 86, y + 18, 16, 16, mouseX, mouseY)){ + if(!result.isEmpty() && isPointInRegion(x + BORDER + 86, y + BORDER + 18, 16, 16, mouseX, mouseY)){ gui.renderToolTip(result, mouseX, mouseY); } GlStateManager.popMatrix(); - GlStateManager.enableLighting(); GlStateManager.enableDepth(); GlStateManager.disableColorMaterial(); - RenderHelper.enableStandardItemLighting(); + RenderHelper.disableStandardItemLighting(); } diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonHyperlink.java b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonHyperlink.java index 7aaa5bf4..d5a48d64 100644 --- a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonHyperlink.java +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonHyperlink.java @@ -1,12 +1,14 @@ package electroblob.wizardry.client.gui.handbook; import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.registry.WizardrySounds; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.audio.SoundHandler; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; @@ -19,10 +21,14 @@ public abstract class GuiButtonHyperlink extends GuiButton { public static final String URL_REGEX = "^((https?|ftp)://|(www|ftp)\\.)?[a-z0-9-]+(\\.[a-z0-9-]+)+([/?].*)?$"; + /** Pulse period of links to new sections, in milliseconds. */ + private static final float PULSATION_PERIOD = 1500; + final int indent; final List lines; + final int linesLeft; - GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix){ + GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix, int linesLeft, boolean rightPage){ super(id, x, y, font.getStringWidth(text), font.FONT_HEIGHT, text); @@ -36,6 +42,7 @@ public abstract class GuiButtonHyperlink extends GuiButton { } this.indent = indent; // Assigned here in case it was corrected above + this.linesLeft = linesLeft; String line1 = font.listFormattedStringToWidth(linkWithSuffix, GuiWizardHandbook.PAGE_WIDTH - indent).get(0); // Without trim(), there will be at least 1 leading space due to the custom wrapping @@ -59,6 +66,11 @@ public abstract class GuiButtonHyperlink extends GuiButton { } } } + + // Remove any lines that overflowed onto the next double-page + if(rightPage){ + while(lines.size() > linesLeft) lines.remove(lines.size() - 1); + } } public boolean isHovered(net.minecraft.client.gui.FontRenderer font, int mouseX, int mouseY){ @@ -72,6 +84,11 @@ public abstract class GuiButtonHyperlink extends GuiButton { int t = y + font.FONT_HEIGHT * i; + if(i > linesLeft){ + l = l + GuiWizardHandbook.GUI_WIDTH - 2 * GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH; + t -= GuiWizardHandbook.PAGE_HEIGHT - (GuiWizardHandbook.PAGE_HEIGHT % font.FONT_HEIGHT); + } + if(mouseX >= l && mouseY >= t && mouseX < l + font.getStringWidth(line) && mouseY < t + font.FONT_HEIGHT){ return true; } @@ -93,7 +110,6 @@ public abstract class GuiButtonHyperlink extends GuiButton { if(this.visible){ this.hovered = isHovered(minecraft.fontRenderer, mouseX, mouseY); - int colour = hovered ? GuiWizardHandbook.colours.get("highlight") : GuiWizardHandbook.colours.get("hyperlink"); int i = 0; @@ -104,13 +120,22 @@ public abstract class GuiButtonHyperlink extends GuiButton { int t = y + minecraft.fontRenderer.FONT_HEIGHT * i; - minecraft.fontRenderer.drawString(line, l, t, colour); + if(i > linesLeft){ + l = l + GuiWizardHandbook.GUI_WIDTH - 2 * GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH; + t -= GuiWizardHandbook.PAGE_HEIGHT - (GuiWizardHandbook.PAGE_HEIGHT % minecraft.fontRenderer.FONT_HEIGHT); + } + + minecraft.fontRenderer.drawString(line, l, t, getColour()); i++; } } } + protected int getColour(){ + return hovered ? GuiWizardHandbook.colours.get("highlight") : GuiWizardHandbook.colours.get("hyperlink"); + } + /** * Creates a new hyperlink button from the given arguments, automatically differentiating between URLs and sections. * @param x The x position of the button @@ -124,7 +149,7 @@ public abstract class GuiButtonHyperlink extends GuiButton { * @throws IllegalArgumentException if the given argument array is empty or contains more than 2 arguments * @throws JsonSyntaxException if the specified link target is not a URL or a valid section ID */ - public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List upToLink, String[] arguments, String suffix){ + public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List upToLink, String[] arguments, String suffix, int linesLeft, boolean rightPage){ if(arguments.length == 0 || arguments.length > 2) throw new IllegalArgumentException("Incorrect array length!"); @@ -133,7 +158,7 @@ public abstract class GuiButtonHyperlink extends GuiButton { if(arguments[0].matches(URL_REGEX)){ button = new GuiButtonHyperlink.External(0, x, y, font, arguments[arguments.length - 1], arguments[0], - font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix); + font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage); }else{ @@ -142,7 +167,7 @@ public abstract class GuiButtonHyperlink extends GuiButton { if(target == null) throw new JsonSyntaxException("Hyperlink points to nonexistent section id " + arguments[0]); button = new GuiButtonHyperlink.Internal(0, x, y, font, arguments[arguments.length - 1], - target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix); + target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage); } return button; @@ -152,26 +177,49 @@ public abstract class GuiButtonHyperlink extends GuiButton { final Section target; - Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix){ - super(id, x, y, font, text, indent, suffix); + Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix, int linesLeft, boolean rightPage){ + super(id, x, y, font, text, indent, suffix, linesLeft, rightPage); this.target = target; } + @Override + public boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY){ + if(!target.isUnlocked()) return false; + return super.mousePressed(minecraft, mouseX, mouseY); + } + @Override public void playPressSound(SoundHandler soundHandler){ soundHandler.playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_PAGE_TURN, 1)); } + @Override + protected int getColour(){ + + if(!target.isUnlocked()) return GuiWizardHandbook.colours.get("text"); + + if(!hovered && target.isNew() && !Minecraft.getMinecraft().player.isCreative()){ + + int c = GuiWizardHandbook.colours.get("new_section"); + int d = GuiWizardHandbook.colours.get("hyperlink"); + float f = (MathHelper.sin((Minecraft.getSystemTime() % PULSATION_PERIOD) / PULSATION_PERIOD * 2 * (float)Math.PI) + 1) / 2f; + + return DrawingUtils.mix(c, d, f); + } + + return super.getColour(); + } + } static class External extends GuiButtonHyperlink { final ITextComponent link; - External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix){ - super(id, x, y, font, text, indent, suffix); + External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix, int linesLeft, boolean rightPage){ + super(id, x, y, font, text, indent, suffix, linesLeft, rightPage); this.link = new TextComponentString(text); - link.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); + link.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)).setColor(TextFormatting.DARK_BLUE); } } diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonTurnPage.java b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonTurnPage.java index a05ed041..662e71a1 100644 --- a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonTurnPage.java +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiButtonTurnPage.java @@ -9,10 +9,8 @@ import net.minecraft.client.audio.SoundHandler; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) class GuiButtonTurnPage extends GuiButton { static final int WIDTH = 20; diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java index 2c21a59f..dcb54387 100644 --- a/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java @@ -3,6 +3,7 @@ package electroblob.wizardry.client.gui.handbook; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.ClientProxy; import electroblob.wizardry.client.DrawingUtils; @@ -11,34 +12,28 @@ import electroblob.wizardry.client.gui.handbook.GuiButtonTurnPage.Type; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.packet.PacketRequestAdvancementSync; +import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.WizardrySounds; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.audio.SoundHandler; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.multiplayer.ClientAdvancementManager; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResourceManager; import net.minecraft.item.ItemStack; import net.minecraft.util.JsonUtils; -import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.event.entity.player.AdvancementEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.relauncher.ReflectionHelper; -import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.input.Keyboard; import java.awt.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.lang.reflect.Field; -import java.util.*; import java.util.List; +import java.util.*; /** * GUI class for the wizard's handbook. Like any GUI class, this is instantiated each time the book is opened. As of @@ -54,7 +49,6 @@ import java.util.List; * @see Image * @see CraftingRecipe */ -@Mod.EventBusSubscriber public class GuiWizardHandbook extends GuiScreen { private static final ResourceLocation DEFAULT = new ResourceLocation(Wizardry.MODID, "texts/handbook_en_us.json"); @@ -71,6 +65,7 @@ public class GuiWizardHandbook extends GuiScreen { static final String IMAGE_TAG = "image"; static final String RECIPE_TAG = "recipe"; + static final String RULER_TAG = "ruler"; static final Map FORMAT_TAGS = new HashMap<>(); @@ -79,6 +74,8 @@ public class GuiWizardHandbook extends GuiScreen { /** The dimensions of the rendered GUI area. */ static final int GUI_WIDTH = 288, GUI_HEIGHT = 180; + /** The dimensions of the GUI texture itself. */ + static final int TEXTURE_WIDTH = 512, TEXTURE_HEIGHT = 256; /** The dimensions of the area of a single page in which text can be drawn. */ static final int PAGE_WIDTH = 120, PAGE_HEIGHT = 140; /** The distance of the text from the top outside corner of each page. */ @@ -107,12 +104,12 @@ public class GuiWizardHandbook extends GuiScreen { * The double-page number where the bookmark is currently set, relative to the section stored in * {@link GuiWizardHandbook#bookmarkSection}. Static because it persists when the book is closed. */ - private static int bookmarkPage = 1; + private static int bookmarkPage = 0; /** - * A reference to the section in which the bookmark is currently set. Static because it persists when the book is - * closed. Storing a section means the bookmark doesn't change location when new sections are unlocked. + * The key corresponding to the section in which the bookmark is currently set. Static because it persists when the + * book is closed. Storing a section means the bookmark doesn't change location when new sections are unlocked. */ - private static Section bookmarkSection; + private static String bookmarkSection; // Buttons private GuiButton bookmark, next, previous, nextSection, previousSection, menu; @@ -164,19 +161,6 @@ public class GuiWizardHandbook extends GuiScreen { */ static final Map recipes = new HashMap<>(); - static String rulerText = "--------------------"; // Assigned here as a fallback - - private static final List>>> RECIPES = new ArrayList<>(); - - // Reflection - - static final Field ADVANCEMENT_TO_PROGRESS; - - static { - // TODO: Obf field name - ADVANCEMENT_TO_PROGRESS = ReflectionHelper.findField(ClientAdvancementManager.class, "advancementToProgress"); - } - /** * Adds a format tag to the handbook. All occurrences of the given tag string preceded by a # will be replaced with * the result of the given value string on GUI load. The value string, therefore, can be anything that should be @@ -193,9 +177,9 @@ public class GuiWizardHandbook extends GuiScreen { addFormatTag("next_spell_key", ClientProxy.NEXT_SPELL.getDisplayName()); addFormatTag("previous_spell_key", ClientProxy.PREVIOUS_SPELL.getDisplayName()); - addFormatTag("mana_per_crystal_minus_30", "" + (Constants.MANA_PER_CRYSTAL - 30)); + addFormatTag("example_charging_loss", "" + (Constants.MANA_PER_CRYSTAL - 30)); addFormatTag("mana_per_crystal", "" + Constants.MANA_PER_CRYSTAL); - addFormatTag("novice_max_charge", "" + Tier.BASIC.maxCharge); + addFormatTag("novice_max_charge", "" + Tier.NOVICE.maxCharge); addFormatTag("apprentice_max_charge", "" + Tier.APPRENTICE.maxCharge); addFormatTag("advanced_max_charge", "" + Tier.ADVANCED.maxCharge); addFormatTag("master_max_charge", "" + Tier.MASTER.maxCharge); @@ -264,12 +248,14 @@ public class GuiWizardHandbook extends GuiScreen { Minecraft.getMinecraft().renderEngine.bindTexture(texture); + GlStateManager.color(1, 1, 1, 1); + // Main background - DrawingUtils.drawTexturedRect(left, top, 0, 0, GUI_WIDTH, GUI_HEIGHT, 512, 256); + DrawingUtils.drawTexturedRect(left, top, 0, 0, GUI_WIDTH, GUI_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT); // First page background if(currentPage == 0){ - DrawingUtils.drawTexturedRect(left, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, 512, 256); + DrawingUtils.drawTexturedRect(left, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT); previous.visible = false; previousSection.visible = false; // Not worth testing if we're in the first section every frame menu.visible = false; @@ -281,7 +267,7 @@ public class GuiWizardHandbook extends GuiScreen { // Last page background if(currentPage == singleToDoublePage(pageCount)){ - DrawingUtils.drawTexturedFlippedRect(left + GUI_WIDTH / 2, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, 512, 256, true, false); + DrawingUtils.drawTexturedFlippedRect(left + GUI_WIDTH / 2, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT, true, false); next.visible = false; nextSection.visible = false; }else{ @@ -302,9 +288,10 @@ public class GuiWizardHandbook extends GuiScreen { } // Main content + contentsList.values().forEach(c -> { if(c.section.isUnlocked()) c.draw(fontRenderer, currentPage, left, top); } ); + sections.values().forEach(s -> { if(s.isUnlocked()) s.draw(fontRenderer, currentPage, left, top); } ); + // These only get populated if the sections are unlocked so no checks are necessary images.values().forEach(i -> i.draw(fontRenderer, currentPage, left, top)); - contentsList.values().forEach(c -> c.draw(fontRenderer, currentPage, left, top)); - sections.values().forEach(s -> s.draw(fontRenderer, currentPage, left, top)); recipes.values().forEach(r -> r.draw(fontRenderer, itemRender, currentPage, left, top)); // Buttons @@ -314,14 +301,15 @@ public class GuiWizardHandbook extends GuiScreen { GlStateManager.color(1, 1, 1, 1); Minecraft.getMinecraft().renderEngine.bindTexture(texture); - if(currentPage == singleToDoublePage(bookmarkSection.startPage) + bookmarkPage){ + if(currentPage == singleToDoublePage(sections.get(bookmarkSection).startPage) + bookmarkPage){ + // If the current page is the bookmarked page, the (invisible) bookmark button is disabled bookmark.visible = false; - DrawingUtils.drawTexturedRect(left + 138, top, 299, 0, 11, 191, 512, 256); + DrawingUtils.drawTexturedRect(left + 138, top, 299, 0, 11, 191, TEXTURE_WIDTH, TEXTURE_HEIGHT); }else{ bookmark.visible = true; - bookmark.x = left + (currentPage > singleToDoublePage(bookmarkSection.startPage) + bookmarkPage ? 130 : 147); + bookmark.x = left + (currentPage > singleToDoublePage(sections.get(bookmarkSection).startPage) + bookmarkPage ? 130 : 147); DrawingUtils.drawTexturedRect(bookmark.x, top, - bookmark.isMouseOver() ? 310 : 288, 0, 11, 191, 512, 256); + bookmark.isMouseOver() ? 310 : 288, 0, 11, 191, TEXTURE_WIDTH, TEXTURE_HEIGHT); } // Recipe tooltips @@ -426,8 +414,6 @@ public class GuiWizardHandbook extends GuiScreen { JsonElement je = gson.fromJson(reader, JsonElement.class); JsonObject json = je.getAsJsonObject(); - rulerText = JsonUtils.getString(json, "ruler_text"); - JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(), Color.decode(e.getValue().getAsString()).getRGB())); @@ -443,10 +429,12 @@ public class GuiWizardHandbook extends GuiScreen { return; } - // Attempts to find a suitable place to put the bookmark to start with - bookmarkSection = sections.get("introduction"); - if(bookmarkSection == null) bookmarkSection = sectionList.get(0); + bookmarkSection = JsonUtils.getString(json, "bookmark_start_section"); + if(!sections.containsKey(bookmarkSection)) throw new JsonSyntaxException("Section with id " + bookmarkSection + " is undefined"); } + + // The first resource load on startup is done before the packet handler is loaded + if(WizardryPacketHandler.net != null) WizardryPacketHandler.net.sendToServer(new PacketRequestAdvancementSync.Message()); } /** @@ -460,6 +448,8 @@ public class GuiWizardHandbook extends GuiScreen { */ private static IResource getHandbookResource(IResourceManager manager){ + // TODO: Implement resource pack stacking to allow addon mods and texture packs to add/overwrite content + IResource handbookFile = null; try{ @@ -507,12 +497,15 @@ public class GuiWizardHandbook extends GuiScreen { if(currentSection != null){ - int index = sectionList.indexOf(currentSection); + List
    visibleSections = new ArrayList<>(sectionList); + visibleSections.removeIf(s -> !s.isUnlocked()); - if(button == nextSection && index + 1 < sections.size()){ - currentPage = singleToDoublePage(sectionList.get(index + 1).startPage); + int index = visibleSections.indexOf(currentSection); + + if(button == nextSection && index + 1 < visibleSections.size()){ + currentPage = singleToDoublePage(visibleSections.get(index + 1).startPage); }else if(index > 0){ - currentPage = singleToDoublePage(sectionList.get(index - 1).startPage); + currentPage = singleToDoublePage(visibleSections.get(index - 1).startPage); } } @@ -520,7 +513,7 @@ public class GuiWizardHandbook extends GuiScreen { currentPage = singleToDoublePage(sections.get("main_contents").startPage); }else if(button == bookmark && bookmarkSection != null){ - currentPage = singleToDoublePage(bookmarkSection.startPage) + bookmarkPage; + currentPage = singleToDoublePage(sections.get(bookmarkSection).startPage) + bookmarkPage; }else{ if(button instanceof GuiButtonHyperlink.Internal){ @@ -540,12 +533,12 @@ public class GuiWizardHandbook extends GuiScreen { this.selectedButton = bookmark; - for(Section section : sections.values()){ + for(String key : sections.keySet()){ // The bookmark is assumed to bookmark the left-hand page - if(section.containsPage(doubleToSinglePage(bookmarkPage, false))) bookmarkSection = section; + if(sections.get(key).containsPage(doubleToSinglePage(currentPage, false))) bookmarkSection = key; } - bookmarkPage = currentPage - singleToDoublePage(bookmarkSection.startPage); + bookmarkPage = currentPage - singleToDoublePage(sections.get(bookmarkSection).startPage); } }else{ super.mouseClicked(mouseX, mouseY, mouseButton); @@ -558,9 +551,14 @@ public class GuiWizardHandbook extends GuiScreen { super.renderToolTip(stack, x, y); } - @SubscribeEvent - public static void onAdvancementEvent(AdvancementEvent event){ - sections.values().forEach(s -> s.onAdvancement(event.getEntityPlayer(), event.getAdvancement())); + @Override + public boolean doesGuiPauseGame(){ + return Wizardry.settings.booksPauseGame; + } + + + public static void updateUnlockStatus(boolean showToasts, ResourceLocation... completedAdvancements){ + sections.values().forEach(s -> s.updateUnlockStatus(showToasts, completedAdvancements)); } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/HandbookToast.java b/src/main/java/electroblob/wizardry/client/gui/handbook/HandbookToast.java new file mode 100644 index 00000000..2db6e666 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/HandbookToast.java @@ -0,0 +1,54 @@ +package electroblob.wizardry.client.gui.handbook; + +import electroblob.wizardry.registry.WizardryItems; +import net.minecraft.client.gui.toasts.GuiToast; +import net.minecraft.client.gui.toasts.IToast; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; + +import java.util.List; + +//@SideOnly(Side.CLIENT) +public class HandbookToast implements IToast { + + private final Section section; + + public HandbookToast(Section section){ + this.section = section; + } + + public IToast.Visibility draw(GuiToast toastGui, long delta){ + + toastGui.getMinecraft().getTextureManager().bindTexture(TEXTURE_TOASTS); + + GlStateManager.color(1.0F, 1.0F, 1.0F); + toastGui.drawTexturedModalRect(0, 0, 0, 32, 160, 32); + + boolean firstPart = delta < 1500L; + + int a = firstPart ? MathHelper.floor(MathHelper.clamp((float)(1500L - delta) / 300.0F, 0.0F, 1.0F) * 255.0F) << 24 | 67108864 + : MathHelper.floor(MathHelper.clamp((float)(delta - 1500L) / 300.0F, 0.0F, 1.0F) * 252.0F) << 24 | 67108864; + + String s = firstPart ? I18n.format("handbook.toast.title") : section.title; + + int c = firstPart ? -11534256 : -16777216; + + List list = toastGui.getMinecraft().fontRenderer.listFormattedStringToWidth(s, 125); + + int h = 16 - list.size() * toastGui.getMinecraft().fontRenderer.FONT_HEIGHT / 2; + + for(String line : list){ + toastGui.getMinecraft().fontRenderer.drawString(line, 30, h, c | a); + h += toastGui.getMinecraft().fontRenderer.FONT_HEIGHT; + } + + RenderHelper.enableGUIStandardItemLighting(); + toastGui.getMinecraft().getRenderItem().renderItemAndEffectIntoGUI(null, new ItemStack(WizardryItems.wizard_handbook), 8, 8); + + return delta >= 5000L ? IToast.Visibility.HIDE : IToast.Visibility.SHOW; + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/Image.java b/src/main/java/electroblob/wizardry/client/gui/handbook/Image.java index cb0d391e..732bb10b 100644 --- a/src/main/java/electroblob/wizardry/client/gui/handbook/Image.java +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/Image.java @@ -9,6 +9,7 @@ import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.JsonUtils; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; import java.util.HashSet; import java.util.Map; @@ -22,11 +23,15 @@ class Image { private int textureWidth, textureHeight; private int u = 0, v = 0; private String caption = ""; + private boolean border = true; // Derived fields, not specifically defined in JSON private final Set instances = new HashSet<>(); private static final int CAPTION_OFFSET = 4; + private static final int TEXTURE_INSET_X = 180; + private static final int BORDER = 1; + private Image(ResourceLocation location, int width, int height){ this.location = location; this.width = width; @@ -68,6 +73,7 @@ class Image { * @param top The y coordinate of the top of the GUI. */ void draw(FontRenderer font, int doublePage, int left, int top){ + // Images for(int[] instance : instances){ if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){ Minecraft.getMinecraft().renderEngine.bindTexture(location); @@ -77,6 +83,29 @@ class Image { top + instance[2] + height + CAPTION_OFFSET, GuiWizardHandbook.colours.get("caption")); } } + + if(border){ + // Borders - do this after all the images are drawn so we only have to bind the handbook texture again once + Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture); + GlStateManager.color(1, 1, 1, 1); + for(int[] instance : instances){ + if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){ + // Math.ceil accounts for odd-numbered image dimensions + DrawingUtils.drawTexturedFlippedRect(left + instance[1] - BORDER, top + instance[2] - BORDER, + TEXTURE_INSET_X, GuiWizardHandbook.GUI_HEIGHT, width / 2 + BORDER, height / 2 + BORDER, + GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT, false, false); + DrawingUtils.drawTexturedFlippedRect(left + instance[1] + width / 2, top + instance[2] - BORDER, + TEXTURE_INSET_X, GuiWizardHandbook.GUI_HEIGHT, MathHelper.ceil(width / 2f) + BORDER, height / 2 + BORDER, + GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT, true, false); + DrawingUtils.drawTexturedFlippedRect(left + instance[1] - BORDER, top + instance[2] + height / 2, + TEXTURE_INSET_X, GuiWizardHandbook.GUI_HEIGHT, width / 2 + BORDER, MathHelper.ceil(height / 2f) + BORDER, + GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT, false, true); + DrawingUtils.drawTexturedFlippedRect(left + instance[1] + width / 2, top + instance[2] + height / 2, + TEXTURE_INSET_X, GuiWizardHandbook.GUI_HEIGHT, MathHelper.ceil(width / 2f) + BORDER, MathHelper.ceil(height / 2f) + BORDER, + GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT, true, true); + } + } + } } /** @@ -98,7 +127,7 @@ class Image { image.textureWidth = JsonUtils.getInt(json, "texture_width", image.width); image.textureHeight = JsonUtils.getInt(json, "texture_height", image.height); image.caption = JsonUtils.getString(json, "caption", ""); - + image.border = JsonUtils.getBoolean(json, "border", true); return image; } diff --git a/src/main/java/electroblob/wizardry/client/gui/handbook/Section.java b/src/main/java/electroblob/wizardry/client/gui/handbook/Section.java index 29f5fc0e..c057d5e5 100644 --- a/src/main/java/electroblob/wizardry/client/gui/handbook/Section.java +++ b/src/main/java/electroblob/wizardry/client/gui/handbook/Section.java @@ -7,13 +7,12 @@ import com.google.gson.JsonSyntaxException; import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.advancements.Advancement; -import net.minecraft.advancements.AdvancementProgress; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.JsonUtils; +import net.minecraft.util.ResourceLocation; import org.apache.commons.lang3.StringUtils; import java.util.*; @@ -23,7 +22,7 @@ import java.util.*; * everything within the section itself, including JSON parsing, unlock triggers and drawing the actual rawText. * Sections may now also be nested and have other elements within them, such as images and a table of contents, a * behaviour which is also handled within this class. - *

    + *

    * The formatting of the book is now done 'dynamically' - that is, the exact positions and page numbers of * sections, images and so on are determined on GUI load and depend on which of the previous sections have been * unlocked, amongst other factors. This means that all of the unlocked sections must be formatted in order on GUI @@ -32,15 +31,15 @@ import java.util.*; * @author Electroblob * @since Wizardry 4.2 */ -// Because these are now generated on resource pack reload (not on handbook open, as before), this class must now -// be static +// Because these are now generated on resource pack reload (not on handbook open, as before), this class can no longer +// be a non-static inner class class Section { // Final fields are mandatory (none here though), the rest are optional String title; private String[] rawText; private Contents contents; - private Advancement[] triggers; + private ResourceLocation[] triggers; private Map subsections; private boolean centreX, centreY; @@ -54,6 +53,9 @@ class Section { */ private final List> pages; + private boolean unlocked = false; + private boolean isNew = false; + private Section(){ this.buttons = new ArrayList<>(); this.pages = new ArrayList<>(); @@ -65,10 +67,10 @@ class Section { } /** - * Returns true if the given page is within this section, false if not. + * Returns true if the given page is within this section, false if not (or if the section is locked). */ boolean containsPage(int page){ - return startPage <= page && startPage + pages.size() > page; + return this.isUnlocked() && startPage <= page && startPage + pages.size() > page; } /** @@ -77,32 +79,24 @@ class Section { */ boolean isUnlocked(){ + if(Minecraft.getMinecraft().player.isCreative()) return true; if(!Wizardry.settings.handbookProgression) return true; // Always unlocked if handbook progression is off + if(triggers == null) return true; // If no triggers were defined, the section is unlocked from the start // A section is automatically unlocked if one of its subsections is unlocked for(Section subsection : subsections.values()){ if(subsection.isUnlocked()) return true; } - if(triggers == null) return true; // If no triggers were defined, the section is unlocked from the start + return unlocked; + } - for(Advancement trigger : triggers){ - - try{ - - // TESTME: Is this properly synced or do we need to do that as well? - Map advancements = (Map)GuiWizardHandbook.ADVANCEMENT_TO_PROGRESS.get(Minecraft.getMinecraft().player.connection.getAdvancementManager()); - - if(advancements.get(trigger).isDone()){ - return true; - } - - }catch(IllegalAccessException e){ - e.printStackTrace(); - } - } - - return false; + /** + * Returns true if this section has been unlocked and not read yet. Also returns true if any subsections are new. + */ + boolean isNew(){ + if(!Wizardry.settings.handbookProgression) return false; + return isNew || this.subsections.values().stream().anyMatch(Section::isNew); } /** @@ -143,12 +137,19 @@ class Section { for(String line : lines){ - int lx = centreX ? x + GuiWizardHandbook.PAGE_WIDTH / 2 - font.getStringWidth(line) / 2 : x; - - font.drawString(line, lx, y, DrawingUtils.BLACK, false); + if(line.startsWith(GuiWizardHandbook.FORMAT_MARKER + GuiWizardHandbook.RULER_TAG)){ + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture); + DrawingUtils.drawTexturedRect(x-1, y-1, 0, GuiWizardHandbook.GUI_HEIGHT, GuiWizardHandbook.PAGE_WIDTH + 2, 9, GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT); + }else{ + int lx = centreX ? x + GuiWizardHandbook.PAGE_WIDTH / 2 - font.getStringWidth(line) / 2 : x; + font.drawString(line, lx, y, DrawingUtils.BLACK, false); + } y += font.FONT_HEIGHT; } + + isNew = false; // Now a page has been drawn, the player must have seen it so it's not new any more } } } @@ -180,7 +181,7 @@ class Section { // Adds the header if present if(!this.title.isEmpty()){ lines.add(this.title); - lines.add(GuiWizardHandbook.rulerText); + lines.add(GuiWizardHandbook.FORMAT_MARKER + GuiWizardHandbook.RULER_TAG); } // Adds space for the contents if it exists @@ -212,7 +213,7 @@ class Section { + StringUtils.abbreviate(raw, 50)); Image image = GuiWizardHandbook.images.get(arguments[1]); - if(image == null) throw new JsonSyntaxException("Image with id " + arguments[1] + "is undefined"); + if(image == null) throw new JsonSyntaxException("Image with id " + arguments[1] + " is undefined"); // Starts a new page if the image will not fit on the current one if((lines.size() % maxLineNumber) * font.FONT_HEIGHT + image.getHeight(font) > GuiWizardHandbook.PAGE_HEIGHT){ @@ -248,27 +249,35 @@ class Section { + StringUtils.abbreviate(raw, 50)); CraftingRecipe recipe = GuiWizardHandbook.recipes.get(arguments[1]); - if(recipe == null) throw new JsonSyntaxException("Recipe with id " + arguments[1] + "is undefined"); + if(recipe == null) throw new JsonSyntaxException("Recipe with id " + arguments[1] + " is undefined"); // Starts a new page if the recipe will not fit on the current one if((lines.size() % maxLineNumber) * font.FONT_HEIGHT + CraftingRecipe.HEIGHT > GuiWizardHandbook.PAGE_HEIGHT){ - // Remaining number of lines on the page - lines.addAll(Collections.nCopies(maxLineNumber - (lines.size() % maxLineNumber), "")); + // Remaining number of lines on the page, plus the first blank one on the new page + lines.addAll(Collections.nCopies(maxLineNumber - (lines.size() % maxLineNumber), " ")); } int page = startPage + (lines.size() / maxLineNumber); + if(lines.size() % maxLineNumber == 0) lines.add(" "); + int startLine = lines.size() % maxLineNumber - 1; + recipe.addInstance(page, GuiWizardHandbook.PAGE_WIDTH / 2 - CraftingRecipe.WIDTH / 2 + (GuiWizardHandbook.isRightPage(page) ? GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : GuiWizardHandbook.TEXT_INSET_X), - GuiWizardHandbook.TEXT_INSET_Y + (lines.size() % maxLineNumber) * font.FONT_HEIGHT); + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT); // Height of the recipe in lines, rounded up // Uses a single space instead of an empty string so that the page trimming doesn't remove them - lines.addAll(Collections.nCopies(CraftingRecipe.HEIGHT / font.FONT_HEIGHT, " ")); + lines.addAll(Collections.nCopies(CraftingRecipe.HEIGHT / font.FONT_HEIGHT - 1, " ")); // This time we're not adding an extra space because it's not really needed }else{ // All other paragraphs + // Formatting + for(Map.Entry entry : GuiWizardHandbook.FORMAT_TAGS.entrySet()){ + paragraph = paragraph.replace(GuiWizardHandbook.FORMAT_MARKER + entry.getKey(), entry.getValue()); + } + // Hyperlinks int linkStart; @@ -284,15 +293,17 @@ class Section { String linkRaw = paragraph.substring(linkStart, linkEnd + 1); String[] arguments = paragraph.substring(linkStart + 1, linkEnd).split("\\s", 2); - String suffix = paragraph.substring(linkEnd).split("\\s", 2)[0]; + String suffix = paragraph.substring(linkEnd).split("\\s", 2)[0].substring(1); // substring(1) to remove the @ // The index of the single page currently being formatted, relative to the section int pageRelative = (lines.size() + upToLink.size() - 1) / maxLineNumber; // The overall index of the single page currently being formatted int page = startPage + pageRelative; + // The line number on this page + int lineNumber = (lines.size() + upToLink.size() - 1) % maxLineNumber; int x = GuiWizardHandbook.isRightPage(page) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X; - int y = top + GuiWizardHandbook.TEXT_INSET_Y + (((lines.size() + upToLink.size() - 1) % maxLineNumber)) * font.FONT_HEIGHT; + int y = top + GuiWizardHandbook.TEXT_INSET_Y + lineNumber * font.FONT_HEIGHT; // Adds any missing sub-lists while(this.buttons.size() <= pageRelative){ @@ -300,18 +311,13 @@ class Section { } // The button id only does what you use it for, so we're just not using it at all. - this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix)); + this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix, maxLineNumber - lineNumber - 1, GuiWizardHandbook.isRightPage(page))); // The link button should exactly overlay the display rawText in the main string // If the link has no display rawText specified, it displays the unformatted target string paragraph = paragraph.replace(linkRaw, arguments[arguments.length - 1]); } - // Formatting - for(Map.Entry entry : GuiWizardHandbook.FORMAT_TAGS.entrySet()){ - paragraph = paragraph.replace(GuiWizardHandbook.FORMAT_MARKER + entry.getKey(), entry.getValue()); - } - lines.addAll(font.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH)); } @@ -373,18 +379,22 @@ class Section { } if(JsonUtils.hasField(json, "contents")){ - section.contents = Contents.fromJson(JsonUtils.getJsonObject(json, "contents")); + section.contents = Contents.fromJson(section, JsonUtils.getJsonObject(json, "contents")); GuiWizardHandbook.contentsList.put(section.contents.id, section.contents); } if(JsonUtils.hasField(json, "text")){ - // TESTME: Does this always preserve order? section.rawText = Streams.stream(JsonUtils.getJsonArray(json, "text")) .map(e -> JsonUtils.getString(e, "element of array rawText")) .toArray(String[]::new); } - // TODO: Triggers + if(JsonUtils.hasField(json, "triggers")){ + section.triggers = Streams.stream(JsonUtils.getJsonArray(json, "triggers")) + .map(e -> new ResourceLocation(JsonUtils.getString(e, "element of array triggers"))) + .toArray(ResourceLocation[]::new); + // TODO: Can we validate this and throw a JSON exception if no such advancement exists? + } if(JsonUtils.hasField(json, "centre")){ JsonObject centre = JsonUtils.getJsonObject(json,"centre"); @@ -416,14 +426,26 @@ class Section { } } - public void onAdvancement(EntityPlayer player, Advancement advancement){ - Minecraft minecraft = Minecraft.getMinecraft(); - //System.out.println(title); - if(triggers != null && Arrays.asList(triggers).contains(advancement) && player == minecraft.player){ - //minecraft.getToastGui().drawToast(IToast); + /** + * Called on login and advancement completion to update this section's unlock status and display toast + * notifications if applicable. + */ + public void updateUnlockStatus(boolean showToasts, ResourceLocation... completedAdvancements){ - // Debug - //System.out.println(title); + if(triggers == null) return; + + List completed = new ArrayList<>(Arrays.asList(completedAdvancements)); + completed.retainAll(Arrays.asList(triggers)); + + // Only shows the toast when the section was locked before and is now unlocked + if(!this.unlocked && !completed.isEmpty() && showToasts && Wizardry.settings.handbookProgression){ + // Mmmmm toast... + Minecraft minecraft = Minecraft.getMinecraft(); + minecraft.getToastGui().add(new HandbookToast(this)); + this.isNew = true; } + + // Currently, this will not take subsections into account + this.unlocked = !completed.isEmpty(); } } diff --git a/src/main/java/electroblob/wizardry/client/model/BakedModelGlowingOverlay.java b/src/main/java/electroblob/wizardry/client/model/BakedModelGlowingOverlay.java new file mode 100644 index 00000000..c3324830 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/BakedModelGlowingOverlay.java @@ -0,0 +1,234 @@ +package electroblob.wizardry.client.model; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad; +import net.minecraftforge.client.model.pipeline.VertexLighterFlat; +import net.minecraftforge.common.ForgeModContainer; +import net.minecraftforge.fml.client.FMLClientHandler; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nullable; +import javax.vecmath.Matrix4f; +import java.util.ArrayList; +import java.util.List; + +/** + * Custom baked model that stores a list of texture names and sets the lighting to full brightness for any quads + * with one of those textures. Most of this code was copied and adapted from refined storage, which is licensed under + * the MIT license. https://github.com/raoulvdberge/refinedstorage
    + *
    + * N.B. This doesn't cover item models, and all of the code/model solutions to this that I have tried haven't worked. + * However, I noticed that the shade tag seems to work perfectly for items, so instead I've simply duplicated the block + * models into the item models folder and add {@code "shade":false} where appropriate. (If it works, it works, right?) + * + * @author Electroblob + * @author raoulvdberge + */ +public class BakedModelGlowingOverlay implements IBakedModel { + + // Something something something cache, says Forge + // This breaks randomised block models (because it's cached, duh...) but simply including the rand parameter will + // completely defeat the point of the cache so I need some way of storing the randomised model variants... hmmm... + // See WeightedBakedModel for more on randomisation (it's pretty similar to my 1.7 implementation from years ago) + +// private class CacheKey { +// +// private IBakedModel base; +// private String suffix; +// private IBlockState state; +// private EnumFacing side; +// +// public CacheKey(IBakedModel base, String suffix, IBlockState state, EnumFacing side){ +// this.base = base; +// this.suffix = suffix; +// this.state = state; +// this.side = side; +// } +// +// @Override +// public boolean equals(Object o){ +// +// if(this == o) return true; +// if(o == null || getClass() != o.getClass()) return false; +// +// CacheKey cacheKey = (CacheKey)o; +// +// if(cacheKey.side != side) return false; +// if(!state.equals(cacheKey.state)) return false; +// +// return true; +// } +// +// @Override +// public int hashCode() { +// return state.hashCode() + (31 * (side != null ? side.hashCode() : 0)); +// } +// } +// +// private static final LoadingCache> CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { +// @Override +// public List load(CacheKey key) { +// return transformQuads(key.base.getQuads(key.state, key.side, 0), key.suffix); +// } +// }); + + private final IBakedModel delegate; + private String suffix; + + public BakedModelGlowingOverlay(IBakedModel delegate, String suffix){ + this.delegate = delegate; + this.suffix = suffix; + } + + @Override + public List getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand){ + if(state == null) return delegate.getQuads(state, side, rand); + return transformQuads(delegate.getQuads(state, side, rand), suffix); + //return CACHE.getUnchecked(new CacheKey(delegate, suffix, state instanceof IExtendedBlockState ? ((IExtendedBlockState) state).getClean() : state, side)); + } + + // I would write these myself but I'd end up with almost the exact same thing anyway + // They replace the quads from the original (delegate) model with full-brightness quads if their texture has the given suffix + + private static List transformQuads(List oldQuads, String suffix){ + + List quads = new ArrayList<>(oldQuads); + + for(int i = 0; i < quads.size(); ++i){ + BakedQuad quad = quads.get(i); + + if(quad.getSprite().getIconName().endsWith(suffix)){ + quads.set(i, transformQuad(quad, 0.007F)); // What's the significance of 0.007? + } + } + + return quads; + } + + private static BakedQuad transformQuad(BakedQuad quad, float light){ + + if(isLightMapDisabled()){ + return quad; + } + + VertexFormat newFormat = getFormatWithLightMap(quad.getFormat()); + + UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(newFormat); + + VertexLighterFlat trans = new VertexLighterFlat(Minecraft.getMinecraft().getBlockColors()) { + @Override + protected void updateLightmap(float[] normal, float[] lightmap, float x, float y, float z){ + lightmap[0] = light; + lightmap[1] = light; + } + + @Override + public void setQuadTint(int tint){ + // NO OP + } + }; + + trans.setParent(builder); + + quad.pipe(trans); + + builder.setQuadTint(quad.getTintIndex()); + builder.setQuadOrientation(quad.getFace()); + builder.setTexture(quad.getSprite()); + builder.setApplyDiffuseLighting(false); + + return builder.build(); + } + + @Override + public boolean isAmbientOcclusion(){ + return delegate.isAmbientOcclusion(); + } + + @Override + public boolean isGui3d(){ + return delegate.isGui3d(); + } + + @Override + public boolean isBuiltInRenderer(){ + return delegate.isBuiltInRenderer(); + } + + @Override + public TextureAtlasSprite getParticleTexture(){ + return delegate.getParticleTexture(); + } + + @Override + public ItemCameraTransforms getItemCameraTransforms(){ + return delegate.getItemCameraTransforms(); + } + + @Override + public ItemOverrideList getOverrides(){ + return delegate.getOverrides();//BakedModelItemOverride.instance; + } + + @Override + public boolean isAmbientOcclusion(IBlockState state){ + return delegate.isAmbientOcclusion(state); + } + + @Override + public Pair handlePerspective(ItemCameraTransforms.TransformType cameraTransformType){ + return delegate.handlePerspective(cameraTransformType); + } + + // Utilities + + private static boolean isLightMapDisabled(){ + return FMLClientHandler.instance().hasOptifine() || !ForgeModContainer.forgeLightPipelineEnabled; + } + + private static final VertexFormat ITEM_FORMAT_WITH_LIGHTMAP = new VertexFormat(DefaultVertexFormats.ITEM).addElement(DefaultVertexFormats.TEX_2S); + + private static VertexFormat getFormatWithLightMap(VertexFormat format){ + + if(isLightMapDisabled()){ + return format; + } + + if(format == DefaultVertexFormats.BLOCK){ + return DefaultVertexFormats.BLOCK; + }else if(format == DefaultVertexFormats.ITEM){ + return ITEM_FORMAT_WITH_LIGHTMAP; + }else if(!format.hasUvOffset(1)){ + VertexFormat result = new VertexFormat(format); + result.addElement(DefaultVertexFormats.TEX_2S); + return result; + } + + return format; + } + + // Bit of a weird way of doing things if you ask me, but as far as I can tell it's how you're supposed to do it +// public static final class BakedModelItemOverride extends ItemOverrideList { +// +// // This class doesn't contain any data of its own so it can be a singleton +// public static final BakedModelItemOverride instance = new BakedModelItemOverride(); +// +// private BakedModelItemOverride(){ +// super(ImmutableList.of()); // We're not using the list functionality +// } +// +// @Override +// public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity){ +// return new BakedModelGlowingOverlay(originalModel, "overlay"); // Bish bash bosh +// } +// } +} diff --git a/src/main/java/electroblob/wizardry/client/model/ModelIceGiant.java b/src/main/java/electroblob/wizardry/client/model/ModelIceGiant.java index 798cfcb4..592f0208 100644 --- a/src/main/java/electroblob/wizardry/client/model/ModelIceGiant.java +++ b/src/main/java/electroblob/wizardry/client/model/ModelIceGiant.java @@ -1,18 +1,16 @@ package electroblob.wizardry.client.model; -import javax.vecmath.Matrix4f; -import javax.vecmath.Vector3f; - import electroblob.wizardry.entity.living.EntityIceGiant; import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelRenderer; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.math.MathHelper; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +import javax.vecmath.Matrix4f; +import javax.vecmath.Vector3f; + +//@SideOnly(Side.CLIENT) public class ModelIceGiant extends ModelBase { /** The head model for the iron golem. */ public ModelRenderer iceGiantHead; diff --git a/src/main/java/electroblob/wizardry/client/model/ModelWizard.java b/src/main/java/electroblob/wizardry/client/model/ModelWizard.java index 0204c86a..8e7a469d 100644 --- a/src/main/java/electroblob/wizardry/client/model/ModelWizard.java +++ b/src/main/java/electroblob/wizardry/client/model/ModelWizard.java @@ -97,9 +97,9 @@ public class ModelWizard extends ModelBiped { setRotation(Shape13, 0F, 0F, 0F); // Makes head bits move with head - // bipedHead.addChild(Shape5); + // bipedHead.addChild(hatSegment4); bipedHead.addChild(beard); - // bipedHead.addChild(Shape7); + // bipedHead.addChild(hatSegment6); // bipedHead.addChild(Shape8); // bipedHead.addChild(Shape9); // bipedHead.addChild(Shape10); @@ -116,8 +116,8 @@ public class ModelWizard extends ModelBiped { /* public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { * super.render(entity, f, f1, f2, f3, f4, f5); setRotationAngles(f, f1, f2, f3, f4, f5, entity); * bipedRightLeg.render(f5); bipedLeftLeg.render(f5); bipedBody.render(f5); bipedLeftArm.render(f5); - * bipedRightArm.render(f5); bipedHead.render(f5); Shape5.render(f5); Shape8.render(f5); Shape9.render(f5); - * Shape10.render(f5); Shape7.render(f5); Shape11.render(f5); Shape12.render(f5); Shape6.render(f5); + * bipedRightArm.render(f5); bipedHead.render(f5); hatSegment4.render(f5); Shape8.render(f5); Shape9.render(f5); + * Shape10.render(f5); hatSegment6.render(f5); Shape11.render(f5); Shape12.render(f5); hatSegment5.render(f5); * Shape13.render(f5); } */ private void setRotation(ModelRenderer model, float x, float y, float z){ model.rotateAngleX = x; diff --git a/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java b/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java index 20429a71..2bebd9c0 100644 --- a/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java +++ b/src/main/java/electroblob/wizardry/client/model/ModelWizardArmour.java @@ -1,99 +1,110 @@ package electroblob.wizardry.client.model; +import electroblob.wizardry.block.BlockStatue; import net.minecraft.client.model.ModelRenderer; import net.minecraft.entity.Entity; public class ModelWizardArmour extends ModelArmourFixer { - ModelRenderer Shape1; - ModelRenderer Shape2; - ModelRenderer Shape3; - ModelRenderer Shape4; - ModelRenderer Shape5; - ModelRenderer Shape6; - ModelRenderer Shape7; + + ModelRenderer hatBrim; + ModelRenderer hatSegment1; + ModelRenderer hatSegment2; + ModelRenderer hatSegment3; + ModelRenderer hatSegment4; + ModelRenderer hatSegment5; + ModelRenderer hatSegment6; ModelRenderer robe; - public ModelWizardArmour(float scale){ + public ModelWizardArmour(float delta){ - super(scale, 0, 64, 64); + super(delta, 0, 64, 64); // This is necessary to stop the head from scaling. this.bipedHead = new ModelRenderer(this, 0, 0); - this.bipedHead.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, 0.1f); + // The hat layer has an offset of 0.5, so 0.6 is about the smallest we can get away with + this.bipedHead.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, 0.6f); this.bipedHead.setRotationPoint(0.0F, 0.0F + 0, 0.0F); - Shape1 = new ModelRenderer(this, -16, 32); - Shape1.addBox(-8F, -7F, -8F, 16, 0, 16); - Shape1.setRotationPoint(0F, 0F, 0F); - Shape1.setTextureSize(64, 64); - Shape1.mirror = true; - setRotation(Shape1, 0F, 0F, 0F); + hatBrim = new ModelRenderer(this, 0, 47); + // Making the height 1 stops the top and bottom z-fighting when the hat is enchanted + hatBrim.addBox(-8F, -6.85F, -8F, 16, 1, 16, 0.6f); + hatBrim.setRotationPoint(0F, 0F, 0F); + hatBrim.setTextureSize(64, 64); + hatBrim.mirror = true; + setRotation(hatBrim, 0F, 0F, 0F); - Shape2 = new ModelRenderer(this, 0, 48); - Shape2.addBox(0F, 0F, 0F, 6, 2, 6); - Shape2.setRotationPoint(-3F, -10F, -3F); - Shape2.setTextureSize(64, 64); - Shape2.mirror = true; - setRotation(Shape2, -0.1396263F, 0F, 0F); + hatSegment1 = new ModelRenderer(this, 0, 32); + hatSegment1.addBox(0F, 0F, 0F, 6, 2, 6, 0.2f); + hatSegment1.setRotationPoint(-3F, -10.6F, -3F); + hatSegment1.setTextureSize(64, 64); + hatSegment1.mirror = true; + setRotation(hatSegment1, -0.1396263F, 0F, 0F); - Shape3 = new ModelRenderer(this, 0, 56); - Shape3.addBox(0F, 0F, 0F, 5, 2, 5); - Shape3.setRotationPoint(-2.5F, -11.53333F, -2F); - Shape3.setTextureSize(64, 64); - Shape3.mirror = true; - setRotation(Shape3, -0.2443461F, 0F, 0F); + hatSegment2 = new ModelRenderer(this, 0, 40); + hatSegment2.addBox(0F, 0F, 0F, 5, 2, 5, 0.1f); + hatSegment2.setRotationPoint(-2.5F, -12.13333F, -2F); + hatSegment2.setTextureSize(64, 64); + hatSegment2.mirror = true; + setRotation(hatSegment2, -0.2443461F, 0F, 0F); - Shape4 = new ModelRenderer(this, 24, 48); - Shape4.addBox(0F, 0F, 0F, 4, 2, 4); - Shape4.setRotationPoint(-2F, -13F, -1F); - Shape4.setTextureSize(64, 64); - Shape4.mirror = true; - setRotation(Shape4, -0.4014257F, 0F, 0F); + hatSegment3 = new ModelRenderer(this, 24, 32); + hatSegment3.addBox(0F, 0F, 0F, 4, 2, 4); + hatSegment3.setRotationPoint(-2F, -13.6F, -1F); + hatSegment3.setTextureSize(64, 64); + hatSegment3.mirror = true; + setRotation(hatSegment3, -0.4014257F, 0F, 0F); - Shape5 = new ModelRenderer(this, 24, 54); - Shape5.addBox(0F, 0F, 0F, 3, 2, 3); - Shape5.setRotationPoint(-1.5F, -14F, 0F); - Shape5.setTextureSize(64, 64); - Shape5.mirror = true; - setRotation(Shape5, -0.5759587F, 0F, 0F); + hatSegment4 = new ModelRenderer(this, 24, 38); + hatSegment4.addBox(0F, 0F, 0F, 3, 2, 3); + hatSegment4.setRotationPoint(-1.5F, -14.6F, 0F); + hatSegment4.setTextureSize(64, 64); + hatSegment4.mirror = true; + setRotation(hatSegment4, -0.5759587F, 0F, 0F); - Shape6 = new ModelRenderer(this, 20, 59); - Shape6.addBox(0F, 0F, 0F, 2, 2, 2); - Shape6.setRotationPoint(-1F, -14F, 0F); - Shape6.setTextureSize(64, 64); - Shape6.mirror = true; - setRotation(Shape6, 0.3316126F, 0F, 0F); + hatSegment5 = new ModelRenderer(this, 20, 43); + hatSegment5.addBox(0F, 0F, 0F, 2, 2, 2); + hatSegment5.setRotationPoint(-1F, -14.6F, 0F); + hatSegment5.setTextureSize(64, 64); + hatSegment5.mirror = true; + setRotation(hatSegment5, 0.3316126F, 0F, 0F); - Shape7 = new ModelRenderer(this, 28, 59); - Shape7.addBox(0F, 0F, 0F, 1, 1, 3); - Shape7.setRotationPoint(-0.5F, -14.5F, 2F); - Shape7.setTextureSize(64, 64); - Shape7.mirror = true; - setRotation(Shape7, -0.5585054F, 0F, 0F); + hatSegment6 = new ModelRenderer(this, 28, 43); + hatSegment6.addBox(0F, 0F, 0F, 1, 1, 3); + hatSegment6.setRotationPoint(-0.5F, -15.1F, 2F); + hatSegment6.setTextureSize(64, 64); + hatSegment6.mirror = true; + setRotation(hatSegment6, -0.5585054F, 0F, 0F); - // The robe is now the body - bipedBody = new ModelRenderer(this, 40, 42); - bipedBody.addBox(-4F, 0F, -2F, 8, 18, 4, scale); + bipedBody = new ModelRenderer(this, 16, 16); + bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta); bipedBody.setRotationPoint(0F, 0F, 0F); bipedBody.setTextureSize(64, 64); bipedBody.mirror = true; setRotation(bipedBody, 0F, 0F, 0F); + robe = new ModelRenderer(this, 40, 32); + robe.addBox(-4F, 0F, -2F, 8, 7, 4, delta); + robe.setRotationPoint(0F, 12, 0F); // 12.5 accounts for the expansion of each box + robe.setTextureSize(64, 64); + robe.mirror = true; + setRotation(robe, 0F, 0F, 0F); + // Makes the hat rotate with the head. - bipedHead.addChild(Shape1); - bipedHead.addChild(Shape2); - bipedHead.addChild(Shape3); - bipedHead.addChild(Shape4); - bipedHead.addChild(Shape5); - bipedHead.addChild(Shape6); - bipedHead.addChild(Shape7); - // Makes the robe move with the body - // bipedBody.addChild(robe); + bipedHead.addChild(hatBrim); + bipedHead.addChild(hatSegment1); + bipedHead.addChild(hatSegment2); + bipedHead.addChild(hatSegment3); + bipedHead.addChild(hatSegment4); + bipedHead.addChild(hatSegment5); + bipedHead.addChild(hatSegment6); } public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){ + if(entity.isInvisible() && !entity.getEntityData().getBoolean(BlockStatue.PETRIFIED_NBT_KEY) + && !entity.getEntityData().getBoolean(BlockStatue.FROZEN_NBT_KEY)) return; super.render(entity, f, f1, f2, f3, f4, f5); setRotationAngles(f, f1, f2, f3, f4, f5, entity); + this.robe.render(f5); } private void setRotation(ModelRenderer model, float x, float y, float z){ @@ -104,6 +115,20 @@ public class ModelWizardArmour extends ModelArmourFixer { public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity){ super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + this.robe.showModel = this.bipedBody.showModel; + if(this.isSneak){ + //this.robe.rotationPointY = 10.5f; + this.robe.rotationPointZ = 4; + }else{ + //this.robe.rotationPointY = 12.5f; + this.robe.rotationPointZ = 0; + } + + // The bottom part of the robe takes the y rotation from the rest of the robe but the x/z rotation + // from the average of the two legs + this.robe.rotateAngleX = (this.bipedLeftLeg.rotateAngleX + this.bipedRightLeg.rotateAngleX) / 2f; + this.robe.rotateAngleY = this.bipedBody.rotateAngleY; + this.robe.rotateAngleZ = (this.bipedLeftLeg.rotateAngleZ + this.bipedRightLeg.rotateAngleZ) / 2f; } } diff --git a/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java b/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java deleted file mode 100644 index f9d101c8..00000000 --- a/src/main/java/electroblob/wizardry/client/model/WizardryItemModels.java +++ /dev/null @@ -1,197 +0,0 @@ -package electroblob.wizardry.client.model; - -import electroblob.wizardry.registry.WizardryBlocks; -import electroblob.wizardry.registry.WizardryItems; -import net.minecraft.client.renderer.block.model.ModelResourceLocation; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.NonNullList; -import net.minecraftforge.client.event.ModelRegistryEvent; -import net.minecraftforge.client.model.ModelLoader; -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; -import net.minecraftforge.oredict.OreDictionary; - -/** - * Class responsible for registering all of wizardry's item (and itemblock) models. - * - * @author Electroblob - * @since Wizardry 2.1 - */ -@SideOnly(Side.CLIENT) -@Mod.EventBusSubscriber(Side.CLIENT) -public final class WizardryItemModels { - - @SubscribeEvent - public static void register(ModelRegistryEvent event){ - - // ItemBlocks - - registerItemModel(Item.getItemFromBlock(WizardryBlocks.arcane_workbench)); - registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_ore)); - registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_flower)); - registerItemModel(Item.getItemFromBlock(WizardryBlocks.transportation_stone)); - registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_block)); - - // Items - - registerItemModel(WizardryItems.magic_crystal); - - registerItemModel(WizardryItems.magic_wand); - registerItemModel(WizardryItems.apprentice_wand); - registerItemModel(WizardryItems.advanced_wand); - registerItemModel(WizardryItems.master_wand); - - registerItemModel(WizardryItems.spell_book); - // Wildcard registered for wizard trades. - registerItemModel(WizardryItems.spell_book, OreDictionary.WILDCARD_VALUE, "normal"); - registerItemModel(WizardryItems.arcane_tome); - registerItemModel(WizardryItems.wizard_handbook); - - registerItemModel(WizardryItems.basic_fire_wand); - registerItemModel(WizardryItems.basic_ice_wand); - registerItemModel(WizardryItems.basic_lightning_wand); - registerItemModel(WizardryItems.basic_necromancy_wand); - registerItemModel(WizardryItems.basic_earth_wand); - registerItemModel(WizardryItems.basic_sorcery_wand); - registerItemModel(WizardryItems.basic_healing_wand); - - registerItemModel(WizardryItems.apprentice_fire_wand); - registerItemModel(WizardryItems.apprentice_ice_wand); - registerItemModel(WizardryItems.apprentice_lightning_wand); - registerItemModel(WizardryItems.apprentice_necromancy_wand); - registerItemModel(WizardryItems.apprentice_earth_wand); - registerItemModel(WizardryItems.apprentice_sorcery_wand); - registerItemModel(WizardryItems.apprentice_healing_wand); - - registerItemModel(WizardryItems.advanced_fire_wand); - registerItemModel(WizardryItems.advanced_ice_wand); - registerItemModel(WizardryItems.advanced_lightning_wand); - registerItemModel(WizardryItems.advanced_necromancy_wand); - registerItemModel(WizardryItems.advanced_earth_wand); - registerItemModel(WizardryItems.advanced_sorcery_wand); - registerItemModel(WizardryItems.advanced_healing_wand); - - registerItemModel(WizardryItems.master_fire_wand); - registerItemModel(WizardryItems.master_ice_wand); - registerItemModel(WizardryItems.master_lightning_wand); - registerItemModel(WizardryItems.master_necromancy_wand); - registerItemModel(WizardryItems.master_earth_wand); - registerItemModel(WizardryItems.master_sorcery_wand); - registerItemModel(WizardryItems.master_healing_wand); - - registerItemModel(WizardryItems.spectral_sword); - registerItemModel(WizardryItems.spectral_pickaxe); - registerItemModel(WizardryItems.spectral_bow); - - registerItemModel(WizardryItems.mana_flask); - - registerItemModel(WizardryItems.storage_upgrade); - registerItemModel(WizardryItems.siphon_upgrade); - registerItemModel(WizardryItems.condenser_upgrade); - registerItemModel(WizardryItems.range_upgrade); - registerItemModel(WizardryItems.duration_upgrade); - registerItemModel(WizardryItems.cooldown_upgrade); - registerItemModel(WizardryItems.blast_upgrade); - registerItemModel(WizardryItems.attunement_upgrade); - - registerItemModel(WizardryItems.flaming_axe); - registerItemModel(WizardryItems.frost_axe); - - registerItemModel(WizardryItems.firebomb); - registerItemModel(WizardryItems.poison_bomb); - - registerItemModel(WizardryItems.blank_scroll); - registerItemModel(WizardryItems.scroll); - - registerItemModel(WizardryItems.armour_upgrade); - - registerItemModel(WizardryItems.magic_silk); - - registerItemModel(WizardryItems.wizard_hat); - registerItemModel(WizardryItems.wizard_robe); - registerItemModel(WizardryItems.wizard_leggings); - registerItemModel(WizardryItems.wizard_boots); - - registerItemModel(WizardryItems.wizard_hat_fire); - registerItemModel(WizardryItems.wizard_robe_fire); - registerItemModel(WizardryItems.wizard_leggings_fire); - registerItemModel(WizardryItems.wizard_boots_fire); - - registerItemModel(WizardryItems.wizard_hat_ice); - registerItemModel(WizardryItems.wizard_robe_ice); - registerItemModel(WizardryItems.wizard_leggings_ice); - registerItemModel(WizardryItems.wizard_boots_ice); - - registerItemModel(WizardryItems.wizard_hat_lightning); - registerItemModel(WizardryItems.wizard_robe_lightning); - registerItemModel(WizardryItems.wizard_leggings_lightning); - registerItemModel(WizardryItems.wizard_boots_lightning); - - registerItemModel(WizardryItems.wizard_hat_necromancy); - registerItemModel(WizardryItems.wizard_robe_necromancy); - registerItemModel(WizardryItems.wizard_leggings_necromancy); - registerItemModel(WizardryItems.wizard_boots_necromancy); - - registerItemModel(WizardryItems.wizard_hat_earth); - registerItemModel(WizardryItems.wizard_robe_earth); - registerItemModel(WizardryItems.wizard_leggings_earth); - registerItemModel(WizardryItems.wizard_boots_earth); - - registerItemModel(WizardryItems.wizard_hat_sorcery); - registerItemModel(WizardryItems.wizard_robe_sorcery); - registerItemModel(WizardryItems.wizard_leggings_sorcery); - registerItemModel(WizardryItems.wizard_boots_sorcery); - - registerItemModel(WizardryItems.wizard_hat_healing); - registerItemModel(WizardryItems.wizard_robe_healing); - registerItemModel(WizardryItems.wizard_leggings_healing); - registerItemModel(WizardryItems.wizard_boots_healing); - - registerItemModel(WizardryItems.spectral_helmet); - registerItemModel(WizardryItems.spectral_chestplate); - registerItemModel(WizardryItems.spectral_leggings); - registerItemModel(WizardryItems.spectral_boots); - - registerItemModel(WizardryItems.smoke_bomb); - - registerItemModel(WizardryItems.identification_scroll); - } - - // Moved from the proxies - - /** - * Registers an item model, using the item's registry name as the model name (this convention makes it easier to - * keep track of everything). Variant defaults to "normal". Registers the model for metadata 0 automatically, plus - * all the other metadata values that the item can take, as defined in - * {@link Item#getSubItems(Item, net.minecraft.creativetab.CreativeTabs, java.util.List)}. The creative tab supplied - * to the aforementioned method will be whichever one the item is in. - */ - private static void registerItemModel(Item item){ - - if(item.getHasSubtypes()){ - NonNullList items = NonNullList.create(); - item.getSubItems(item.getCreativeTab(), items); // Client-only method, but we're client-side so this is OK. - for(ItemStack stack : items){ - ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(), - new ModelResourceLocation(item.getRegistryName(), "inventory")); - } - } - // Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why! - ModelLoader.setCustomModelResourceLocation(item, 0, - new ModelResourceLocation(item.getRegistryName(), "inventory")); - } - - /** - * Registers an item model for the given metadata, using the item's registry name as the model name (this convention - * makes it easier to keep track of everything). This is intended for registering additional metadata values which - * aren't displayed in the creative menu, for example the wildcard spell book used in wizard trades. - */ - private static void registerItemModel(Item item, int metadata, String variant){ - ModelLoader.setCustomModelResourceLocation(item, metadata, - new ModelResourceLocation(item.getRegistryName(), variant)); - } - -} diff --git a/src/main/java/electroblob/wizardry/client/model/WizardryModels.java b/src/main/java/electroblob/wizardry/client/model/WizardryModels.java new file mode 100644 index 00000000..a6f2529e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/WizardryModels.java @@ -0,0 +1,343 @@ +package electroblob.wizardry.client.model; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockCrystal; +import electroblob.wizardry.block.BlockPedestal; +import electroblob.wizardry.block.BlockRunestone; +import electroblob.wizardry.item.IMultiTexturedItem; +import electroblob.wizardry.item.ItemBlockMultiTexturedElemental; +import electroblob.wizardry.item.ItemCrystal; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.block.statemap.StateMap; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import net.minecraftforge.client.event.ModelBakeEvent; +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.model.ModelLoader; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.oredict.OreDictionary; + +/** + * Class responsible for registering all of wizardry's item and block models. + * + * @author Electroblob + * @since Wizardry 2.1 + */ +//@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(Side.CLIENT) +public final class WizardryModels { + + private WizardryModels(){} // No instances! + + @SubscribeEvent + public static void register(ModelRegistryEvent event){ + + // ItemBlocks + + registerItemModel(Item.getItemFromBlock(WizardryBlocks.arcane_workbench)); + registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_ore)); + registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_flower)); + registerItemModel(Item.getItemFromBlock(WizardryBlocks.transportation_stone)); + + ModelLoader.setCustomStateMapper(WizardryBlocks.crystal_block, new StateMap.Builder() + .withName(BlockCrystal.ELEMENT).withSuffix("_crystal_block").build()); + // Yay unchecked casting! But we know it's always ok here, and it makes everything much neater. + ItemBlockMultiTexturedElemental crystalBlockItem = (ItemBlockMultiTexturedElemental)Item.getItemFromBlock(WizardryBlocks.crystal_block); + registerMultiTexturedModel(crystalBlockItem); + + ModelLoader.setCustomStateMapper(WizardryBlocks.runestone, new StateMap.Builder() + .withName(BlockRunestone.ELEMENT).withSuffix("_runestone").build()); + ItemBlockMultiTexturedElemental runestoneItem = (ItemBlockMultiTexturedElemental)Item.getItemFromBlock(WizardryBlocks.runestone); + registerMultiTexturedModel(runestoneItem); + + ModelLoader.setCustomStateMapper(WizardryBlocks.runestone_pedestal, new StateMap.Builder() + .withName(BlockPedestal.ELEMENT).ignore(BlockPedestal.NATURAL).withSuffix("_runestone_pedestal").build()); // Don't care about NATURAL property + ItemBlockMultiTexturedElemental pedestalItem = (ItemBlockMultiTexturedElemental)Item.getItemFromBlock(WizardryBlocks.runestone_pedestal); + registerMultiTexturedModel(pedestalItem); + + // Items + + registerMultiTexturedModel((ItemCrystal)WizardryItems.magic_crystal); + + registerItemModel(WizardryItems.magic_wand); + registerItemModel(WizardryItems.apprentice_wand); + registerItemModel(WizardryItems.advanced_wand); + registerItemModel(WizardryItems.master_wand); + + registerItemModel(WizardryItems.spell_book); + // Wildcard registered for wizard trades. + registerItemModel(WizardryItems.spell_book, OreDictionary.WILDCARD_VALUE, "normal"); + registerItemModel(WizardryItems.arcane_tome); + registerItemModel(WizardryItems.wizard_handbook); + + registerItemModel(WizardryItems.novice_fire_wand); + registerItemModel(WizardryItems.novice_ice_wand); + registerItemModel(WizardryItems.novice_lightning_wand); + registerItemModel(WizardryItems.novice_necromancy_wand); + registerItemModel(WizardryItems.novice_earth_wand); + registerItemModel(WizardryItems.novice_sorcery_wand); + registerItemModel(WizardryItems.novice_healing_wand); + + registerItemModel(WizardryItems.apprentice_fire_wand); + registerItemModel(WizardryItems.apprentice_ice_wand); + registerItemModel(WizardryItems.apprentice_lightning_wand); + registerItemModel(WizardryItems.apprentice_necromancy_wand); + registerItemModel(WizardryItems.apprentice_earth_wand); + registerItemModel(WizardryItems.apprentice_sorcery_wand); + registerItemModel(WizardryItems.apprentice_healing_wand); + + registerItemModel(WizardryItems.advanced_fire_wand); + registerItemModel(WizardryItems.advanced_ice_wand); + registerItemModel(WizardryItems.advanced_lightning_wand); + registerItemModel(WizardryItems.advanced_necromancy_wand); + registerItemModel(WizardryItems.advanced_earth_wand); + registerItemModel(WizardryItems.advanced_sorcery_wand); + registerItemModel(WizardryItems.advanced_healing_wand); + + registerItemModel(WizardryItems.master_fire_wand); + registerItemModel(WizardryItems.master_ice_wand); + registerItemModel(WizardryItems.master_lightning_wand); + registerItemModel(WizardryItems.master_necromancy_wand); + registerItemModel(WizardryItems.master_earth_wand); + registerItemModel(WizardryItems.master_sorcery_wand); + registerItemModel(WizardryItems.master_healing_wand); + + registerItemModel(WizardryItems.spectral_sword); + registerItemModel(WizardryItems.spectral_pickaxe); + registerItemModel(WizardryItems.spectral_bow); + + registerItemModel(WizardryItems.small_mana_flask); + registerItemModel(WizardryItems.medium_mana_flask); + registerItemModel(WizardryItems.large_mana_flask); + + registerItemModel(WizardryItems.crystal_shard); + registerItemModel(WizardryItems.grand_crystal); + + registerItemModel(WizardryItems.astral_diamond); + + registerItemModel(WizardryItems.purifying_elixir); + + registerItemModel(WizardryItems.storage_upgrade); + registerItemModel(WizardryItems.siphon_upgrade); + registerItemModel(WizardryItems.condenser_upgrade); + registerItemModel(WizardryItems.range_upgrade); + registerItemModel(WizardryItems.duration_upgrade); + registerItemModel(WizardryItems.cooldown_upgrade); + registerItemModel(WizardryItems.blast_upgrade); + registerItemModel(WizardryItems.attunement_upgrade); + registerItemModel(WizardryItems.melee_upgrade); + + registerItemModel(WizardryItems.flaming_axe); + registerItemModel(WizardryItems.frost_axe); + + registerItemModel(WizardryItems.firebomb); + registerItemModel(WizardryItems.poison_bomb); + registerItemModel(WizardryItems.smoke_bomb); + registerItemModel(WizardryItems.spark_bomb); + + registerItemModel(WizardryItems.blank_scroll); + registerItemModel(WizardryItems.scroll); + registerItemModel(WizardryItems.identification_scroll); + + registerItemModel(WizardryItems.armour_upgrade); + + registerItemModel(WizardryItems.magic_silk); + + registerItemModel(WizardryItems.wizard_hat); + registerItemModel(WizardryItems.wizard_robe); + registerItemModel(WizardryItems.wizard_leggings); + registerItemModel(WizardryItems.wizard_boots); + + registerItemModel(WizardryItems.wizard_hat_fire); + registerItemModel(WizardryItems.wizard_robe_fire); + registerItemModel(WizardryItems.wizard_leggings_fire); + registerItemModel(WizardryItems.wizard_boots_fire); + + registerItemModel(WizardryItems.wizard_hat_ice); + registerItemModel(WizardryItems.wizard_robe_ice); + registerItemModel(WizardryItems.wizard_leggings_ice); + registerItemModel(WizardryItems.wizard_boots_ice); + + registerItemModel(WizardryItems.wizard_hat_lightning); + registerItemModel(WizardryItems.wizard_robe_lightning); + registerItemModel(WizardryItems.wizard_leggings_lightning); + registerItemModel(WizardryItems.wizard_boots_lightning); + + registerItemModel(WizardryItems.wizard_hat_necromancy); + registerItemModel(WizardryItems.wizard_robe_necromancy); + registerItemModel(WizardryItems.wizard_leggings_necromancy); + registerItemModel(WizardryItems.wizard_boots_necromancy); + + registerItemModel(WizardryItems.wizard_hat_earth); + registerItemModel(WizardryItems.wizard_robe_earth); + registerItemModel(WizardryItems.wizard_leggings_earth); + registerItemModel(WizardryItems.wizard_boots_earth); + + registerItemModel(WizardryItems.wizard_hat_sorcery); + registerItemModel(WizardryItems.wizard_robe_sorcery); + registerItemModel(WizardryItems.wizard_leggings_sorcery); + registerItemModel(WizardryItems.wizard_boots_sorcery); + + registerItemModel(WizardryItems.wizard_hat_healing); + registerItemModel(WizardryItems.wizard_robe_healing); + registerItemModel(WizardryItems.wizard_leggings_healing); + registerItemModel(WizardryItems.wizard_boots_healing); + + registerItemModel(WizardryItems.spectral_helmet); + registerItemModel(WizardryItems.spectral_chestplate); + registerItemModel(WizardryItems.spectral_leggings); + registerItemModel(WizardryItems.spectral_boots); + + registerItemModel(WizardryItems.lightning_hammer); + + registerItemModel(WizardryItems.ring_condensing); + registerItemModel(WizardryItems.ring_siphoning); + registerItemModel(WizardryItems.ring_battlemage); + registerItemModel(WizardryItems.ring_combustion); + registerItemModel(WizardryItems.ring_fire_melee); + registerItemModel(WizardryItems.ring_fire_biome); + registerItemModel(WizardryItems.ring_disintegration); + registerItemModel(WizardryItems.ring_ice_melee); + registerItemModel(WizardryItems.ring_ice_biome); + registerItemModel(WizardryItems.ring_arcane_frost); + registerItemModel(WizardryItems.ring_shattering); + registerItemModel(WizardryItems.ring_lightning_melee); + registerItemModel(WizardryItems.ring_storm); + registerItemModel(WizardryItems.ring_seeking); + registerItemModel(WizardryItems.ring_hammer); + registerItemModel(WizardryItems.ring_soulbinding); + registerItemModel(WizardryItems.ring_leeching); + registerItemModel(WizardryItems.ring_necromancy_melee); + registerItemModel(WizardryItems.ring_mind_control); + registerItemModel(WizardryItems.ring_poison); + registerItemModel(WizardryItems.ring_earth_melee); + registerItemModel(WizardryItems.ring_earth_biome); + registerItemModel(WizardryItems.ring_full_moon); + registerItemModel(WizardryItems.ring_extraction); + registerItemModel(WizardryItems.ring_mana_return); + registerItemModel(WizardryItems.ring_blockwrangler); + registerItemModel(WizardryItems.ring_conjurer); + registerItemModel(WizardryItems.ring_defender); + registerItemModel(WizardryItems.ring_paladin); + registerItemModel(WizardryItems.ring_interdiction); + + registerItemModel(WizardryItems.amulet_arcane_defence); + registerItemModel(WizardryItems.amulet_warding); + registerItemModel(WizardryItems.amulet_wisdom); + registerItemModel(WizardryItems.amulet_fire_protection); + registerItemModel(WizardryItems.amulet_fire_cloaking); + registerItemModel(WizardryItems.amulet_ice_immunity); + registerItemModel(WizardryItems.amulet_ice_protection); + registerItemModel(WizardryItems.amulet_potential); + registerItemModel(WizardryItems.amulet_channeling); + registerItemModel(WizardryItems.amulet_lich); + registerItemModel(WizardryItems.amulet_wither_immunity); + registerItemModel(WizardryItems.amulet_glide); + registerItemModel(WizardryItems.amulet_banishing); + registerItemModel(WizardryItems.amulet_anchoring); + registerItemModel(WizardryItems.amulet_recovery); + registerItemModel(WizardryItems.amulet_transience); + registerItemModel(WizardryItems.amulet_resurrection); + registerItemModel(WizardryItems.amulet_auto_shield); + + registerItemModel(WizardryItems.charm_haggler); + registerItemModel(WizardryItems.charm_experience_tome); + registerItemModel(WizardryItems.charm_auto_smelt); + registerItemModel(WizardryItems.charm_lava_walking); + registerItemModel(WizardryItems.charm_storm); + registerItemModel(WizardryItems.charm_minion_health); + registerItemModel(WizardryItems.charm_minion_variants); + registerItemModel(WizardryItems.charm_flight); + registerItemModel(WizardryItems.charm_growth); + registerItemModel(WizardryItems.charm_abseiling); + registerItemModel(WizardryItems.charm_silk_touch); + registerItemModel(WizardryItems.charm_stop_time); + registerItemModel(WizardryItems.charm_light); + registerItemModel(WizardryItems.charm_transportation); + registerItemModel(WizardryItems.charm_feeding); + + } + + @SubscribeEvent + public static void bake(ModelBakeEvent event){ + // MMMmmmm I love the smell of freshly-baked models... + // This stuff is the boilerplate for making runestone overlay render with full brightness + // See https://www.minecraftforge.net/forum/topic/66005-how-do-i-make-a-tileentityspecialrenderer-solved-with-ibakedmodel/ + // As usual the Forge documentation is just a description of each class and not an explanation of how to use them + // I had to work out where this goes from the refined storage repo linked in the above thread, which is mixed in + // with a more extensive registration system (which is super neat, but it's overkill for our purposes) + // https://github.com/raoulvdberge/refinedstorage/blob/13d6e7f2b92f41b5009187aa2cbde50dbc72082f/src/main/java/com/raoulvdberge/refinedstorage/proxy/ProxyClient.java#L59 + + for(ModelResourceLocation location : event.getModelRegistry().getKeys()){ + + if(location.getNamespace().equals(Wizardry.MODID)){ + + if(location.getPath().contains("runestone") || location.getPath().contains("runestone_pedestal")){ + IBakedModel original = event.getModelRegistry().getObject(location); + event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "overlay")); + } + } + } + } + + // Moved from the proxies + + /** + * Registers an item model, using the item's registry name as the model name (this convention makes it easier to + * keep track of everything). Variant defaults to "normal". Registers the model for metadata 0 automatically, plus + * all the other metadata values that the item can take, as defined in + * {@link Item#getSubItems(CreativeTabs, NonNullList)}. The creative tab supplied + * to the aforementioned method will be whichever one the item is in. + */ + private static void registerItemModel(Item item){ + + if(item.getHasSubtypes()){ + NonNullList items = NonNullList.create(); + item.getSubItems(item.getCreativeTab(), items); // Client-only method, but we're client-side so this is OK. + for(ItemStack stack : items){ + ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(), + new ModelResourceLocation(item.getRegistryName(), "inventory")); + } + } + // Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why! + ModelLoader.setCustomModelResourceLocation(item, 0, + new ModelResourceLocation(item.getRegistryName(), "inventory")); + } + + /** + * Registers an item model, using the itemstack-sensitive {@link IMultiTexturedItem#getModelName(ItemStack)} as the + * model name. This allows items to change their texture based on metadata/NBT. Variant defaults to "normal". Registers the + * model for metadata 0 automatically, plus all the other metadata values that the item can take, as defined in + * {@link Item#getSubItems(CreativeTabs, NonNullList)}. The creative tab supplied + * to the aforementioned method will be whichever one the item is in. + */ + private static void registerMultiTexturedModel(T item){ + + if(item.getHasSubtypes()){ + NonNullList items = NonNullList.create(); + item.getSubItems(item.getCreativeTab(), items); + for(ItemStack stack : items){ + ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(), + new ModelResourceLocation(item.getModelName(stack), "inventory")); + } + } + } + + /** + * Registers an item model for the given metadata, using the item's registry name as the model name (this convention + * makes it easier to keep track of everything). This is intended for registering additional metadata values which + * aren't displayed in the creative menu, for example the wildcard spell book used in wizard trades. + */ + private static void registerItemModel(Item item, int metadata, String variant){ + ModelLoader.setCustomModelResourceLocation(item, metadata, + new ModelResourceLocation(item.getRegistryName(), variant)); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java index 63548e0b..3e6d3a3f 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java @@ -1,13 +1,12 @@ 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; +import org.lwjgl.opengl.GL11; public class ParticleBeam extends ParticleTargeted { @@ -17,10 +16,15 @@ public class ParticleBeam extends ParticleTargeted { 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.setMaxAge(0); this.particleScale = 1; } - + + @Override + public boolean shouldDisableDepth(){ + return true; + } + @Override public int getFXLayer(){ return 3; @@ -31,7 +35,7 @@ public class ParticleBeam extends ParticleTargeted { float scale = this.particleScale; - if(this.particleMaxAge > 1){ + if(this.particleMaxAge > 0){ float ageFraction = (particleAge + partialTicks - 1)/particleMaxAge; // Squaring this makes it look smoother than a linear shrinking effect scale = this.particleScale * (1 - ageFraction*ageFraction); diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java index 9e9a46d0..a7a8a752 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java @@ -1,26 +1,18 @@ package electroblob.wizardry.client.particle; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.Wizardry; import net.minecraft.client.Minecraft; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.GlStateManager.DestFactor; import net.minecraft.client.renderer.GlStateManager.SourceFactor; -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.util.math.MathHelper; import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class ParticleBuff extends ParticleWizardry { private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/buff.png"); @@ -28,13 +20,19 @@ public class ParticleBuff extends ParticleWizardry { public ParticleBuff(World world, double x, double y, double z){ super(world, x, y, z); - this.setVelocity(0, 0.27, 0); // Approximately what it was before - this.mirror = world.rand.nextBoolean(); + this.setVelocity(0, 0.162, 0); // Approximately what it was before + this.mirror = random.nextBoolean(); this.setMaxAge(15); this.setGravity(false); this.canCollide = false; } - + + @Override + public boolean shouldDisableDepth(){ + return true; + } + + @Override public void onUpdate(){ super.onUpdate(); @@ -59,14 +57,13 @@ public class ParticleBuff extends ParticleWizardry { @Override public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ + + // Copied from ParticleWizardry, needs to be here since we're not calling super + updateEntityLinking(partialTicks); GlStateManager.pushMatrix(); GlStateManager.pushAttrib(); - float scale = 0.6f; - GlStateManager.scale(scale, scale, scale); - if(mirror) GlStateManager.scale(-1, 1, 1); - GlStateManager.enableBlend(); GlStateManager.disableAlpha(); GlStateManager.disableCull(); @@ -94,31 +91,29 @@ public class ParticleBuff extends ParticleWizardry { buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); - // 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); - + // Increases from 0 to 1 in steps of 0.125 evenly throughout the particle's lifetime float f = 0.875f - 0.125f * MathHelper.floor((float)this.particleAge/(float)this.particleMaxAge * 8 - 0.000001f); float g = f + 0.125f; float hrepeat = 1; - float yScale = 0.7f; + float scale = 0.6f; + float yScale = 0.7f * scale; + float dx = mirror ? -scale : scale; + float dz = scale; - buffer.pos(x-1, y-yScale, z-1).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x-1, y+yScale, z-1).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x+1, y-yScale, z-1).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x+1, y+yScale, z-1).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x+1, y-yScale, z+1).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x+1, y+yScale, z+1).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x-1, y-yScale, z+1).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x-1, y+yScale, z+1).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x-1, y-yScale, z-1).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos(x-1, y+yScale, z-1).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-dx, y-yScale, z-dz).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-dx, y+yScale, z-dz).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+dx, y-yScale, z-dz).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+dx, y+yScale, z-dz).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+dx, y-yScale, z+dz).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+dx, y+yScale, z+dz).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-dx, y-yScale, z+dz).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-dx, y+yScale, z+dz).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-dx, y-yScale, z-dz).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-dx, y+yScale, z-dz).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); Tessellator.getInstance().draw(); diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java b/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java index b4bc8710..7558bf89 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleDarkMagic.java @@ -3,10 +3,8 @@ package electroblob.wizardry.client.particle; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.entity.Entity; import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class ParticleDarkMagic extends ParticleWizardry { /** Base spell texture index */ diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java b/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java index 3a7f70fd..cd925b81 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleDust.java @@ -1,10 +1,8 @@ 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) +//@SideOnly(Side.CLIENT) public class ParticleDust extends ParticleWizardry { public ParticleDust(World world, double x, double y, double z){ @@ -24,7 +22,7 @@ public class ParticleDust extends ParticleWizardry { this.prevPosX = this.posX; this.prevPosY = this.posY; this.prevPosZ = this.posZ; - // this.moveEntity(this.motionX, this.motionY, this.motionZ); + this.move(this.motionX, this.motionY, this.motionZ); if(this.particleMaxAge-- <= 0){ this.setExpired(); diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java index a24cd16b..f85bc90c 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java @@ -19,10 +19,15 @@ public class ParticleFlash extends ParticleWizardry { this.particleScale = 0.6f; // 7.1f is the value used in fireworks this.particleMaxAge = 6; } - + @Override - public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ - float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * (float)Math.PI); + public boolean shouldDisableDepth(){ + return true; // Well this fixes everything... let's hope it doesn't cause any side-effects! + } + + @Override + public void drawParticle(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)/particleMaxAge * (float)Math.PI); this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * 0.5F); float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); @@ -34,7 +39,7 @@ public class ParticleFlash extends ParticleWizardry { buffer.pos((double)(f5 - rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 - rotationYZ * f4 + rotationXZ * f4)).tex(0.5D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); buffer.pos((double)(f5 + rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 + rotationYZ * f4 + rotationXZ * f4)).tex(0.25D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); buffer.pos((double)(f5 + rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 + rotationYZ * f4 - rotationXZ * f4)).tex(0.25D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); - } + } @Override public int getBrightnessForRender(float partialTicks){ diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java index bc530448..22a86d18 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java @@ -6,9 +6,8 @@ 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) +//@SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT) public class ParticleIce extends ParticleWizardry { diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java index 327ac57a..07f7c9fb 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java @@ -6,9 +6,8 @@ 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) +//@SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT) public class ParticleLeaf extends ParticleWizardry { @@ -24,7 +23,7 @@ public class ParticleLeaf extends ParticleWizardry { this.particleGravity = 0; this.canCollide = true; // Produces a variety of browns and greens - this.setRBGColorF(0.1f + 0.3f * world.rand.nextFloat(), 0.5f + 0.3f * world.rand.nextFloat(), 0.1f); + this.setRBGColorF(0.1f + 0.3f * random.nextFloat(), 0.5f + 0.3f * random.nextFloat(), 0.1f); } @Override diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java index 80f43088..fc73ff92 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java @@ -1,15 +1,12 @@ 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; +import org.lwjgl.opengl.GL11; public class ParticleLightning extends ParticleTargeted { @@ -28,10 +25,6 @@ public class ParticleLightning extends ParticleTargeted { /** 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(); @@ -39,7 +32,12 @@ public class ParticleLightning extends ParticleTargeted { this.setMaxAge(3); this.particleScale = 1; } - + + @Override + public boolean shouldDisableDepth(){ + return true; + } + @Override public int getFXLayer(){ return 3; @@ -67,7 +65,7 @@ public class ParticleLightning extends ParticleTargeted { // 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); + random.setSeed(this.seed + this.particleAge/UPDATE_PERIOD); // numberOfSegments-1 because the last segment is handled separately. for(int i=0; i this.particleMaxAge/2){ - this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge/2)) / (float)this.particleMaxAge); + this.setAlphaF(1 - ((float)this.particleAge - this.particleMaxAge/2f) / (this.particleMaxAge/2f)); } EnumFacing facing = EnumFacing.fromAngle(yaw); diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java index e5de49f9..b34b3bab 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java @@ -6,9 +6,8 @@ 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) +//@SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT) public class ParticleSnow extends ParticleWizardry { @@ -24,7 +23,7 @@ public class ParticleSnow extends ParticleWizardry { this.canCollide = true; 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); + this.setRBGColorF(0.9f + 0.1f * random.nextFloat(), 0.95f + 0.05f * random.nextFloat(), 1); } @SubscribeEvent diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java index 5d879ad0..7617d450 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java @@ -6,9 +6,8 @@ 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) +//@SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT) public class ParticleSpark extends ParticleWizardry { @@ -25,14 +24,18 @@ public class ParticleSpark extends ParticleWizardry { this.canCollide = false; this.setMaxAge(3); // Lifetime defaults to 3 (and is very unlikely to be changed) } - + + @Override + public boolean shouldDisableDepth(){ + return true; + } + // May no longer be necessary, ParticleManager seems to enable blending now // @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); // } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java index 4aa64a35..812678a2 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java @@ -6,9 +6,8 @@ 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) +//@SideOnly(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT) public class ParticleSparkle extends ParticleWizardry { diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSphere.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSphere.java new file mode 100644 index 00000000..89eaf5a7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSphere.java @@ -0,0 +1,131 @@ +package electroblob.wizardry.client.particle; + +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.entity.Entity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +public class ParticleSphere extends ParticleWizardry { + + public ParticleSphere(World world, double x, double y, double z){ + super(world, x, y, z); + this.setRBGColorF(1, 1, 1); + this.particleMaxAge = 5; + this.particleAlpha = 0.8f; + } + + @Override + public boolean shouldDisableDepth(){ + return true; + } + + @Override + public int getFXLayer(){ + return 3; + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, + float rotationXY, float rotationXZ){ + + // Copied from ParticleWizardry, needs to be here since we're not calling super + updateEntityLinking(partialTicks); + + float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks); + float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks); + float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks); + + GlStateManager.pushMatrix(); + GlStateManager.translate(x - interpPosX, y - interpPosY, z - interpPosZ); + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.enableCull(); + GlStateManager.disableTexture2D(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + float latStep = (float)Math.PI/20; + float longStep = (float)Math.PI/20; + + float sphereRadius = this.particleScale * (this.particleAge + partialTicks - 1) / this.particleMaxAge; + float alpha = this.particleAlpha * (1 - (this.particleAge + partialTicks - 1) / this.particleMaxAge); + + drawSphere(Tessellator.getInstance(), buffer, sphereRadius, latStep, longStep, true, particleRed, particleGreen, particleBlue, alpha); + drawSphere(Tessellator.getInstance(), buffer, sphereRadius, latStep, longStep, false, particleRed, particleGreen, particleBlue, alpha); + + GlStateManager.enableTexture2D(); + GlStateManager.enableLighting(); + GlStateManager.disableCull(); + GlStateManager.disableBlend(); + + GlStateManager.popMatrix(); + + } + + @Override + public int getBrightnessForRender(float partialTicks){ + return 15728880; + } + + /** + * Draws a sphere (using lat/long triangles) with the given parameters. + * @param radius The radius of the sphere. + * @param latStep The latitude step; smaller is smoother but increases performance cost. + * @param longStep The longitude step; smaller is smoother but increases performance cost. + * @param inside Whether to draw the outside or the inside of the sphere. + * @param r The red component of the sphere colour. + * @param g The green component of the sphere colour. + * @param b The blue component of the sphere colour. + * @param a The alpha component of the sphere colour. + */ + private static void drawSphere(Tessellator tessellator, BufferBuilder buffer, float radius, float latStep, float longStep, boolean inside, float r, float g, float b, float a){ + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); + + boolean goingUp = inside; + + buffer.pos(0, goingUp ? -radius : radius, 0).color(r, g, b, a).endVertex(); // Start at the north pole + + for(float longitude = -(float)Math.PI; longitude <= (float)Math.PI; longitude += longStep){ + + // Leave the poles out since they only have a single point per stack instead of two + for(float theta = (float)Math.PI/2 - latStep; theta >= -(float)Math.PI/2 + latStep; theta -= latStep){ + + float latitude = goingUp ? -theta : theta; + + float hRadius = radius * MathHelper.cos(latitude); + float vy = radius * MathHelper.sin(latitude); + float vx = hRadius * MathHelper.sin(longitude); + float vz = hRadius * MathHelper.cos(longitude); + + buffer.pos(vx, vy, vz).color(r, g, b, a).endVertex(); + + vx = hRadius * MathHelper.sin(longitude + longStep); + vz = hRadius * MathHelper.cos(longitude + longStep); + + buffer.pos(vx, vy, vz).color(r, g, b, a).endVertex(); + } + + // The next pole + buffer.pos(0, goingUp ? radius : -radius, 0).color(r, g, b, a).endVertex(); + + goingUp = !goingUp; + } + + tessellator.draw(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSummon.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSummon.java new file mode 100644 index 00000000..55daba3e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSummon.java @@ -0,0 +1,132 @@ +package electroblob.wizardry.client.particle; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +//@SideOnly(Side.CLIENT) +public class ParticleSummon extends ParticleWizardry { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/summon.png"); + private final boolean mirror; + + public ParticleSummon(World world, double x, double y, double z){ + super(world, x, y, z); + this.mirror = random.nextBoolean(); + this.setMaxAge(10); + this.setGravity(false); + this.canCollide = false; + } + +// @Override +// public void onUpdate(){ +// super.onUpdate(); +// if(this.particleAge > this.particleMaxAge/2) this.particleAlpha = 2f - 2f*(float)this.particleAge/(float)this.particleMaxAge; +// } + + /* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png + * to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the + * render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine + * for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was + * presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning + * you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten + * anyway since they bind their own textures. It is of course important to bind the texture every time you render a + * custom particle, but I don't see how you could do it any other way, since you don't have access to + * EffectRenderer. */ + @Override + public int getFXLayer(){ + // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. + return 3; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, + float rotationYZ, float rotationXY, float rotationXZ){ + + // Copied from ParticleWizardry, needs to be here since we're not calling super + updateEntityLinking(partialTicks); + + GlStateManager.pushMatrix(); + GlStateManager.pushAttrib(); + + float scale = 0.6f; + GlStateManager.scale(scale, scale, scale); + if(mirror) GlStateManager.scale(-1, 1, 1); + + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.disableCull(); + GlStateManager.disableLighting(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + // Makes the particle colour add to the colour of the texture pixels, rather than the default multiplying + GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_ADD); + + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); + + // Does the texture translation wrapping thing (the cool stuff) +// GlStateManager.matrixMode(GL11.GL_TEXTURE); +// GlStateManager.loadIdentity(); +// +// GlStateManager.translate((this.particleAge + partialTicks)/(float)this.particleMaxAge * -2, 0, 0); +// +// GlStateManager.matrixMode(GL11.GL_MODELVIEW); + + RenderHelper.disableStandardItemLighting(); + + Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE); + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); + + 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); + + // Increases from 0 to 1 in steps of 0.125 evenly throughout the particle's lifetime + float f = 0.125f * MathHelper.floor((float)this.particleAge/(float)this.particleMaxAge * 8 - 0.000001f); + float g = f + 0.125f; + float hrepeat = 1; + float yScale = 3f; + + this.setRBGColorF(1, 1, 1); + + buffer.pos(x-1, y, z-1).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y+yScale, z-1).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+1, y, z-1).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+1, y+yScale, z-1).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+1, y, z+1).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x+1, y+yScale, z+1).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y, z+1).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y+yScale, z+1).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y, z-1).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + buffer.pos(x-1, y+yScale, z-1).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); + + Tessellator.getInstance().draw(); + + // Undoes the texture transformations +// GlStateManager.matrixMode(GL11.GL_TEXTURE); +// GlStateManager.loadIdentity(); +// GlStateManager.matrixMode(GL11.GL_MODELVIEW); + + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.enableCull(); + GlStateManager.enableLighting(); + // Reverses the colour addition change from before + GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE); + + GlStateManager.popAttrib(); + GlStateManager.popMatrix(); + + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java b/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java index 80ce3e59..cd89d0af 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java @@ -1,23 +1,28 @@ 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.util.math.Vec3d; import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +import javax.annotation.Nullable; /** 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; + protected double targetVelX; + protected double targetVelY; + protected double targetVelZ; + + protected double length; /** The target this particle is linked to. The particle will stretch to touch this entity. */ @Nullable @@ -33,43 +38,83 @@ public abstract class ParticleTargeted extends ParticleWizardry { this.targetY = y; this.targetZ = z; } + + @Override + public void setTargetVelocity(double vx, double vy, double vz){ + this.targetVelX = vx; + this.targetVelY = vy; + this.targetVelZ = vz; + } @Override public void setTargetEntity(Entity target){ this.target = target; } - + + @Override + public void setLength(double length){ + this.length = length; + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(!Double.isNaN(targetVelX) && !Double.isNaN(targetVelY) && !Double.isNaN(targetVelZ)){ + this.targetX += this.targetVelX; + this.targetY += this.targetVelY; + this.targetZ += this.targetVelZ; + } + } + @Override public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ - + + // Copied from ParticleWizardry, needs to be here since we're not calling super + updateEntityLinking(partialTicks); + + float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks); + float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks); + float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks); + if(this.target != null){ - this.targetX = this.target.posX; - this.targetY = this.target.getEntityBoundingBox().minY + target.height/2; - this.targetZ = this.target.posZ; + + this.targetX = this.target.prevPosX + (this.target.posX - this.target.prevPosX) * partialTicks; + double correction = this.target.getEntityBoundingBox().minY - this.target.posY; + this.targetY = this.target.prevPosY + (this.target.posY - this.target.prevPosY) * partialTicks + + target.height/2 + correction; + this.targetZ = this.target.prevPosZ + (this.target.posZ - this.target.prevPosZ) * partialTicks; + + }else if(this.entity != null && this.length > 0){ + + Vec3d look = entity.getLook(partialTicks).scale(length); + this.targetX = x + look.x; + this.targetY = y + look.y; + this.targetZ = z + look.z; } 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!"); + + "position was set, and it either had no length assigned or was not linked to an entity!"); 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); + GlStateManager.translate(x - interpPosX, y - interpPosY, z - interpPosZ); - double dx = this.targetX - this.posX; - double dy = this.targetY - this.posY; - double dz = this.targetZ - this.posZ; + double dx = this.targetX - x; + double dy = this.targetY - y; + double dz = this.targetZ - z; + + // No need for previous tick target positions and all that stuff since this is the only place they're used + // and interpolating like this works just as well + if(!Double.isNaN(targetVelX) && !Double.isNaN(targetVelY) && !Double.isNaN(targetVelZ)){ + dx += partialTicks * this.targetVelX; + dy += partialTicks * this.targetVelY; + dz += partialTicks * this.targetVelZ; + } // The distance from origin to endpoint double length = Math.sqrt(dx*dx+dy*dy+dz*dz); @@ -87,12 +132,12 @@ public abstract class ParticleTargeted extends ParticleWizardry { GlStateManager.popMatrix(); } - + /** Called from {@link ParticleTargeted#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)}, * once the appropriate calculations and transformations have been applied, to actually render the particle. Subclasses * override this instead of overriding {@code renderParticle} directly, and inside render the particle along * the z-axis, starting at (0, 0, 0) - it will be translated and rotated automatically. - *

    + *

    * N.B. Other than transformations, no GL state changes are applied; these should be done within this method. * * @param tessellator A reference to the tessellator, for convenience. diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleTornado.java b/src/main/java/electroblob/wizardry/client/particle/ParticleTornado.java index 8887e503..8dab58fa 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleTornado.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleTornado.java @@ -3,14 +3,13 @@ package electroblob.wizardry.client.particle; import net.minecraft.block.state.IBlockState; import net.minecraft.client.particle.ParticleDigging; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class ParticleTornado extends ParticleDigging { - private double angle; + private float angle; private double radius; private double speed; /** Velocity of the tornado itself; in other words the velocity of the point the particle circles around. */ @@ -20,9 +19,9 @@ public class ParticleTornado extends ParticleDigging { public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos, double velX, double velZ, IBlockState block){ super(world, 0, 0, 0, 0, 0, 0, block); - this.angle = this.rand.nextDouble() * Math.PI * 2; - double x = originX - Math.cos(angle) * radius; - double z = originZ + radius * Math.sin(angle); + float angle = this.rand.nextFloat() * (float)Math.PI * 2; + double x = originX - MathHelper.cos(angle) * radius; + double z = originZ + radius * MathHelper.sin(angle); this.radius = radius; this.setPosition(x, yPos, z); this.prevPosX = x; @@ -66,8 +65,8 @@ public class ParticleTornado extends ParticleDigging { // v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi. this.angle += omega; - this.motionZ = radius * omega * Math.cos(angle); - this.motionX = radius * omega * Math.sin(angle); + this.motionZ = radius * omega * MathHelper.cos(angle); + this.motionX = radius * omega * MathHelper.sin(angle); this.move(motionX + velX, 0, motionZ + velZ); if(this.particleAge > this.particleMaxAge / 2){ diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleVine.java b/src/main/java/electroblob/wizardry/client/particle/ParticleVine.java new file mode 100644 index 00000000..79c9d872 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleVine.java @@ -0,0 +1,154 @@ +package electroblob.wizardry.client.particle; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.Minecraft; +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.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import org.lwjgl.opengl.GL11; + +//@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleVine extends ParticleTargeted { + + /** Half the width of the vine. */ + private static final float THICKNESS = 0.02f; + private static final float LEAF_SPACING = 0.5f; + private static final float SEGMENT_LENGTH = 1; + + private static final ResourceLocation STEM_TEXTURE = new ResourceLocation(Wizardry.MODID, "particle/vine"); + private static final ResourceLocation[] LEAF_TEXTURES = generateTextures("vine_leaf", 5); + + public ParticleVine(World world, double x, double y, double z){ + super(world, x, y, z, STEM_TEXTURE); + //this.setRBGColorF(1, 1, 1); + this.setMaxAge(0); + this.particleScale = 1; + this.setRBGColorF(0.2f, 0.65f, 0f); + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ + // When using FX layer 1 the BufferBuilder is already drawing... but in the wrong mode :/ + Tessellator.getInstance().draw(); + super.renderParticle(buffer, viewer, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + } + + @Override + protected void draw(Tessellator tessellator, double length, float partialTicks){ + + random.setSeed(seed); // Reset the random so we get the same sequence of numbers each frame + + float scale = this.particleScale; + + BufferBuilder buffer = tessellator.getBuffer(); + + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + // Hmmmm we can't get the texture to tile using OpenGL texture space because it's on a sprite sheet... + // Solution: Draw loads of boxes. Simple! + // (Since there aren't going to be that many of these particles around we could have not used sprite sheets + // and done the OpenGL texture space thing, but this is kinda easier) + // Everything is drawn back-to-front so it looks like the vine is growing from the origin, not the endpoint + int i = 0; + while(i + SEGMENT_LENGTH < length){ + drawShearedBox(tessellator, 0, 0, length-i, 0, 0, length-i-SEGMENT_LENGTH, THICKNESS * scale, + particleRed, particleGreen, particleBlue, particleAlpha); + i += SEGMENT_LENGTH; + } + + drawShearedBox(tessellator, 0, 0, length-i, 0, 0, 0, THICKNESS * scale, + particleRed, particleGreen, particleBlue, particleAlpha); + + for(double l=length; l>0; l-=LEAF_SPACING){ + + GlStateManager.pushMatrix(); + + GlStateManager.rotate(random.nextInt(4) * 90, 0, 0, 1); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); + + TextureAtlasSprite leaf = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( + LEAF_TEXTURES[random.nextInt(LEAF_TEXTURES.length)].toString()); + + float w = 16 * THICKNESS * scale; + float u1 = leaf.getMinU(); + float u2 = leaf.getMaxU(); + float v1 = leaf.getMinV(); + float v2 = leaf.getMaxV(); + + float colourVariation = 0.3f; + + float r = MathHelper.clamp(particleRed + (random.nextFloat() - 0.5f) * colourVariation, 0, 1); + float g = MathHelper.clamp(particleGreen + (random.nextFloat() - 0.5f) * colourVariation, 0, 1); + float b = MathHelper.clamp(particleBlue + (random.nextFloat() - 0.5f) * colourVariation, 0, 1); + + buffer.pos(0, 0, l).tex(u1, v1).color(r, g, b, particleAlpha).endVertex(); + buffer.pos(w, 0, l).tex(u2, v1).color(r, g, b, particleAlpha).endVertex(); + buffer.pos(w, w, l).tex(u2, v2).color(r, g, b, particleAlpha).endVertex(); + buffer.pos(0, w, l).tex(u1, v2).color(r, g, b, particleAlpha).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + } + + // Makes the rain go weird + //GlStateManager.enableLighting(); + } + + /** 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(Tessellator tessellator, double x1, double y1, double z1, double x2, double y2, double z2, float width, float r, float g, float b, float a){ + + float u1 = particleTexture.getMinU(); + float u2 = u1 + (particleTexture.getMaxU() - u1) * (float)(z1-z2)/SEGMENT_LENGTH; + float v1 = particleTexture.getMinV(); + float dv = particleTexture.getMaxV() - v1; + // width * 8 gives the total 'circumference' of the box + float v2 = v1 + dv * 0.0625f; + float v3 = v1 + dv * 0.125f; + float v4 = v1 + dv * 0.1875f; + float v5 = v1 + dv * 0.25f; + + BufferBuilder buffer = tessellator.getBuffer(); + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); + + buffer.pos(x1-width, y1-width, z1).tex(u1, v1).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2-width, z2).tex(u2, v1).color(r, g, b, a).endVertex(); + buffer.pos(x1-width, y1+width, z1).tex(u1, v2).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2+width, z2).tex(u2, v2).color(r, g, b, a).endVertex(); + buffer.pos(x1+width, y1+width, z1).tex(u1, v3).color(r, g, b, a).endVertex(); + buffer.pos(x2+width, y2+width, z2).tex(u2, v3).color(r, g, b, a).endVertex(); + buffer.pos(x1+width, y1-width, z1).tex(u1, v4).color(r, g, b, a).endVertex(); + buffer.pos(x2+width, y2-width, z2).tex(u2, v4).color(r, g, b, a).endVertex(); + buffer.pos(x1-width, y1-width, z1).tex(u1, v5).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2-width, z2).tex(u2, v5).color(r, g, b, a).endVertex(); + + tessellator.draw(); + } + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + + event.getMap().registerSprite(STEM_TEXTURE); + + for(ResourceLocation texture : LEAF_TEXTURES){ + event.getMap().registerSprite(texture); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java b/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java index 62f96e7f..1172bb34 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java @@ -1,35 +1,41 @@ package electroblob.wizardry.client.particle; -import java.util.Arrays; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.ClientProxy; +import electroblob.wizardry.entity.ICustomHitbox; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.client.Minecraft; import net.minecraft.client.particle.Particle; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + /** * Abstract superclass for all of wizardry's particles. This replaces {@code ParticleCustomTexture} (the functionality of * which is no longer necessary since wizardry now uses {@code TextureAtlasSprite}s to do the rendering), and fits into * {@code ParticleBuilder} by exposing all the necessary variables through getters, allowing them to be set on the fly * rather than needing to be passed into the constructor. - *

    + *

    * The new system is as follows: - *

    + *

    * - All particle classes have a single constructor which takes a world and a position only.
    * - Each particle class defines any relevant default values in its constructor, including velocity.
    * - The particle builder then overwrites any other values that were set during building. - *

    + *

    * This beauty of this system is that there are never any redundant parameters when spawning particles, 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 @@ -39,12 +45,24 @@ import net.minecraftforge.fml.relauncher.SideOnly; * @since Wizardry 4.2.0 * @see electroblob.wizardry.util.ParticleBuilder ParticleBuilder */ -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public abstract class ParticleWizardry extends Particle { /** Implementation of animated particles using the TextureAtlasSprite system. Why vanilla doesn't support this I * don't know, considering it too has animated particles. */ protected final TextureAtlasSprite[] sprites; + + /** A long value used by the renderer as a random number seed, ensuring anything that is randomised remains the + * same across multiple frames. For example, lightning particles use this to keep their shape across ticks. + * This value can also be set during particle creation, allowing users to keep randomised properties the same + * even across multiple particles. If unspecified, the seed is chosen at random. */ + protected long seed; + /** This particle's random number generator. All particles should use this in preference to any other random + * instance (like random), even if it isn't actually necessary to keep properties across frames. Note that + * if you do need to generate the same sequence of random numbers each frame, you must call + * {@code random.setSeed(seed)} from the {@link ParticleWizardry#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)} + * method - this is not done automatically. */ + protected Random random = new Random(); // If we're not using a seed, this defaults to any old seed /** True if the particle is shaded, false if the particle always renders at full brightness. Defaults to false. */ protected boolean shaded = false; @@ -64,12 +82,12 @@ public abstract class ParticleWizardry extends Particle { /** 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. */ + /** Coordinates of this particle relative to the linked entity. If the linked entity is null, these are used as + * the absolute coordinates of the centre of rotation for particles with spin. If the particle has neither a + * linked entity nor spin, 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; + /** Velocity of this particle relative to the linked entity. If the linked entity is null, these are not used. */ + protected double relativeMotionX, relativeMotionY, relativeMotionZ; // 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). */ @@ -77,6 +95,14 @@ public abstract class ParticleWizardry extends Particle { /** The pitch angle this particle is facing, or {@code NaN} if this particle always faces the viewer (default behaviour). */ protected float pitch = Float.NaN; + /** The fraction of the impact velocity that should be the maximum spread speed added on impact. */ + private static final double SPREAD_FACTOR = 0.2; + /** Lateral velocity is reduced by this factor on impact, before adding random spread velocity. */ + private static final double IMPACT_FRICTION = 0.2; + + /** Previous-tick velocity, used in collision detection. */ + private double prevVelX, prevVelY, prevVelZ; + /** * 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). @@ -108,7 +134,6 @@ public abstract class ParticleWizardry extends Particle { this.setParticleTexture(sprites[0]); }else{ - sprites = new TextureAtlasSprite[0]; } } @@ -117,6 +142,15 @@ public abstract class ParticleWizardry extends Particle { // Setters for parameters that affect all particles - these are implemented in this class (although they may be // reimplemented in subclasses) + + /** Sets the seed for this particle's randomly generated values and resets {@link ParticleWizardry#random} to use + * that seed. Implementations will differ between particle types; for example, ParticleLightning has an update + * period which changes the seed every few ticks, whereas ParticleVine simply retains the same seed for its entire + * lifetime. */ + public void setSeed(long seed){ + this.seed = seed; + this.random = new Random(seed); + } /** 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.*/ @@ -154,13 +188,10 @@ public abstract class ParticleWizardry extends Particle { 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? + this.angle = this.rand.nextFloat() * (float)Math.PI * 2; // Random start angle // 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; + this.posX = relativeX - radius * MathHelper.cos(angle); + this.posZ = relativeZ + radius * MathHelper.sin(angle); // Set these to the correct values this.relativeMotionX = motionX; this.relativeMotionY = motionY; @@ -180,6 +211,7 @@ public abstract class ParticleWizardry extends Particle { this.prevPosX = this.posX; this.prevPosY = this.posY; this.prevPosZ = this.posZ; + // Set these to the correct values this.relativeMotionX = motionX; this.relativeMotionY = motionY; this.relativeMotionZ = motionZ; @@ -218,7 +250,7 @@ public abstract class ParticleWizardry extends Particle { /** * 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 yaw The yaw angle of this particle in degrees, where 0 is south. * @param pitch The pitch angle of this particle in degrees, where 0 is horizontal. */ public void setFacing(float yaw, float pitch){ @@ -239,6 +271,18 @@ public abstract class ParticleWizardry extends Particle { public void setTargetPosition(double x, double y, double z){ // Does nothing for normal particles since normal particles always render at a single point } + + /** + * Sets the target point velocity for this particle. This will cause the position it stretches to touch to move + * at the given velocity. Has no effect unless {@link ParticleWizardry#setTargetVelocity(double, double, double)} + * is also used. + * @param vx The x velocity of the target point. + * @param vy The y velocity of the target point. + * @param vz The z velocity of the target point. + */ + public void setTargetVelocity(double vx, double vy, double vz){ + // 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. @@ -247,6 +291,15 @@ public abstract class ParticleWizardry extends Particle { public void setTargetEntity(Entity target){ // Does nothing for normal particles since normal particles always render at a single point } + + /** + * Sets the length of this particle. This will cause it to stretch to touch a point this distance along its + * linked entity's line of sight. + * @param length The length to set. + */ + public void setLength(double length){ + // Does nothing for normal particles since normal particles always render at a single point + } // ============================================== Method Overrides ============================================== @@ -278,15 +331,16 @@ public abstract class ParticleWizardry extends Particle { * @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}. */ + // Fun fact: unlike entities, particles don't seem to bother checking the camera frustum... @Override public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float lookZ, float lookY, float lookX, float lookXY, float lookYZ){ + + updateEntityLinking(partialTicks); 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); - + drawParticle(buffer, viewer, partialTicks, lookZ, lookY, lookX, lookXY, lookYZ); }else{ // Specific rotation @@ -302,7 +356,25 @@ public abstract class ParticleWizardry extends Particle { float rotationYZ = -rotationZ * MathHelper.sin(pitch * degToRadFactor); float rotationXY = rotationX * MathHelper.sin(pitch * degToRadFactor); - super.renderParticle(buffer, viewer, partialTicks, rotationX, rotationY, rotationZ, rotationYZ, rotationXY); + drawParticle(buffer, viewer, partialTicks, rotationX, rotationY, rotationZ, rotationYZ, rotationXY); + } + } + + /** + * Delegate function for {@link ParticleWizardry#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)}; + * does the actual rendering. Subclasses should override this method instead of renderParticle. By default, this + * method simply calls super.renderParticle. + */ + protected void drawParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationY, float rotationZ, float rotationYZ, float rotationXY){ + super.renderParticle(buffer, viewer, partialTicks, rotationX, rotationY, rotationZ, rotationYZ, rotationXY); + } + + protected void updateEntityLinking(float partialTicks){ + if(this.entity != null){ + // This is kind of cheating but we know it's always a constant velocity so it works fine + prevPosX = posX + entity.prevPosX - entity.posX - relativeMotionX * (1-partialTicks); + prevPosY = posY + entity.prevPosY - entity.posY - relativeMotionY * (1-partialTicks); + prevPosZ = posZ + entity.prevPosZ - entity.posZ - relativeMotionZ * (1-partialTicks); } } @@ -310,38 +382,43 @@ public abstract class ParticleWizardry extends Particle { public void onUpdate(){ super.onUpdate(); - - // If any of these values is NaN, the particle has neither an entity nor a spin - if(!Double.isNaN(relativeMotionX) && !Double.isNaN(relativeMotionY) && !Double.isNaN(relativeMotionZ)){ - - // This allows velocity changes from entity linking and spin to stack - double vx = relativeMotionX; - double vy = relativeMotionY; - double vz = relativeMotionZ; + + if(this.canCollide && this.onGround){ + // I reject your friction and substitute my own! + this.motionX /= 0.699999988079071D; + this.motionZ /= 0.699999988079071D; + } + + if(entity != null || radius > 0){ + + double x = relativeX; + double y = relativeY; + double z = relativeZ; // 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; + if(this.entity.isDead){ + this.setExpired(); + }else{ + x += this.entity.posX; + y += this.entity.posY; + z += this.entity.posZ; + } } // Spin if(radius > 0){ angle += speed; - vx += radius * speed * MathHelper.sin(angle); - vz += radius * speed * MathHelper.cos(angle); + // If the particle has spin, x/z relative position is used as centre and coords are changed each tick + x += radius * -MathHelper.cos(angle); + z += radius * MathHelper.sin(angle); } - - this.relativeX += vx; - this.relativeY += vy; - this.relativeZ += vz; + + this.setPosition(x, y, z); + + this.relativeX += relativeMotionX; + this.relativeY += relativeMotionY; + this.relativeZ += relativeMotionZ; } // Colour fading @@ -357,8 +434,96 @@ public abstract class ParticleWizardry extends Particle { // (which would probably otherwise happen if particleAge == particleMaxAge) this.setParticleTexture(sprites[Math.min((int)(ageFraction * sprites.length), sprites.length - 1)]); } + + // Collision spreading + if(canCollide){ + + if(this.motionX == 0 && this.prevVelX != 0){ // If the particle just collided in x + // Reduce lateral velocity so the added spread speed actually has an effect + this.motionY *= IMPACT_FRICTION; + this.motionZ *= IMPACT_FRICTION; + // Add random velocity in y and z proportional to the impact velocity + this.motionY += (rand.nextDouble()*2 - 1) * this.prevVelX * SPREAD_FACTOR; + this.motionZ += (rand.nextDouble()*2 - 1) * this.prevVelX * SPREAD_FACTOR; + } + + if(this.motionY == 0 && this.prevVelY != 0){ // If the particle just collided in y + // Reduce lateral velocity so the added spread speed actually has an effect + this.motionX *= IMPACT_FRICTION; + this.motionZ *= IMPACT_FRICTION; + // Add random velocity in x and z proportional to the impact velocity + this.motionX += (rand.nextDouble()*2 - 1) * this.prevVelY * SPREAD_FACTOR; + this.motionZ += (rand.nextDouble()*2 - 1) * this.prevVelY * SPREAD_FACTOR; + } + + if(this.motionZ == 0 && this.prevVelZ != 0){ // If the particle just collided in z + // Reduce lateral velocity so the added spread speed actually has an effect + this.motionX *= IMPACT_FRICTION; + this.motionY *= IMPACT_FRICTION; + // Add random velocity in x and y proportional to the impact velocity + this.motionX += (rand.nextDouble()*2 - 1) * this.prevVelZ * SPREAD_FACTOR; + this.motionY += (rand.nextDouble()*2 - 1) * this.prevVelZ * SPREAD_FACTOR; + } + + double searchRadius = 20; + + List nearbyEntities = WizardryUtilities.getEntitiesWithinRadius(searchRadius, this.posX, + this.posY, this.posZ, world, Entity.class); + + nearbyEntities.removeIf(e -> !(e instanceof ICustomHitbox && ((ICustomHitbox)e).contains(new Vec3d(this.posX, this.posY, this.posZ)))); + + if(nearbyEntities.size() > 0) this.setExpired(); + + } + + this.prevVelX = motionX; + this.prevVelY = motionY; + this.prevVelZ = motionZ; } - + + // Overridden and copied to fix the collision behaviour + @Override + public void move(double x, double y, double z){ + + double origY = y; + double origX = x; + double origZ = z; + + if(this.canCollide){ + + List list = this.world.getCollisionBoxes(null, this.getBoundingBox().expand(x, y, z)); + + for(AxisAlignedBB axisalignedbb : list){ + y = axisalignedbb.calculateYOffset(this.getBoundingBox(), y); + } + + this.setBoundingBox(this.getBoundingBox().offset(0.0D, y, 0.0D)); + + for(AxisAlignedBB axisalignedbb1 : list){ + x = axisalignedbb1.calculateXOffset(this.getBoundingBox(), x); + } + + this.setBoundingBox(this.getBoundingBox().offset(x, 0.0D, 0.0D)); + + for(AxisAlignedBB axisalignedbb2 : list){ + z = axisalignedbb2.calculateZOffset(this.getBoundingBox(), z); + } + + this.setBoundingBox(this.getBoundingBox().offset(0.0D, 0.0D, z)); + + }else{ + this.setBoundingBox(this.getBoundingBox().offset(x, y, z)); + } + + this.resetPositionToBB(); + this.onGround = origY != y && origY < 0.0D; + + if(origX != x) this.motionX = 0.0D; + if(origY != y) this.motionY = 0.0D; // Why doesn't Particle do this for y? + if(origZ != z) this.motionZ = 0.0D; + } + + // =============================================== Helper Methods =============================================== /** Static helper method that generates an array of n ResourceLocations using the particle file naming convention, @@ -390,6 +555,21 @@ public abstract class ParticleWizardry extends Particle { return textures; } + /** + * Associates the given {@link ResourceLocation} with the given {@link IWizardryParticleFactory}, allowing it to + * be used in the {@link electroblob.wizardry.util.ParticleBuilder ParticleBuilder}. This is a similar concept to + * registering entity renderers, in that it associates the client-only bit with its common-code counterpart - but + * of course, particles are client-side only so a simple identifier is all that is necessary. As with entity + * renderers, this method may only be called from the client side, probably a client proxy. + * @param name The {@link ResourceLocation} to use for the particle. This effectively replaces the particle type + * enum from previous versions. Keep a reference to this somewhere in common code for use later. + * @param factory A {@link IWizardryParticleFactory} that produces your particle. A constructor reference is usually + * sufficient. + */ + public static void registerParticle(ResourceLocation name, IWizardryParticleFactory factory){ + ClientProxy.addParticleFactory(name, factory); + } + /** 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) diff --git a/src/main/java/electroblob/wizardry/client/renderer/LayerFrost.java b/src/main/java/electroblob/wizardry/client/renderer/LayerFrost.java new file mode 100644 index 00000000..ae8536dd --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/LayerFrost.java @@ -0,0 +1,153 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockStatue; +import electroblob.wizardry.registry.WizardryPotions; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelBiped; +import net.minecraft.client.model.ModelPlayer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderLivingBase; +import net.minecraft.client.renderer.entity.RenderPlayer; +import net.minecraft.client.renderer.entity.layers.LayerRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.opengl.GL11; + +/** + * Layer used to render the frost texture on a creature with the frostbite effect. Handles dynamic tiling of the texture. + * + * @author Electroblob + * @since Wizardry 1.2 + */ +public class LayerFrost implements LayerRenderer { + + protected ModelBase model; + private final RenderLivingBase renderer; + + private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/frost_overlay.png"); + + public static void initialiseLayers(){ + + for(Render renderer : Minecraft.getMinecraft().getRenderManager().entityRenderMap.values()){ + // Because the zombie classes are now split properly, their renderers play nicely like everything else. + if(renderer instanceof RenderLivingBase){ + // Adds a frost layer to all the living entity renderers in the game. Whether it is actually rendered + // is decided in doRenderLayer below on a per-entity basis. + ((RenderLivingBase)renderer).addLayer(new LayerFrost((RenderLivingBase)renderer)); + } + } + + for(RenderPlayer renderer : Minecraft.getMinecraft().getRenderManager().getSkinMap().values()){ + renderer.addLayer(new LayerFrost(renderer)); + } + } + + public LayerFrost(RenderLivingBase renderer){ + this.renderer = renderer; + this.model = renderer.getMainModel(); + } + + @Override + public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, + float ageInTicks, float netHeadYaw, float headPitch, float scale){ + + if(entity.isPotionActive(WizardryPotions.frost) || entity.getEntityData().getBoolean(BlockStatue.FROZEN_NBT_KEY)){ + + GlStateManager.enableLighting(); + int i = this.getBlockBrightnessForEntity(entity, partialTicks); + + int j = i % 65536; + int k = i / 65536; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); + + // Frost texture + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + this.renderer.bindTexture(texture); + this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, + headPitch, scale); + GlStateManager.disableBlend(); + + } + } + + private int getBlockBrightnessForEntity(Entity entity, float partialTicks){ + + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(MathHelper.floor(entity.posX), 0, + MathHelper.floor(entity.posZ)); + + if(entity.world.isBlockLoaded(pos)){ + pos.setY(MathHelper.floor(entity.posY + (double)entity.getEyeHeight())); + return entity.world.getCombinedLight(pos, 0); + }else{ + return 0; + } + } + + private void renderEntityModel(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, + float ageInTicks, float netHeadYaw, float headPitch, float scale){ + + GlStateManager.pushMatrix(); + // Enables tiling (Also used for guardian beam, beacon beam and ender crystal beam) + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); + + GlStateManager.depthMask(true); // Some entities set depth mask to false (i.e. no sorting of faces by depth) + // In particular, LayerSpiderEyes sets it to false when the spider is invisible, for some reason. + + // Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example, + // but with translation instead of scaling. + // NOTE: You can do all sorts of fun stuff with this, just by applying transformations in the 2D texture space. + GlStateManager.matrixMode(GL11.GL_TEXTURE); + GlStateManager.loadIdentity(); + double scaleX = 1, scaleY = 1; + // It's more logical to use the model's texture size, but some classes don't bother setting it properly + // (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead. + if(model.boxList != null && model.boxList.get(0) != null){ + scaleX = (double)model.boxList.get(0).textureWidth / 16d; + scaleY = (double)model.boxList.get(0).textureHeight / 16d; + }else{ // Fallback to model fields; should never be needed + scaleX = (double)model.textureWidth / 16d; + scaleY = (double)model.textureHeight / 16d; + } + GlStateManager.scale(scaleX, scaleY, 1); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + + // Hides the hat layer for bipeds + if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = true; + + if(this.model instanceof ModelPlayer){ + ((ModelPlayer)this.model).bipedBodyWear.isHidden = true; + ((ModelPlayer)this.model).bipedLeftArmwear.isHidden = true; + ((ModelPlayer)this.model).bipedRightArmwear.isHidden = true; + ((ModelPlayer)this.model).bipedLeftLegwear.isHidden = true; + ((ModelPlayer)this.model).bipedRightLegwear.isHidden = true; + } + + this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks); + this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); + + if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = false; + + // Undoes the texture scaling + GlStateManager.matrixMode(GL11.GL_TEXTURE); + GlStateManager.loadIdentity(); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + + GlStateManager.popMatrix(); + } + + @Override + public boolean shouldCombineTextures(){ + return false; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java b/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java index 7978e26e..ed1d5669 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java +++ b/src/main/java/electroblob/wizardry/client/renderer/LayerStone.java @@ -1,9 +1,5 @@ package electroblob.wizardry.client.renderer; -import java.util.Map.Entry; - -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.client.ClientProxy; import net.minecraft.client.Minecraft; @@ -21,6 +17,7 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; +import org.lwjgl.opengl.GL11; /** * Layer used to render the stone texture on a petrified creature. Handles dynamic tiling of the stone texture. @@ -36,16 +33,14 @@ public class LayerStone implements LayerRenderer { private static final ResourceLocation texture = new ResourceLocation("textures/blocks/stone.png"); public static void initialiseLayers(){ - for(Entry, Render> entry : Minecraft.getMinecraft() - .getRenderManager().entityRenderMap.entrySet()){ + + for(Render renderer : Minecraft.getMinecraft().getRenderManager().entityRenderMap.values()){ // Because the zombie classes are now split properly, their renderers play nicely like everything else. - if(entry.getValue() instanceof RenderLivingBase){ + if(renderer instanceof RenderLivingBase){ // Adds a stone layer to all the living entity renderers in the game. Whether it is actually rendered // is decided in doRenderLayer below on a per-entity basis. - ((RenderLivingBase)entry.getValue()).addLayer(new LayerStone((RenderLivingBase)entry.getValue())); + ((RenderLivingBase)renderer).addLayer(new LayerStone((RenderLivingBase)renderer)); } - // NOTE: May have to do some special stuff for players if they are to be added; see - // Minecraft.getMinecraft().getRenderManager().getSkinMap() } } @@ -55,12 +50,13 @@ public class LayerStone implements LayerRenderer { } // FIXME: Does not work with zombie pigmen, I have no idea why. + // I believe the issue is with the TESR actually, since LayerFrost works fine @Override public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){ - if(entity.getEntityData().getBoolean(BlockStatue.NBT_KEY)){ + if(entity.getEntityData().getBoolean(BlockStatue.PETRIFIED_NBT_KEY)){ GlStateManager.enableLighting(); int i = this.getBlockBrightnessForEntity(entity, partialTicks); @@ -108,7 +104,6 @@ public class LayerStone implements LayerRenderer { GlStateManager.pushMatrix(); // Enables tiling (Also used for guardian beam, beacon beam and ender crystal beam) - // TODO: Backport this improvement GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); diff --git a/src/main/java/electroblob/wizardry/client/renderer/LayerStrayMinionClothing.java b/src/main/java/electroblob/wizardry/client/renderer/LayerStrayMinionClothing.java new file mode 100644 index 00000000..00496ecb --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/LayerStrayMinionClothing.java @@ -0,0 +1,33 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.entity.living.EntityStrayMinion; +import net.minecraft.client.model.ModelSkeleton; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.RenderLivingBase; +import net.minecraft.client.renderer.entity.layers.LayerRenderer; +import net.minecraft.util.ResourceLocation; + +/** Had to copy this entire class just because of one unnecessarily specific type parameter. The type parameter has been + * changed to {@code EntityStrayMinion} and parameter types updated accordingly. Everything else is identical. */ +public class LayerStrayMinionClothing implements LayerRenderer { + + private static final ResourceLocation STRAY_CLOTHES_TEXTURES = new ResourceLocation("textures/entity/skeleton/stray_overlay.png"); + private final RenderLivingBase renderer; + private final ModelSkeleton layerModel = new ModelSkeleton(0.25F, true); + + public LayerStrayMinionClothing(RenderLivingBase renderer){ + this.renderer = renderer; + } + + public void doRenderLayer(EntityStrayMinion entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){ + this.layerModel.setModelAttributes(this.renderer.getMainModel()); + this.layerModel.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + this.renderer.bindTexture(STRAY_CLOTHES_TEXTURES); + this.layerModel.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); + } + + public boolean shouldCombineTextures(){ + return true; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneLock.java b/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneLock.java new file mode 100644 index 00000000..cb2058f8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderArcaneLock.java @@ -0,0 +1,89 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.spell.ArcaneLock; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +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.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import org.lwjgl.opengl.GL11; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class RenderArcaneLock { + + private static final ResourceLocation[] textures = new ResourceLocation[8]; + + static { + for(int i=0; i { @@ -30,19 +30,19 @@ public class RenderArcaneWorkbench extends TileEntitySpecialRenderer { @@ -81,21 +77,21 @@ public class RenderBlackHole extends Render { int sliceAngle = 20 + a; - double x1 = scale * Math.sin((blackhole.ticksExisted + 40 * j) * (Math.PI / 180)); - // double y1 = 0.7*Math.cos((blackhole.timer - 40*j)*(Math.PI/180))*j/10; - double z1 = scale * Math.cos((blackhole.ticksExisted + 40 * j) * (Math.PI / 180)); + double x1 = scale * MathHelper.sin((blackhole.ticksExisted + 40 * j) * ((float)Math.PI / 180f)); + // double y1 = 0.7*MathHelper.cos((blackhole.timer - 40*j)*(Math.PI/180))*j/10; + double z1 = scale * MathHelper.cos((blackhole.ticksExisted + 40 * j) * ((float)Math.PI / 180)); - double x2 = scale * Math.sin((blackhole.ticksExisted + 40 * j - sliceAngle) * (Math.PI / 180)); - // double y2 = 0.7*Math.sin((blackhole.timer - 40*j)*(Math.PI/180))*j/10; - double z2 = scale * Math.cos((blackhole.ticksExisted + 40 * j - sliceAngle) * (Math.PI / 180)); + double x2 = scale * MathHelper.sin((blackhole.ticksExisted + 40 * j - sliceAngle) * ((float)Math.PI / 180)); + // double y2 = 0.7*MathHelper.sin((blackhole.timer - 40*j)*(Math.PI/180))*j/10; + double z2 = scale * MathHelper.cos((blackhole.ticksExisted + 40 * j - sliceAngle) * ((float)Math.PI / 180)); - double absoluteX = x1 * Math.cos(31 * b); - double absoluteY = z1 * Math.sin(31 * a) + x1 * Math.cos(31 * a) * Math.sin(31 * b); - double absoluteZ = z1 * Math.cos(31 * a); + double absoluteX = x1 * MathHelper.cos(31 * b); + double absoluteY = z1 * MathHelper.sin(31 * a) + x1 * MathHelper.cos(31 * a) * MathHelper.sin(31 * b); + double absoluteZ = z1 * MathHelper.cos(31 * a); - double absoluteX2 = x2 * Math.cos(31 * b); - double absoluteY2 = z2 * Math.sin(31 * a) + x2 * Math.cos(31 * a) * Math.sin(31 * b); - double absoluteZ2 = z2 * Math.cos(31 * a); + double absoluteX2 = x2 * MathHelper.cos(31 * b); + double absoluteY2 = z2 * MathHelper.sin(31 * a) + x2 * MathHelper.cos(31 * a) * MathHelper.sin(31 * b); + double absoluteZ2 = z2 * MathHelper.cos(31 * a); /* buffer.begin(0, DefaultVertexFormats.POSITION_TEX); * * tessellator.setColorOpaque(255, 255, 255); GL11.glPointSize(5); diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderBubble.java b/src/main/java/electroblob/wizardry/client/renderer/RenderBubble.java index fa0cb695..2694f1e8 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderBubble.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderBubble.java @@ -1,7 +1,5 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.construct.EntityBubble; import electroblob.wizardry.util.WizardryUtilities; @@ -14,6 +12,7 @@ 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; +import org.lwjgl.opengl.GL11; public class RenderBubble extends Render { diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderContainmentField.java b/src/main/java/electroblob/wizardry/client/renderer/RenderContainmentField.java new file mode 100644 index 00000000..b52b83b0 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderContainmentField.java @@ -0,0 +1,268 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.potion.PotionContainment; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +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.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import org.lwjgl.opengl.GL11; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class RenderContainmentField { + + private static final ResourceLocation[] textures = new ResourceLocation[8]; + + private static final float ANIMATION_SPEED = 0.004f; + private static final float FADE_DISTANCE_SQUARED = 15; + + static { + for(int i=0; i { diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderDecoy.java b/src/main/java/electroblob/wizardry/client/renderer/RenderDecoy.java index 4c421adc..10acfa56 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderDecoy.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderDecoy.java @@ -1,8 +1,5 @@ package electroblob.wizardry.client.renderer; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.living.EntityDecoy; import net.minecraft.client.model.ModelBiped; @@ -12,10 +9,11 @@ import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.relauncher.ReflectionHelper; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +//@SideOnly(Side.CLIENT) public class RenderDecoy extends RenderBiped { private static final ResourceLocation steveTextures = new ResourceLocation("textures/entity/steve.png"); diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderEvilWizard.java b/src/main/java/electroblob/wizardry/client/renderer/RenderEvilWizard.java index 2828261f..34299e1c 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderEvilWizard.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderEvilWizard.java @@ -7,10 +7,8 @@ import net.minecraft.client.renderer.entity.RenderBiped; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderEvilWizard extends RenderBiped { static final ResourceLocation[] textures = new ResourceLocation[6]; diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderFireRing.java b/src/main/java/electroblob/wizardry/client/renderer/RenderFireRing.java index 8597bacf..9e01b89b 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderFireRing.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderFireRing.java @@ -1,7 +1,5 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.entity.construct.EntityFireRing; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; @@ -15,6 +13,7 @@ import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.init.Blocks; import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; public class RenderFireRing extends Render { diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java b/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java index a7632a8d..7f908e71 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderForceArrow.java @@ -1,7 +1,5 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.projectile.EntityForceArrow; import net.minecraft.client.renderer.BufferBuilder; @@ -13,10 +11,9 @@ import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderForceArrow extends Render { private static final ResourceLocation arrowTextures = new ResourceLocation(Wizardry.MODID, diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderForcefield.java b/src/main/java/electroblob/wizardry/client/renderer/RenderForcefield.java new file mode 100644 index 00000000..660c1e1a --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderForcefield.java @@ -0,0 +1,124 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.entity.construct.EntityForcefield; +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; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.opengl.GL11; + +public class RenderForcefield extends Render { + + private static final float EXPANSION_TIME = 3; + + public RenderForcefield(RenderManager renderManager){ + super(renderManager); + } + + @Override + public void doRender(EntityForcefield entity, double x, double y, double z, float yaw, float partialTicks){ + + // For now we're just using a UV sphere + + GlStateManager.pushMatrix(); + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.translate(x, y, z); + + float latStep = (float)Math.PI/20; + float longStep = (float)Math.PI/20; + + float pulse = MathHelper.sin((entity.ticksExisted + partialTicks)/10f); + + float r = 0.35f, g = 0.55f + 0.05f * pulse, b = 1; + + float radius = entity.getRadius(); + float a = 0.5f; + + if(entity.ticksExisted > entity.lifetime - EXPANSION_TIME){ + radius *= 1 + 0.2f * (entity.ticksExisted + partialTicks - (entity.lifetime - EXPANSION_TIME))/EXPANSION_TIME; + a *= Math.max(0, 1 - (entity.ticksExisted + partialTicks - (entity.lifetime - EXPANSION_TIME))/EXPANSION_TIME); + }else if(entity.ticksExisted < EXPANSION_TIME){ + radius *= 1 - (EXPANSION_TIME - entity.ticksExisted - partialTicks)/EXPANSION_TIME; + a *= 1 - (EXPANSION_TIME - entity.ticksExisted - partialTicks)/EXPANSION_TIME; + } + + // Draw the inside first + drawSphere(radius - 0.1f - 0.025f * pulse, latStep, longStep, true, r, g, b, a); + drawSphere(radius - 0.1f - 0.025f * pulse, latStep, longStep, false, 1, 1, 1, a); + drawSphere(radius, latStep, longStep, false, r, g, b, 0.7f * a); + + GlStateManager.enableTexture2D(); + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityForcefield entity){ + return null; + } + + /** + * Draws a sphere (using lat/long triangles) with the given parameters. + * @param radius The radius of the sphere. + * @param latStep The latitude step; smaller is smoother but increases performance cost. + * @param longStep The longitude step; smaller is smoother but increases performance cost. + * @param inside Whether to draw the outside or the inside of the sphere. + * @param r The red component of the sphere colour. + * @param g The green component of the sphere colour. + * @param b The blue component of the sphere colour. + * @param a The alpha component of the sphere colour. + */ + private static void drawSphere(float radius, float latStep, float longStep, boolean inside, float r, float g, float b, float a){ + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); + + boolean goingUp = inside; + + buffer.pos(0, goingUp ? -radius : radius, 0).color(r, g, b, a).endVertex(); // Start at the north pole + + for(float longitude = -(float)Math.PI; longitude <= (float)Math.PI; longitude += longStep){ + + // Leave the poles out since they only have a single point per stack instead of two + for(float theta = (float)Math.PI/2 - latStep; theta >= -(float)Math.PI/2 + latStep; theta -= latStep){ + + float latitude = goingUp ? -theta : theta; + + float hRadius = radius * MathHelper.cos(latitude); + float vy = radius * MathHelper.sin(latitude); + float vx = hRadius * MathHelper.sin(longitude); + float vz = hRadius * MathHelper.cos(longitude); + + buffer.pos(vx, vy, vz).color(r, g, b, a).endVertex(); + + vx = hRadius * MathHelper.sin(longitude + longStep); + vz = hRadius * MathHelper.cos(longitude + longStep); + + buffer.pos(vx, vy, vz).color(r, g, b, a).endVertex(); + } + + // The next pole + buffer.pos(0, goingUp ? radius : -radius, 0).color(r, g, b, a).endVertex(); + + goingUp = !goingUp; + } + + tessellator.draw(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderHammer.java b/src/main/java/electroblob/wizardry/client/renderer/RenderHammer.java index 8f448603..3962e04b 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderHammer.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderHammer.java @@ -19,11 +19,13 @@ public class RenderHammer extends Render { } @Override - public void doRender(EntityHammer entity, double x, double y, double z, float f, float f1){ + public void doRender(EntityHammer entity, double x, double y, double z, float yaw, float partialTicks){ GlStateManager.pushMatrix(); GlStateManager.translate(x, y + 1.5, z); GlStateManager.rotate(180, 0F, 0F, 1F); + GlStateManager.rotate(yaw, 0, 1, 0); + GlStateManager.rotate(entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * partialTicks, 0, 0, 1); this.bindTexture(texture); diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderIceGiant.java b/src/main/java/electroblob/wizardry/client/renderer/RenderIceGiant.java index b78c6888..e20f22bf 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderIceGiant.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderIceGiant.java @@ -7,10 +7,8 @@ import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.RenderLiving; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderIceGiant extends RenderLiving { private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderIceSpike.java b/src/main/java/electroblob/wizardry/client/renderer/RenderIceSpike.java index 961b87f5..3a88d93b 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderIceSpike.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderIceSpike.java @@ -1,7 +1,5 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.construct.EntityIceSpike; import net.minecraft.client.renderer.BufferBuilder; @@ -12,6 +10,7 @@ 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; +import org.lwjgl.opengl.GL11; public class RenderIceSpike extends Render { @@ -23,13 +22,14 @@ public class RenderIceSpike extends Render { } @Override - public void doRender(EntityIceSpike entity, double x, double y, double z, float fa, float partialTickTime){ + public void doRender(EntityIceSpike entity, double x, double y, double z, float yaw, float partialTickTime){ GlStateManager.pushMatrix(); GlStateManager.translate((float)x, (float)y, (float)z); - // Apparently, disabling lighting... doesn't disable lighting. Or at least, you can still set the brightness - // with setLightmapTextureCoords. + GlStateManager.rotate(entity.rotationYaw - 90.0F, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(entity.rotationPitch - 90, 0.0F, 0.0F, 1.0F); + GlStateManager.disableLighting(); int j = entity.getBrightnessForRender(); diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderLightningDisc.java b/src/main/java/electroblob/wizardry/client/renderer/RenderLightningDisc.java index 77af69d3..96fe6110 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderLightningDisc.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderLightningDisc.java @@ -1,7 +1,5 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.entity.projectile.EntityLightningDisc; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; @@ -11,6 +9,7 @@ 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; +import org.lwjgl.opengl.GL11; public class RenderLightningDisc extends Render { diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderMagicArrow.java b/src/main/java/electroblob/wizardry/client/renderer/RenderMagicArrow.java index 9dfb0527..b0db9b36 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderMagicArrow.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderMagicArrow.java @@ -1,7 +1,5 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.entity.projectile.EntityMagicArrow; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; @@ -12,10 +10,9 @@ import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderMagicArrow extends Render { private final ResourceLocation texture; diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderMagicLight.java b/src/main/java/electroblob/wizardry/client/renderer/RenderMagicLight.java index 198e02f7..a0e2a2ce 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderMagicLight.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderMagicLight.java @@ -1,18 +1,14 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.tileentity.TileEntityMagicLight; import net.minecraft.client.Minecraft; -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.*; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.opengl.GL11; public class RenderMagicLight extends TileEntitySpecialRenderer { @@ -40,10 +36,9 @@ public class RenderMagicLight extends TileEntitySpecialRenderer tileentity.maxTimer - 10 && tileentity.timer <= tileentity.maxTimer){ - GlStateManager.scale((float)(tileentity.maxTimer - tileentity.timer) / 10, - (float)(tileentity.maxTimer - tileentity.timer) / 10, - (float)(tileentity.maxTimer - tileentity.timer) / 10); + if(tileentity.maxTimer > 0 && tileentity.timer > tileentity.maxTimer - 10){ + float scale = Math.max(0, (float)(tileentity.maxTimer - tileentity.timer) / 10); + GlStateManager.scale(scale, scale, scale); } // Renders the aura effect @@ -105,13 +100,13 @@ public class RenderMagicLight extends TileEntitySpecialRenderer { private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/phoenix.png"); diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderPossessingPlayer.java b/src/main/java/electroblob/wizardry/client/renderer/RenderPossessingPlayer.java new file mode 100644 index 00000000..0820a178 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderPossessingPlayer.java @@ -0,0 +1,41 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.spell.Possession; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.client.event.RenderPlayerEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class RenderPossessingPlayer { + + @SubscribeEvent + @SuppressWarnings("unchecked") // Can't check it due to type erasure + public static void onRenderPlayerPreEvent(RenderPlayerEvent.Pre event){ + + EntityPlayer player = event.getEntityPlayer(); + EntityLiving possessee = Possession.getPossessee(player); + + if(possessee != null){ + // I reject your renderer and substitute my own! + Render renderer = (Render)event.getRenderer().getRenderManager().entityRenderMap.get(possessee.getClass()); + float yaw = player.prevRotationYaw + (player.rotationYaw - player.prevRotationYaw) * event.getPartialRenderTick(); + possessee.swingProgress = player.swingProgress; + possessee.prevSwingProgress = player.prevSwingProgress; + possessee.renderYawOffset = player.renderYawOffset; + possessee.prevRenderYawOffset = player.prevRenderYawOffset; + possessee.rotationYawHead = player.rotationYawHead; + possessee.prevRotationYawHead = player.prevRotationYawHead; + possessee.rotationPitch = player.rotationPitch; + possessee.prevRotationPitch = player.prevRotationPitch; + possessee.limbSwing = player.limbSwing; + possessee.limbSwingAmount = player.limbSwingAmount; + possessee.prevLimbSwingAmount = player.prevLimbSwingAmount; + renderer.doRender(possessee, event.getX(), event.getY(), event.getZ(), yaw, event.getPartialRenderTick()); + event.setCanceled(true); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderProjectile.java b/src/main/java/electroblob/wizardry/client/renderer/RenderProjectile.java index 387257b4..f5ece03f 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderProjectile.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderProjectile.java @@ -1,7 +1,5 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.entity.projectile.EntityMagicProjectile; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; @@ -12,10 +10,9 @@ 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; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderProjectile extends Render { private float scale; diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderShadowWard.java b/src/main/java/electroblob/wizardry/client/renderer/RenderShadowWard.java new file mode 100644 index 00000000..a0cf181f --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderShadowWard.java @@ -0,0 +1,148 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +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.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.event.RenderPlayerEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import org.lwjgl.opengl.GL11; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class RenderShadowWard { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/shadow_ward.png"); + + // First person + @SubscribeEvent + public static void onRenderWorldLastEvent(RenderWorldLastEvent event){ + // Only render in first person + if(Minecraft.getMinecraft().gameSettings.thirdPersonView == 0){ + + EntityPlayer player = Minecraft.getMinecraft().player; + + if(WizardryUtilities.isCasting(player, Spells.shadow_ward)){ + + GlStateManager.pushMatrix(); + + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + //GlStateManager.shadeModel(GL11.GL_SMOOTH); + GlStateManager.disableLighting(); + //GlStateManager.disableAlpha(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.translate(0, 1.2, 0); + GlStateManager.rotate(-player.rotationYaw, 0, 1, 0); + GlStateManager.rotate(player.rotationPitch, 1, 0, 0); + + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE); + + GlStateManager.pushMatrix(); + + GlStateManager.translate(0, 0, 1.2); + GlStateManager.rotate(player.world.getTotalWorldTime() * -2, 0, 0, 1); + GlStateManager.scale(1.1, 1.1, 1.1); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); + buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); + buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); + buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); + buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); + buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); + buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + //GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + + GlStateManager.popMatrix(); + + } + } + } + + // Third person + @SubscribeEvent + public static void onRenderPlayerEvent(RenderPlayerEvent.Post event){ + + EntityPlayer player = event.getEntityPlayer(); + + if(WizardryUtilities.isCasting(player, Spells.shadow_ward)){ + + GlStateManager.pushMatrix(); + + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + Vec3d delta = player.getPositionEyes(event.getPartialRenderTick()) + .subtract(Minecraft.getMinecraft().player.getPositionEyes(event.getPartialRenderTick())); + GlStateManager.translate(delta.x, delta.y, delta.z); + + GlStateManager.rotate(180, 0, 1, 0); + GlStateManager.rotate(-player.renderYawOffset, 0, 1, 0); + + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + GlStateManager.translate(0, 1.2, 0); + GlStateManager.rotate(player.world.getTotalWorldTime() * -2, 0, 0, 1); + GlStateManager.scale(1.1, 1.1, 1.1); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); + buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); + buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); + buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(-0.5, 0.5, -0.5).tex(0, 0).endVertex(); + buffer.pos(-0.5, -0.5, -0.5).tex(0, 1).endVertex(); + buffer.pos(0.5, -0.5, -0.5).tex(1, 1).endVertex(); + buffer.pos(0.5, 0.5, -0.5).tex(1, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + + GlStateManager.popMatrix(); + + } + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderShield.java b/src/main/java/electroblob/wizardry/client/renderer/RenderShield.java new file mode 100644 index 00000000..6211d4f4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderShield.java @@ -0,0 +1,168 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Shield; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +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.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.event.RenderPlayerEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import org.lwjgl.opengl.GL11; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class RenderShield { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/shield.png"); + + // First person + @SubscribeEvent + public static void onRenderWorldLastEvent(RenderWorldLastEvent event){ + // Only render in first person + if(Minecraft.getMinecraft().gameSettings.thirdPersonView == 0){ + + EntityPlayer player = Minecraft.getMinecraft().player; + + if(WizardData.get(player).getVariable(Shield.SHIELD_KEY) != null && WizardryUtilities.isCasting(player, Spells.shield)){ + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + GlStateManager.translate(0, 1.4, 0); + + GlStateManager.rotate(-player.rotationYaw, 0, 1, 0); + GlStateManager.rotate(player.rotationPitch, 1, 0, 0); + + GlStateManager.translate(0, 0, 0.8); + + Tessellator tessellator = Tessellator.getInstance(); + + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE); + + render(tessellator); + + GlStateManager.enableLighting(); + + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableCull(); + GlStateManager.disableBlend(); + // RenderHelper.enableStandardItemLighting(); + + GlStateManager.popMatrix(); + } + } + } + + // Third person + @SubscribeEvent + public static void onRenderPlayerEvent(RenderPlayerEvent.Post event){ + + EntityPlayer player = event.getEntityPlayer(); + + if(WizardData.get(player).getVariable(Shield.SHIELD_KEY) != null && WizardryUtilities.isCasting(player, Spells.shield)){ + + GlStateManager.pushMatrix(); + + GlStateManager.disableCull(); + GlStateManager.enableBlend(); + // For some reason, the old blend function (GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA) caused the inner + // edges to appear black, so I have changed it to this, which looks very slightly different. + GlStateManager.blendFunc(GL11.GL_ONE, GL11.GL_SRC_ALPHA); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + Vec3d delta = player.getPositionEyes(event.getPartialRenderTick()) + .subtract(Minecraft.getMinecraft().player.getPositionEyes(event.getPartialRenderTick())); + GlStateManager.translate(delta.x, delta.y, delta.z); + + GlStateManager.translate(0, 1.3, 0); + + // GlStateManager.rotate(180, 0, 1, 0); + GlStateManager.rotate(-player.renderYawOffset, 0, 1, 0); + // GlStateManager.rotate(-player.rotationPitch, 1, 0, 0); + + GlStateManager.translate(0, 0, 0.8); + + Tessellator tessellator = Tessellator.getInstance(); + + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE); + + render(tessellator); + + GlStateManager.enableLighting(); + + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableCull(); + GlStateManager.disableBlend(); + // RenderHelper.enableStandardItemLighting(); + + GlStateManager.popMatrix(); + } + } + + private static void render(Tessellator tessellator){ + + BufferBuilder buffer = tessellator.getBuffer(); + + double widthOuter = 0.6d; + double heightOuter = 0.7d; + double widthInner = 0.3d; + double heightInner = 0.4d; + double depth = 0.2d; + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); + + buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); + buffer.pos(-widthInner, heightOuter, -depth).tex(0.2, 0).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); + + buffer.pos(widthInner, heightOuter, -depth).tex(0.8, 0).color(0, 0, 0, 255).endVertex(); + buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); + buffer.pos(widthOuter, heightInner, -depth).tex(1, 0.2).color(0, 0, 0, 255).endVertex(); + buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); + + buffer.pos(widthOuter, -heightInner, -depth).tex(1, 0.8).color(0, 0, 0, 255).endVertex(); + buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); + buffer.pos(widthInner, -heightOuter, -depth).tex(0.8, 1).color(0, 0, 0, 255).endVertex(); + buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); + + buffer.pos(-widthInner, -heightOuter, -depth).tex(0.2, 1).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); + buffer.pos(-widthOuter, -heightInner, -depth).tex(0, 0.8).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); + + buffer.pos(-widthOuter, heightInner, -depth).tex(0, 0.2).color(0, 0, 0, 255).endVertex(); + buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR); + + buffer.pos(-widthInner, heightInner, 0).tex(0.2, 0.2).color(200, 200, 255, 255).endVertex(); + buffer.pos(widthInner, heightInner, 0).tex(0.8, 0.2).color(200, 200, 255, 255).endVertex(); + buffer.pos(-widthInner, -heightInner, 0).tex(0.2, 0.8).color(200, 200, 255, 255).endVertex(); + buffer.pos(widthInner, -heightInner, 0).tex(0.8, 0.8).color(200, 200, 255, 255).endVertex(); + + tessellator.draw(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderSigil.java b/src/main/java/electroblob/wizardry/client/renderer/RenderSigil.java index 739b44c1..5d43d31c 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderSigil.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderSigil.java @@ -1,10 +1,8 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.entity.construct.EntityHealAura; import electroblob.wizardry.entity.construct.EntityMagicConstruct; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.AllyDesignationSystem; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; @@ -15,6 +13,7 @@ import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; public class RenderSigil extends Render { @@ -34,8 +33,8 @@ public class RenderSigil extends Render { // Makes the sigil invisible to enemies of the player that created it if(this.invisibleToEnemies){ - - if(entity.getCaster() instanceof EntityPlayer && !WizardryUtilities + // Unfortunately we can't access the caster's allies if they're not online, it only works the other way round + if(entity.getCaster() instanceof EntityPlayer && !AllyDesignationSystem .isPlayerAlly((EntityPlayer)entity.getCaster(), Minecraft.getMinecraft().player)){ return; } diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritHorse.java b/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritHorse.java index c3452e38..79cd0ab7 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritHorse.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritHorse.java @@ -1,22 +1,23 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.living.EntitySpiritHorse; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.RenderHorse; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.passive.EntityHorse; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderSpiritHorse extends RenderHorse { private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/spirit_horse.png"); +// private static final int GHOST_COPIES = 3; +// private static final float DECONVERGENCE = 0.35f; + public RenderSpiritHorse(RenderManager renderManager){ super(renderManager); } @@ -27,10 +28,36 @@ public class RenderSpiritHorse extends RenderHorse { } @Override - protected void preRenderCallback(EntityHorse entitylivingbaseIn, float partialTickTime){ - super.preRenderCallback(entitylivingbaseIn, partialTickTime); + protected void preRenderCallback(EntityHorse horse, float partialTickTime){ + super.preRenderCallback(horse, partialTickTime); GlStateManager.enableBlend(); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + if(horse instanceof EntitySpiritHorse){ // Always true + GlStateManager.color(1, 1, 1, ((EntitySpiritHorse)horse).getOpacity()); + } + } + + @Override + public void doRender(EntityHorse entity, double x, double y, double z, float entityYaw, float partialTicks){ + + super.doRender(entity, x, y, z, entityYaw, partialTicks); + +// double dx = (entity.posX - entity.prevPosX) * DECONVERGENCE; +// double dy = (entity.posY - entity.prevPosY) * DECONVERGENCE; +// double dz = (entity.posZ - entity.prevPosZ) * DECONVERGENCE; +// float dyaw = (entity.rotationYaw - entity.prevRotationYaw) * DECONVERGENCE; +// +// float opacity = 1; +// if(entity instanceof EntitySpiritHorse){ // Always true +// opacity = ((EntitySpiritHorse)entity).getOpacity(); +// } +// +// for(int i = 0; i < GHOST_COPIES; i++){ +// +// GlStateManager.color(1, 1, 1, opacity * (0.6f - (float)i/(GHOST_COPIES*2))); +// +// super.doRender(entity, x - dx * i, y - dy * i, z - dz * i, entityYaw - dyaw * i, partialTicks); +// } } } diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritWolf.java b/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritWolf.java index a3f4fadc..0564f69b 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritWolf.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderSpiritWolf.java @@ -1,22 +1,23 @@ package electroblob.wizardry.client.renderer; -import org.lwjgl.opengl.GL11; - import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.living.EntitySpiritWolf; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.entity.RenderWolf; import net.minecraft.entity.passive.EntityWolf; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderSpiritWolf extends RenderWolf { private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/spirit_wolf.png"); +// private static final int GHOST_COPIES = 3; +// private static final float DECONVERGENCE = 0.8f; + public RenderSpiritWolf(RenderManager renderManager){ super(renderManager); } @@ -31,5 +32,31 @@ public class RenderSpiritWolf extends RenderWolf { super.preRenderCallback(entity, partialTickTime); GlStateManager.enableBlend(); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + if(entity instanceof EntitySpiritWolf){ // Always true + GlStateManager.color(1, 1, 1, ((EntitySpiritWolf)entity).getOpacity()); + } + } + + @Override + public void doRender(EntityWolf entity, double x, double y, double z, float entityYaw, float partialTicks){ + + super.doRender(entity, x, y, z, entityYaw, partialTicks); + +// double dx = (entity.posX - entity.prevPosX) * DECONVERGENCE; +// double dy = (entity.posY - entity.prevPosY) * DECONVERGENCE; +// double dz = (entity.posZ - entity.prevPosZ) * DECONVERGENCE; +// float dyaw = (entity.rotationYaw - entity.prevRotationYaw) * DECONVERGENCE; +// +// float opacity = 1; +// if(entity instanceof EntitySpiritWolf){ // Always true +// opacity = ((EntitySpiritWolf)entity).getOpacity(); +// } +// +// for(int i = 0; i < GHOST_COPIES; i++){ +// +// GlStateManager.color(1, 1, 1, opacity * (0.6f - (float)i/(GHOST_COPIES*2))); +// +// super.doRender(entity, x - dx * i, y - dy * i, z - dz * i, entityYaw - dyaw * i, partialTicks); +// } } } diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderStrayMinion.java b/src/main/java/electroblob/wizardry/client/renderer/RenderStrayMinion.java new file mode 100644 index 00000000..815d4979 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderStrayMinion.java @@ -0,0 +1,24 @@ +package electroblob.wizardry.client.renderer; + +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.entity.RenderSkeleton; +import net.minecraft.entity.monster.AbstractSkeleton; +import net.minecraft.util.ResourceLocation; + +/** This class also had to be copied for the same reason as {@link LayerStrayMinionClothing}. */ +public class RenderStrayMinion extends RenderSkeleton { + + private static final ResourceLocation STRAY_SKELETON_TEXTURES = new ResourceLocation("textures/entity/skeleton/stray.png"); + + public RenderStrayMinion(RenderManager manager){ + super(manager); + this.addLayer(new LayerStrayMinionClothing(this)); // This is the only change + } + + /** + * Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture. + */ + protected ResourceLocation getEntityTexture(AbstractSkeleton entity){ + return STRAY_SKELETON_TEXTURES; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderTransportationUI.java b/src/main/java/electroblob/wizardry/client/renderer/RenderTransportationUI.java new file mode 100644 index 00000000..599d168e --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderTransportationUI.java @@ -0,0 +1,177 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.spell.Transportation; +import electroblob.wizardry.util.Location; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +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.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import org.lwjgl.opengl.GL11; + +import java.util.List; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class RenderTransportationUI { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/gui/transportation_marker.png"); + + // I can't get rid of the view bobbing with RenderWorldLastEvent, is there an alternative? + @SubscribeEvent + public static void onRenderWorldLastEvent(RenderWorldLastEvent event){ + + // Only render in first person + if(Minecraft.getMinecraft().gameSettings.thirdPersonView != 0) return; + + EntityPlayer player = Minecraft.getMinecraft().player; + + ItemStack stack = player.getHeldItemMainhand(); + if(!(stack.getItem() instanceof ISpellCastingItem)){ + stack = player.getHeldItemOffhand(); + if(!(stack.getItem() instanceof ISpellCastingItem)) return; + } + + if(((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack) == Spells.transportation + && ItemArtefact.isArtefactActive(player, WizardryItems.charm_transportation)){ + + WizardData data = WizardData.get(player); + if(data == null) return; + + List locations = data.getVariable(Transportation.LOCATIONS_KEY); + + if(locations == null) return; + + GlStateManager.pushMatrix(); + + Vec3d origin = player.getPositionEyes(event.getPartialTicks()); + GlStateManager.translate(0, origin.y - Minecraft.getMinecraft().getRenderManager().viewerPosY, 0); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + Location target = Transportation.getLocationAimedAt(player, locations, event.getPartialTicks()); + + for(Location location : locations){ + + if(location.dimension != player.dimension) continue; + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.disableLighting(); + GlStateManager.disableDepth(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.color(1, 1, 1, 1); + + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); + + Vec3d position = WizardryUtilities.getCentre(location.pos).subtract(origin); + double distance = position.length(); + // The icon lines up perfectly if you render it at actual distance, otherwise view bobbing messes things up + // However, if that's outside the render distance it won't render at all! To fudge our way around this + // problem, we're capping the distance to just below the render distance and adjusting the scale accordingly + double distanceCap = Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16 - 8; + double displayDist = distance > distanceCap ? distanceCap : distance; + double factor = displayDist/distance; + + GlStateManager.translate(position.x * factor, position.y * factor, position.z * factor); + + GlStateManager.rotate(-Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(Minecraft.getMinecraft().getRenderManager().playerViewX, 1.0F, 0.0F, 0.0F); + + // Get the angle between the player's look vector and the direction of the stone circle + double angle = Transportation.getLookDeviationAngle(player, location.pos, event.getPartialTicks()); + double iconSize = Transportation.getIconSize(distance); + + // Now apply a fancy formula to make it enlarge with a nice smooth animation: + double proximityFactor = Math.max(0, Math.pow(1 - angle/iconSize * angle/iconSize, 3)); + iconSize *= 1 + 0.3 * proximityFactor; + iconSize *= displayDist; // Adjust the icon size for perspective + + float f = location == target ? 1 : 0.5f; // Makes it obvious which one is being aimed at + + buffer.pos(-iconSize, iconSize, 0).tex(0, 0).color(f, 1, f, f).endVertex(); + buffer.pos(iconSize, iconSize, 0).tex(1, 0).color(f, 1, f, f).endVertex(); + buffer.pos(iconSize, -iconSize, 0).tex(1, 1).color(f, 1, f, f).endVertex(); + buffer.pos(-iconSize, -iconSize, 0).tex(0, 1).color(f, 1, f, f).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + if(location == target){ + String label = location.pos.getX() + ", " + location.pos.getY() + ", " + location.pos.getZ(); + drawLabel(Minecraft.getMinecraft().fontRenderer, label, (float)(position.x * factor), + (float)(position.y * factor + iconSize*1.5f), (float)(position.z * factor), (float)displayDist * 0.2f, 0, + Minecraft.getMinecraft().getRenderManager().playerViewY, Minecraft.getMinecraft().getRenderManager().playerViewX); + } + } + + GlStateManager.disableBlend(); + GlStateManager.enableTexture2D(); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + GlStateManager.disableRescaleNormal(); + GlStateManager.popMatrix(); + } + } + + // Copied from EntityRenderer#drawNameplate and tweaked a bit + private static void drawLabel(FontRenderer fontRendererIn, String str, float x, float y, float z, float scale, int verticalShift, float viewerYaw, float viewerPitch){ + + GlStateManager.pushMatrix(); + GlStateManager.translate(x, y, z); + GlStateManager.glNormal3f(0.0F, 1.0F, 0.0F); + GlStateManager.rotate(-viewerYaw, 0.0F, 1.0F, 0.0F); + GlStateManager.rotate(viewerPitch, 1.0F, 0.0F, 0.0F); + GlStateManager.scale(-0.025F, -0.025F, 0.025F); + GlStateManager.scale(scale, scale, scale); + GlStateManager.disableLighting(); + GlStateManager.depthMask(false); + + GlStateManager.disableDepth(); + + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + int i = fontRendererIn.getStringWidth(str) / 2; + GlStateManager.disableTexture2D(); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_COLOR); + bufferbuilder.pos((double)(-i - 1), (double)(-1 + verticalShift), 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex(); + bufferbuilder.pos((double)(-i - 1), (double)(8 + verticalShift), 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex(); + bufferbuilder.pos((double)(i + 1), (double)(8 + verticalShift), 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex(); + bufferbuilder.pos((double)(i + 1), (double)(-1 + verticalShift), 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex(); + tessellator.draw(); + GlStateManager.enableTexture2D(); + + fontRendererIn.drawString(str, -fontRendererIn.getStringWidth(str) / 2, verticalShift, 0x86ff65); + GlStateManager.enableDepth(); + + GlStateManager.depthMask(true); + fontRendererIn.drawString(str, -fontRendererIn.getStringWidth(str) / 2, verticalShift, 0x86ff65); + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.popMatrix(); + } +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderWings.java b/src/main/java/electroblob/wizardry/client/renderer/RenderWings.java new file mode 100644 index 00000000..5701d736 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderWings.java @@ -0,0 +1,113 @@ +package electroblob.wizardry.client.renderer; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.client.Minecraft; +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.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.event.RenderPlayerEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import org.lwjgl.opengl.GL11; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class RenderWings { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/wing.png"); + + // No first person in here because you can never see the wings on your back! + + // Third person + @SubscribeEvent + public static void onRenderPlayerEvent(RenderPlayerEvent.Post event){ + + EntityPlayer player = event.getEntityPlayer(); + + if(WizardryUtilities.isCasting(player, Spells.flight)){ + + GlStateManager.pushMatrix(); + + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GlStateManager.disableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + Vec3d delta = player.getPositionEyes(event.getPartialRenderTick()) + .subtract(Minecraft.getMinecraft().player.getPositionEyes(event.getPartialRenderTick())); + GlStateManager.translate(delta.x, delta.y, delta.z); + + // GlStateManager.rotate(-entityplayer.rotationYawHead, 0, 1, 0); + GlStateManager.rotate(-player.renderYawOffset, 0, 1, 0); + // GlStateManager.rotate(180, 1, 0, 0); + + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + GlStateManager.pushMatrix(); + + GlStateManager.translate(0.1, 0.4, -0.15); + GlStateManager.rotate(20 + 20 * MathHelper.sin((player.ticksExisted + event.getPartialRenderTick()) * 0.3f), 0, 1, 0); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(0, 2, 0).tex(0, 0).endVertex(); + buffer.pos(2, 2, 0).tex(1, 0).endVertex(); + buffer.pos(2, 0, 0).tex(1, 1).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(0, 2, 0).tex(0, 0).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + buffer.pos(2, 0, 0).tex(1, 1).endVertex(); + buffer.pos(2, 2, 0).tex(1, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + GlStateManager.pushMatrix(); + + GlStateManager.translate(-0.1, 0.4, -0.15); + GlStateManager.rotate(-200 - 20 * MathHelper.sin((player.ticksExisted + event.getPartialRenderTick()) * 0.3f), 0, 1, 0); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(0, 2, 0).tex(0, 0).endVertex(); + buffer.pos(2, 2, 0).tex(1, 0).endVertex(); + buffer.pos(2, 0, 0).tex(1, 1).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + + tessellator.draw(); + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + buffer.pos(0, 2, 0).tex(0, 0).endVertex(); + buffer.pos(0, 0, 0).tex(0, 1).endVertex(); + buffer.pos(2, 0, 0).tex(1, 1).endVertex(); + buffer.pos(2, 2, 0).tex(1, 0).endVertex(); + + tessellator.draw(); + + GlStateManager.popMatrix(); + + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + + GlStateManager.popMatrix(); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderWizard.java b/src/main/java/electroblob/wizardry/client/renderer/RenderWizard.java index baa322ee..566bc5a7 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderWizard.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderWizard.java @@ -7,10 +7,8 @@ import net.minecraft.client.renderer.entity.RenderBiped; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderWizard extends RenderBiped { static final ResourceLocation[] textures = new ResourceLocation[6]; diff --git a/src/main/java/electroblob/wizardry/client/renderer/RenderWraithMinion.java b/src/main/java/electroblob/wizardry/client/renderer/RenderWraithMinion.java index da691189..d8cfe382 100644 --- a/src/main/java/electroblob/wizardry/client/renderer/RenderWraithMinion.java +++ b/src/main/java/electroblob/wizardry/client/renderer/RenderWraithMinion.java @@ -5,10 +5,8 @@ import net.minecraft.client.model.ModelBlaze; import net.minecraft.client.renderer.entity.RenderLiving; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -@SideOnly(Side.CLIENT) +//@SideOnly(Side.CLIENT) public class RenderWraithMinion extends RenderLiving { private ResourceLocation texture = new ResourceLocation("textures/entity/blaze.png"); diff --git a/src/main/java/electroblob/wizardry/command/CommandCastSpell.java b/src/main/java/electroblob/wizardry/command/CommandCastSpell.java index 7dbbde14..c71e9e29 100644 --- a/src/main/java/electroblob/wizardry/command/CommandCastSpell.java +++ b/src/main/java/electroblob/wizardry/command/CommandCastSpell.java @@ -1,36 +1,41 @@ package electroblob.wizardry.command; -import java.util.List; - -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent.Source; import electroblob.wizardry.packet.PacketCastSpell; +import electroblob.wizardry.packet.PacketCastSpellAtPos; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.command.NumberInvalidException; -import net.minecraft.command.PlayerNotFoundException; -import net.minecraft.command.WrongUsageException; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.command.*; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.JsonToNBT; import net.minecraft.nbt.NBTException; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import java.util.List; + public class CommandCastSpell extends CommandBase { + /** The default number of ticks for which /cast will cast a continuous spell, if duration is not specified. */ + public static final int DEFAULT_CASTING_DURATION = 100; + /** The minimum number of seconds for which /cast may cast a continuous spell. */ + public static final int MIN_CASTING_DURATION = 0; + /** The maximum number of seconds for which /cast may cast a continuous spell. */ + public static final int MAX_CASTING_DURATION = 1000000; + @Override public String getName(){ return Wizardry.settings.castCommandName; @@ -74,6 +79,8 @@ public class CommandCastSpell extends CommandBase { int i = 0; EntityPlayerMP caster = null; + Vec3d origin = null; + EnumFacing direction = null; try{ caster = getCommandSenderAsPlayer(sender); @@ -85,12 +92,24 @@ public class CommandCastSpell extends CommandBase { Spell spell = Spell.get(arguments[i++]); if(spell == null){ - throw new NumberInvalidException("commands." + Wizardry.MODID + ":cast.not_found", new Object[]{arguments[i - 1]}); + throw new NumberInvalidException("commands." + Wizardry.MODID + ":cast.not_found", arguments[i - 1]); } boolean castAsOtherPlayer = false; - if(i < arguments.length){ + if(i + 3 < arguments.length){ + + Vec3d vec3d = sender.getPositionVector(); + CoordinateArg x = parseCoordinate(vec3d.x, arguments[i++], true); + CoordinateArg y = parseCoordinate(vec3d.y, arguments[i++], 0, 256, false); + CoordinateArg z = parseCoordinate(vec3d.z, arguments[i++], true); + + origin = new Vec3d(x.getResult(), y.getResult(), z.getResult()); + + direction = EnumFacing.byName(arguments[i++]); + if(direction == null) throw new NumberInvalidException("commands." + Wizardry.MODID + ":cast.invalid_direction", arguments[i - 1]); + + }else if(i < arguments.length){ try{ // If the second argument is a player and is not the player that gave the command, the spell is cast // as the given player rather than the command sender, and there is a different chat readout. @@ -107,8 +126,31 @@ public class CommandCastSpell extends CommandBase { // If, after this point, the player is still null, the sender must be a command block or the console and the // player must not have been specified, meaning an exception should be thrown. - if(caster == null) - throw new PlayerNotFoundException("You must specify which player you wish to perform this action on."); + if(caster == null && origin == null) + throw new PlayerNotFoundException("commands." + Wizardry.MODID + ":cast.origin_not_specified"); + + int duration = DEFAULT_CASTING_DURATION; + int seconds = duration/20; + + if(spell.isContinuous){ + + if(i >= arguments.length) throw new CommandException("commands." + Wizardry.MODID + ":cast.duration_not_specified"); + + try{ + seconds = parseInt(arguments[i++]); + }catch(NumberInvalidException e){ + // If no duration was found, assume it was unspecified + i--; + } + + if(seconds < MIN_CASTING_DURATION){ + throw new NumberInvalidException("commands.generic.num.tooSmall", seconds, MIN_CASTING_DURATION); + }else if(seconds > MAX_CASTING_DURATION){ + throw new NumberInvalidException("commands.generic.num.tooBig", seconds, MAX_CASTING_DURATION); + } + + duration = seconds * 20; + } SpellModifiers modifiers = new SpellModifiers(); @@ -136,64 +178,124 @@ public class CommandCastSpell extends CommandBase { // ===== Spell casting ===== - // If anything stops the spell working at this point, nothing else happens. - if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(caster, spell, modifiers, Source.COMMAND))){ - displayFailMessage(sender, spell); - return; - } + if(origin != null){ // Positional - WizardData data = WizardData.get((EntityPlayer)caster); + World world = sender.getEntityWorld(); - if(spell.isContinuous){ + // If anything stops the spell working at this point, nothing else happens. + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(Source.COMMAND, spell, world, + origin.x, origin.y, origin.z, direction, modifiers))){ + if(server.sendCommandFeedback()) displayFailMessage(sender, spell); + return; + } - // Events for continuous spell casting via commands are dealt with in WizardData. + if(spell.isContinuous){ - if(data != null){ - if(data.isCasting()){ - data.stopCastingContinuousSpell(); - }else{ + if(spell.cast(world, origin.x, origin.y, origin.z, direction, 0, duration, modifiers)){ - data.startCastingContinuousSpell(spell, modifiers); + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.COMMAND, spell, world, origin.x, origin.y, origin.z, direction, modifiers)); - if(castAsOtherPlayer){ - sender.sendMessage( - new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success_remote_continuous", - spell.getNameForTranslationFormatted(), caster.getName())); - }else{ - sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success_continuous", - spell.getNameForTranslationFormatted())); + SpellEmitter.add(spell, world, origin.x, origin.y, origin.z, direction, duration, modifiers); + IMessage msg = new PacketCastSpellAtPos.Message(origin, direction, spell, modifiers, duration); + WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); + + if(server.sendCommandFeedback()){ + sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success_position_continuous", + spell.getNameForTranslationFormatted(), origin.x, origin.y, origin.z, seconds)); } + + return; } + }else{ + + if(spell.cast(world, origin.x, origin.y, origin.z, direction, 0, -1, modifiers)){ + + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.COMMAND, spell, world, origin.x, origin.y, origin.z, direction, modifiers)); + + if(spell.requiresPacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + // Only sent if the spell succeeded, because if the spell failed, you wouldn't + // need to spawn any particles! + IMessage msg = new PacketCastSpellAtPos.Message(origin, direction, spell, modifiers); + WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); + } + + if(server.sendCommandFeedback()){ + sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success_position", + spell.getNameForTranslationFormatted(), origin.x, origin.y, origin.z)); + } + + return; + } + } + + }else{ // Player-based + + // If anything stops the spell working at this point, nothing else happens. + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(Source.COMMAND, spell, caster, modifiers))){ + if(server.sendCommandFeedback()) displayFailMessage(sender, spell); return; } - }else{ + if(spell.isContinuous){ - if(spell.cast(caster.world, caster, EnumHand.MAIN_HAND, 0, modifiers)){ + WizardData data = WizardData.get(caster); - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(caster, spell, modifiers, Source.COMMAND)); + // Events/packets for continuous spell casting via commands are dealt with in WizardData. - if(spell.doesSpellRequirePacket()){ - // Sends a packet to all players in dimension to tell them to spawn particles. - // Only sent if the spell succeeded, because if the spell failed, you wouldn't - // need to spawn any particles! - IMessage msg = new PacketCastSpell.Message(caster.getEntityId(), null, spell.id(), modifiers); - WizardryPacketHandler.net.sendToDimension(msg, caster.world.provider.getDimension()); + if(data != null){ + if(data.isCasting()){ + data.stopCastingContinuousSpell(); // TODO: Where should this go now? + }else{ + + data.startCastingContinuousSpell(spell, modifiers, duration); + + if(server.sendCommandFeedback()){ + if(castAsOtherPlayer){ + sender.sendMessage( + new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success_remote_continuous", + spell.getNameForTranslationFormatted(), caster.getName(), seconds)); + }else{ + sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success_continuous", + spell.getNameForTranslationFormatted(), seconds)); + } + } + } + + return; } - if(castAsOtherPlayer){ - sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success_remote", - spell.getNameForTranslationFormatted(), caster.getName())); - }else{ - sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success", - spell.getNameForTranslationFormatted())); + }else{ + + if(spell.cast(caster.world, caster, EnumHand.MAIN_HAND, 0, modifiers)){ + + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.COMMAND, spell, caster, modifiers)); + + if(spell.requiresPacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + // Only sent if the spell succeeded, because if the spell failed, you wouldn't + // need to spawn any particles! + IMessage msg = new PacketCastSpell.Message(caster.getEntityId(), null, spell, modifiers); + WizardryPacketHandler.net.sendToDimension(msg, caster.world.provider.getDimension()); + } + + if(server.sendCommandFeedback()){ + if(castAsOtherPlayer){ + sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success_remote", + spell.getNameForTranslationFormatted(), caster.getName())); + }else{ + sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":cast.success", + spell.getNameForTranslationFormatted())); + } + } + + return; } - return; } } - displayFailMessage(sender, spell); + if(server.sendCommandFeedback()) displayFailMessage(sender, spell); } } diff --git a/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java b/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java index d97e6470..84733924 100644 --- a/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java +++ b/src/main/java/electroblob/wizardry/command/CommandDiscoverSpell.java @@ -1,24 +1,19 @@ package electroblob.wizardry.command; -import java.util.List; - -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.event.DiscoverSpellEvent; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.command.NumberInvalidException; -import net.minecraft.command.PlayerNotFoundException; -import net.minecraft.command.WrongUsageException; +import net.minecraft.command.*; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraftforge.common.MinecraftForge; +import java.util.List; + public class CommandDiscoverSpell extends CommandBase { @Override @@ -92,7 +87,7 @@ public class CommandDiscoverSpell extends CommandBase { if(spell == null){ throw new NumberInvalidException("commands." + Wizardry.MODID + ":discoverspell.not_found", - new Object[]{arguments[i - 1]}); + arguments[i - 1]); } } @@ -110,32 +105,32 @@ public class CommandDiscoverSpell extends CommandBase { if(player == null) throw new PlayerNotFoundException("You must specify which player you wish to perform this action on."); - WizardData properties = WizardData.get(player); + WizardData data = WizardData.get(player); - if(properties != null){ + if(data != null){ if(clear){ - properties.spellsDiscovered.clear(); - sender.sendMessage( + data.spellsDiscovered.clear(); + if(server.sendCommandFeedback()) sender.sendMessage( new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.clear", player.getName())); }else if(all){ - properties.spellsDiscovered.addAll(Spell.getSpells(Spell.allSpells)); - sender.sendMessage( + data.spellsDiscovered.addAll(Spell.getSpells(Spell.allSpells)); + if(server.sendCommandFeedback()) sender.sendMessage( new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.all", player.getName())); }else{ - if(properties.hasSpellBeenDiscovered(spell)){ - properties.spellsDiscovered.remove(spell); - sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.removespell", + if(data.hasSpellBeenDiscovered(spell)){ + data.spellsDiscovered.remove(spell); + if(server.sendCommandFeedback()) sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.removespell", spell.getNameForTranslationFormatted(), player.getName())); }else{ if(!MinecraftForge.EVENT_BUS .post(new DiscoverSpellEvent(player, spell, DiscoverSpellEvent.Source.COMMAND))){ - properties.discoverSpell(spell); - sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.addspell", + data.discoverSpell(spell); + if(server.sendCommandFeedback()) sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.addspell", spell.getNameForTranslationFormatted(), player.getName())); } } } - properties.sync(); + data.sync(); } } } diff --git a/src/main/java/electroblob/wizardry/command/CommandSetAlly.java b/src/main/java/electroblob/wizardry/command/CommandSetAlly.java index 2ca42dfa..2ffcc375 100644 --- a/src/main/java/electroblob/wizardry/command/CommandSetAlly.java +++ b/src/main/java/electroblob/wizardry/command/CommandSetAlly.java @@ -1,16 +1,9 @@ package electroblob.wizardry.command; -import java.util.List; - -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; -import net.minecraft.command.ICommandSender; -import net.minecraft.command.NumberInvalidException; -import net.minecraft.command.PlayerNotFoundException; -import net.minecraft.command.WrongUsageException; +import net.minecraft.command.*; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.server.MinecraftServer; @@ -18,6 +11,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextFormatting; +import java.util.List; + public class CommandSetAlly extends CommandBase { @Override @@ -85,10 +80,12 @@ public class CommandSetAlly extends CommandBase { if(allyOf != sender && sender instanceof EntityPlayer && !WizardryUtilities.isPlayerOp((EntityPlayer)sender, server)){ // Displays a chat message if a non-op tries to modify another player's allies. - TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation( - "commands." + Wizardry.MODID + ":ally.permission"); - TextComponentTranslation2.getStyle().setColor(TextFormatting.RED); - allyOf.sendMessage(TextComponentTranslation2); + if(server.sendCommandFeedback()){ + TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation( + "commands." + Wizardry.MODID + ":ally.permission"); + TextComponentTranslation2.getStyle().setColor(TextFormatting.RED); + allyOf.sendMessage(TextComponentTranslation2); + } return; } @@ -102,15 +99,17 @@ public class CommandSetAlly extends CommandBase { if(allyOf == ally) throw new NumberInvalidException("commands." + Wizardry.MODID + ":ally.self"); - if(WizardData.get(allyOf) != null){ - String string = WizardData.get(allyOf).toggleAlly(ally) ? "add" : "remove"; - if(executeAsOtherPlayer){ - sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":ally." + string + "ally", - ally.getName(), allyOf.getName())); - // In this case, the player whose allies have been modified is also notified. - allyOf.sendMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName())); - }else{ - sender.sendMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName())); + if(server.sendCommandFeedback()){ + if(WizardData.get(allyOf) != null){ + String string = WizardData.get(allyOf).toggleAlly(ally) ? "add" : "remove"; + if(executeAsOtherPlayer){ + sender.sendMessage(new TextComponentTranslation("commands." + Wizardry.MODID + ":ally." + string + "ally", + ally.getName(), allyOf.getName())); + // In this case, the player whose allies have been modified is also notified. + allyOf.sendMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName())); + }else{ + sender.sendMessage(new TextComponentTranslation("item.wand." + string + "ally", ally.getName())); + } } } diff --git a/src/main/java/electroblob/wizardry/command/CommandViewAllies.java b/src/main/java/electroblob/wizardry/command/CommandViewAllies.java index 3bb82a2b..dde5e46d 100644 --- a/src/main/java/electroblob/wizardry/command/CommandViewAllies.java +++ b/src/main/java/electroblob/wizardry/command/CommandViewAllies.java @@ -1,12 +1,8 @@ package electroblob.wizardry.command; -import java.util.List; -import java.util.Set; - -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.client.resources.I18n; import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; @@ -18,6 +14,9 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextFormatting; +import java.util.List; +import java.util.Set; + public class CommandViewAllies extends CommandBase { @Override @@ -75,10 +74,12 @@ public class CommandViewAllies extends CommandBase { if(player != sender && sender instanceof EntityPlayer && !WizardryUtilities.isPlayerOp((EntityPlayer)sender, server)){ // Displays a chat message if a non-op tries to view another player's allies. - TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation( - "commands." + Wizardry.MODID + ":allies.permission"); - TextComponentTranslation2.getStyle().setColor(TextFormatting.RED); - player.sendMessage(TextComponentTranslation2); + if(server.sendCommandFeedback()){ + TextComponentTranslation TextComponentTranslation2 = new TextComponentTranslation( + "commands." + Wizardry.MODID + ":allies.permission"); + TextComponentTranslation2.getStyle().setColor(TextFormatting.RED); + player.sendMessage(TextComponentTranslation2); + } return; } @@ -101,6 +102,7 @@ public class CommandViewAllies extends CommandBase { playerList = new TextComponentTranslation("commands." + Wizardry.MODID + ":allies.none"); } + // Ignore sendCommandFeedback here since that's the entire point of this command if(executeAsOtherPlayer){ sender.sendMessage( new TextComponentTranslation("commands." + Wizardry.MODID + ":allies.list_other", player.getName(), playerList)); diff --git a/src/main/java/electroblob/wizardry/command/SpellEmitter.java b/src/main/java/electroblob/wizardry/command/SpellEmitter.java new file mode 100644 index 00000000..7a09e6b0 --- /dev/null +++ b/src/main/java/electroblob/wizardry/command/SpellEmitter.java @@ -0,0 +1,177 @@ +package electroblob.wizardry.command; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.SpellEmitterData; +import electroblob.wizardry.event.SpellCastEvent; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import io.netty.buffer.ByteBuf; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ITickable; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; + +/** + * A {@code SpellEmitter} represents a continuous spell being cast from a position via commands. + * + * @since Wizardry 4.2 + * @author Electroblob + */ +public class SpellEmitter implements ITickable { + + protected final Spell spell; + protected World world; + protected final double x, y, z; + protected final EnumFacing direction; + protected final int duration; + protected final SpellModifiers modifiers; + + protected int castingTick = 0; + protected boolean needsRemoving = false; + + protected SpellEmitter(Spell spell, World world, double x, double y, double z, EnumFacing direction, int duration, SpellModifiers modifiers){ + this.spell = spell; + this.world = world; + this.duration = duration; + this.x = x; + this.y = y; + this.z = z; + this.direction = direction; + this.modifiers = modifiers; + } + + /** Marks this spell emitter to be removed next tick. */ + protected void markForRemoval(){ + this.needsRemoving = true; + } + + /** Returns whether this spell emitter is marked for removal. */ + public boolean needsRemoving(){ + return needsRemoving; + } + + /** Returns the {@link SpellCastEvent.Source} that should be used for events fired by this spell emitter. */ + protected SpellCastEvent.Source getSource(){ + return SpellCastEvent.Source.COMMAND; + } + + /** Sets this spell emitter's world. This should only be used on the client side when the world has not yet been + * set, otherwise the world will not be changed and a warning will be printed to the console. */ + public void setWorld(World world){ + if(world.isRemote && this.world == null){ + this.world = world; + }else{ + Wizardry.logger.warn("Tried to change the world for a spell emitter, this shouldn't happen!"); + } + } + + @Override + public void update(){ + + if(castingTick < duration){ + + if(!MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(getSource(), spell, world, x, y, z, direction, modifiers, castingTick))){ + + if(spell.cast(world, x, y, z, direction, castingTick, duration, modifiers)){ + if(castingTick == 0) MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(getSource(), spell, world, x, y, z, direction, modifiers)); + castingTick++; + return; + } + } + } + // If the time ran out or the spell failed, interrupt spell casting + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Finish(getSource(), spell, world, x, y, z, direction, modifiers, castingTick)); + spell.finishCasting(world, null, x, y, z, direction, duration, modifiers); + markForRemoval(); + } + + /** Writes this {@code SpellEmitter} to the given ByteBuf. */ + public void write(ByteBuf buf){ + buf.writeInt(spell.networkID()); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeInt(direction.getIndex()); + // This is sent through as the duration, meaning castingTick always starts at zero client-side, which is + // important for sounds to work correctly. As a consequence, the client's castingTick will be different to the + // server value if the player changes dimension or re-logs. However, since this is pretty uncommon anyway I + // think it's an ok compromise. + buf.writeInt(duration - castingTick); + modifiers.write(buf); + } + + /** Reads a {@code SpellEmitter} from the given ByteBuf and returns it. */ + public static SpellEmitter read(ByteBuf buf){ + + Spell spell = Spell.byNetworkID(buf.readInt()); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + EnumFacing direction = EnumFacing.byIndex(buf.readInt()); + int duration = buf.readInt(); + SpellModifiers modifiers = new SpellModifiers(); + modifiers.read(buf); + + return new SpellEmitter(spell, null, x, y, z, direction, duration, modifiers); + } + + // INBTSerializable is annoying, it doesn't allow you to have final fields + + /** Returns a new {@link NBTTagCompound} representing this {@code SpellEmitter}. */ + public NBTTagCompound toNBT(){ + + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setInteger("spell", spell.metadata()); + nbt.setDouble("x", x); + nbt.setDouble("y", y); + nbt.setDouble("z", z); + nbt.setInteger("direction", direction.getIndex()); + nbt.setInteger("duration", duration); + nbt.setTag("modifiers", modifiers.toNBT()); + nbt.setInteger("castingTick", castingTick); + + return nbt; + } + + /** Creates a new {@code SpellEmitter} from the given {@link NBTTagCompound} and returns it. */ + public static SpellEmitter fromNBT(World world, NBTTagCompound nbt){ + + Spell spell = Spell.byMetadata(nbt.getInteger("spell")); + double x = nbt.getDouble("x"); + double y = nbt.getDouble("y"); + double z = nbt.getDouble("z"); + EnumFacing direction = EnumFacing.byIndex(nbt.getInteger("direction")); + int duration = nbt.getInteger("duration"); + SpellModifiers modifiers = SpellModifiers.fromNBT(nbt.getCompoundTag("modifiers")); + int castingTick = nbt.getInteger("castingTick"); + + SpellEmitter emitter = new SpellEmitter(spell, world, x, y, z, direction, duration, modifiers); + emitter.castingTick = castingTick; + return emitter; + } + + /** + * Creates a new {@code SpellEmitter} and adds it to the list of active emitters in {@link SpellEmitterData}. + * This method does not perform any syncing. + * + * @param spell The spell to be cast + * @param world The world in which to cast the spell + * @param x The x-coordinate of the spell origin + * @param y The y-coordinate of the spell origin + * @param z The z-coordinate of the spell origin + * @param direction The direction to cast the spell in + * @param duration The number of ticks to cast the spell for + * @param modifiers The {@link SpellModifiers} for the spell + */ + public static void add(Spell spell, World world, double x, double y, double z, EnumFacing direction, int duration, SpellModifiers modifiers){ + if(spell.isContinuous){ + if(duration <= 0) Wizardry.logger.warn("Adding a spell emitter with negative or zero duration!"); + SpellEmitterData.get(world).add(new SpellEmitter(spell, world, x, y, z, direction, duration, modifiers)); + }else{ + Wizardry.logger.warn("Tried to add a non-continuous spell emitter for spell {}", spell.getRegistryName()); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/constants/Constants.java b/src/main/java/electroblob/wizardry/constants/Constants.java index 28bba9a9..0316b4e3 100644 --- a/src/main/java/electroblob/wizardry/constants/Constants.java +++ b/src/main/java/electroblob/wizardry/constants/Constants.java @@ -5,23 +5,25 @@ import electroblob.wizardry.WizardryEventHandler; /** Stores various global constants used in Wizardry. */ public final class Constants { + /** The amount of mana a crystal shard is worth */ + // 100 doesn't divide nicely by 9 so we're calling this 10. I guess you lose a little bit by smashing a crystal. + public static final int MANA_PER_SHARD = 10; /** The amount of mana each magic crystal is worth */ public static final int MANA_PER_CRYSTAL = 100; - /** The amount of mana each mana flask can hold */ - public static final int MANA_PER_FLASK = 700; + /** The amount of mana a grand magic crystal is worth */ + public static final int GRAND_CRYSTAL_MANA = 400; /** The maximum number of one type of wand upgrade which can be applied to a wand. */ public static final int UPGRADE_STACK_LIMIT = 3; /** The fraction by which cooldowns are reduced for each level of cooldown upgrade. */ public static final float COOLDOWN_REDUCTION_PER_LEVEL = 0.15f; /** The fraction by which maximum charge is increased for each level of storage upgrade. */ public static final float STORAGE_INCREASE_PER_LEVEL = 0.15f; - /** The fraction by which damage is increased for each tier of matching wand. */ - public static final float DAMAGE_INCREASE_PER_TIER = 0.15f; - /** - * The fraction by which costs are reduced for each piece of matching armour. Note that changing this value will not - * affect continuous spells, since they are handled differently. - */ - public static final float COST_REDUCTION_PER_ARMOUR = 0.2f; + /** The fraction by which potency is increased for each tier of matching wand. */ + public static final float POTENCY_INCREASE_PER_TIER = 0.15f; + /** The fraction by which costs are reduced for each piece of matching armour. */ + public static final float COST_REDUCTION_PER_ARMOUR = 0.15f; + /** The extra fraction by which costs are reduced for a full set of elemental armour. */ + public static final float FULL_ARMOUR_SET_BONUS = 0.2f; /** The fraction by which spell duration is increased for each level of duration upgrade. */ public static final float DURATION_INCREASE_PER_LEVEL = 0.25f; /** The fraction by which spell range is increased for each level of range upgrade. */ @@ -32,7 +34,7 @@ public final class Constants { public static final double FROST_SLOWNESS_PER_LEVEL = 0.5; /** The fraction by which movement speed is reduced per level of decay effect. */ public static final double DECAY_SLOWNESS_PER_LEVEL = 0.2; - /** The fraction by which dig speed is reduced per level of frost effect. */ + /** The fraction by which dig speed is reduced per level of frostbite effect. */ public static final float FROST_FATIGUE_PER_LEVEL = 0.45f; /** The number of ticks between each mana increase for wands with the condenser upgrade. */ public static final int CONDENSER_TICK_INTERVAL = 50; @@ -40,11 +42,13 @@ public final class Constants { * The amount of mana given for a kill for each level of siphon upgrade. A random amount from 0 to this number - 1 * is also added. See {@link WizardryEventHandler#onLivingDeathEvent} for more details. */ - public static final int SIPHON_MANA_PER_LEVEL = 3; + public static final int SIPHON_MANA_PER_LEVEL = 5; /** * The number of ticks between the spawning of patches of decay when an entity has the decay effect. Note that decay * won't spawn again if something is already standing in it. */ public static final int DECAY_SPREAD_INTERVAL = 8; + /** The fraction by which potency is increased per level of the empowerment effect. */ + public static final float EMPOWERMENT_POTENCY_PER_LEVEL = 0.25f; } diff --git a/src/main/java/electroblob/wizardry/constants/Element.java b/src/main/java/electroblob/wizardry/constants/Element.java index dd357774..7b433693 100644 --- a/src/main/java/electroblob/wizardry/constants/Element.java +++ b/src/main/java/electroblob/wizardry/constants/Element.java @@ -1,7 +1,7 @@ package electroblob.wizardry.constants; import electroblob.wizardry.Wizardry; -import net.minecraft.client.resources.I18n; +import net.minecraft.util.IStringSerializable; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.Style; @@ -10,19 +10,18 @@ import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -public enum Element { +public enum Element implements IStringSerializable { - /** - * The 'default' element, with {@link electroblob.wizardry.spell.MagicMissile MagicMissile} being its only spell. - */ - MAGIC(new Style().setColor(TextFormatting.GRAY), "simple", Wizardry.MODID), - FIRE(new Style().setColor(TextFormatting.DARK_RED), "fire", Wizardry.MODID), - ICE(new Style().setColor(TextFormatting.AQUA), "ice", Wizardry.MODID), - LIGHTNING(new Style().setColor(TextFormatting.DARK_AQUA), "lightning", Wizardry.MODID), - NECROMANCY(new Style().setColor(TextFormatting.DARK_PURPLE), "necromancy", Wizardry.MODID), - EARTH(new Style().setColor(TextFormatting.DARK_GREEN), "earth", Wizardry.MODID), - SORCERY(new Style().setColor(TextFormatting.GREEN), "sorcery", Wizardry.MODID), - HEALING(new Style().setColor(TextFormatting.YELLOW), "healing", Wizardry.MODID); + /** The 'default' element, with {@link electroblob.wizardry.registry.Spells#magic_missile magic missile} being its + * only spell. */ + MAGIC(new Style().setColor(TextFormatting.GRAY), "magic"), + FIRE(new Style().setColor(TextFormatting.DARK_RED), "fire"), + ICE(new Style().setColor(TextFormatting.AQUA), "ice"), + LIGHTNING(new Style().setColor(TextFormatting.DARK_AQUA), "lightning"), + NECROMANCY(new Style().setColor(TextFormatting.DARK_PURPLE), "necromancy"), + EARTH(new Style().setColor(TextFormatting.DARK_GREEN), "earth"), + SORCERY(new Style().setColor(TextFormatting.GREEN), "sorcery"), + HEALING(new Style().setColor(TextFormatting.YELLOW), "healing"); /** Display colour for this element */ private final Style colour; @@ -31,16 +30,31 @@ public enum Element { /** The {@link ResourceLocation} for this element's 8x8 icon (displayed in the arcane workbench GUI) */ private final ResourceLocation icon; - private Element(Style colour, String name, String modid){ + Element(Style colour, String name){ + this(colour, name, Wizardry.MODID); + } + + Element(Style colour, String name, String modid){ this.colour = colour; this.unlocalisedName = name; this.icon = new ResourceLocation(modid, "textures/gui/element_icon_" + unlocalisedName + ".png"); } + /** Returns the element with the given name, or throws an {@link java.lang.IllegalArgumentException} if no such + * element exists. */ + public static Element fromName(String name){ + + for(Element element : values()){ + if(element.unlocalisedName.equals(name)) return element; + } + + throw new IllegalArgumentException("No such element with unlocalised name: " + name); + } + /** Returns the translated display name of this element, without formatting. */ @SideOnly(Side.CLIENT) public String getDisplayName(){ - return I18n.format("element." + getUnlocalisedName()); + return net.minecraft.client.resources.I18n.format("element." + getName()); } /** Returns the {@link Style} object representing the colour of this element. */ @@ -55,11 +69,12 @@ public enum Element { /** Returns the translated display name for wizards of this element, shown in the trading GUI. */ public ITextComponent getWizardName(){ - return new TextComponentTranslation("element." + getUnlocalisedName() + ".wizard"); + return new TextComponentTranslation("element." + getName() + ".wizard"); } - /** Returns this element's unlocalised name. */ - public String getUnlocalisedName(){ + /** Returns this element's unlocalised name. Also used as the serialised string in block properties. */ + @Override + public String getName(){ return unlocalisedName; } diff --git a/src/main/java/electroblob/wizardry/constants/SpellType.java b/src/main/java/electroblob/wizardry/constants/SpellType.java index e1791940..afefec7f 100644 --- a/src/main/java/electroblob/wizardry/constants/SpellType.java +++ b/src/main/java/electroblob/wizardry/constants/SpellType.java @@ -1,6 +1,5 @@ package electroblob.wizardry.constants; -import net.minecraft.client.resources.I18n; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -21,8 +20,23 @@ public enum SpellType { this.unlocalisedName = name; } + /** Returns the spell type with the given name, or throws an {@link java.lang.IllegalArgumentException} if no such + * spell type exists. */ + public static SpellType fromName(String name){ + + for(SpellType type : values()){ + if(type.unlocalisedName.equals(name)) return type; + } + + throw new IllegalArgumentException("No such spell type with unlocalised name: " + name); + } + + public String getUnlocalisedName(){ + return unlocalisedName; + } + @SideOnly(Side.CLIENT) public String getDisplayName(){ - return I18n.format("spelltype." + unlocalisedName); + return net.minecraft.client.resources.I18n.format("spelltype." + unlocalisedName); } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/constants/Tier.java b/src/main/java/electroblob/wizardry/constants/Tier.java index 2cadd2a0..5cf6bdd0 100644 --- a/src/main/java/electroblob/wizardry/constants/Tier.java +++ b/src/main/java/electroblob/wizardry/constants/Tier.java @@ -1,19 +1,20 @@ package electroblob.wizardry.constants; -import java.util.Random; - -import net.minecraft.client.resources.I18n; +import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.Random; + public enum Tier { - BASIC(700, 3, 12, new Style().setColor(TextFormatting.WHITE), "basic"), - APPRENTICE(1000, 5, 5, new Style().setColor(TextFormatting.AQUA), "apprentice"), - ADVANCED(1500, 7, 2, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"), - MASTER(2500, 9, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master"); + NOVICE(700, 3, 12, 0, new Style().setColor(TextFormatting.WHITE), "novice"), + APPRENTICE(1000, 5, 5, 6000, new Style().setColor(TextFormatting.AQUA), "apprentice"), + ADVANCED(1500, 7, 2, 9000, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"), + MASTER(2500, 9, 1, 15000, new Style().setColor(TextFormatting.DARK_PURPLE), "master"); /** Maximum mana a wand of this tier can store. */ public final int maxCharge; @@ -23,29 +24,59 @@ public enum Tier { public final int upgradeLimit; /** The weight given to this tier in the standard weighting. */ public final int weight; + /** The progression required for a wand to be upgraded to this tier. */ + public final int progression; /** The colour of text associated with this tier. */ // Changed to a Style object for consistency. private final Style colour; private final String unlocalisedName; - private Tier(int maxCharge, int upgradeLimit, int weight, Style colour, String name){ + Tier(int maxCharge, int upgradeLimit, int weight, int progression, Style colour, String name){ this.maxCharge = maxCharge; this.level = ordinal(); this.upgradeLimit = upgradeLimit; this.weight = weight; + this.progression = progression; this.colour = colour; this.unlocalisedName = name; } + /** Returns the tier with the given name, or throws an {@link java.lang.IllegalArgumentException} if no such + * tier exists. */ + public static Tier fromName(String name){ + + for(Tier tier : values()){ + if(tier.unlocalisedName.equals(name)) return tier; + } + + throw new IllegalArgumentException("No such tier with unlocalised name: " + name); + } + @SideOnly(Side.CLIENT) public String getDisplayName(){ - return I18n.format("tier." + unlocalisedName); + return net.minecraft.client.resources.I18n.format("tier." + unlocalisedName); + } + + /** + * Returns a {@code TextComponentTranslation} which will be translated to the display name of the tier, without + * formatting (i.e. not coloured). + */ + public TextComponentTranslation getNameForTranslation(){ + return new TextComponentTranslation("tier." + unlocalisedName); } @SideOnly(Side.CLIENT) public String getDisplayNameWithFormatting(){ - return this.getFormattingCode() + I18n.format("tier." + unlocalisedName); + return this.getFormattingCode() + net.minecraft.client.resources.I18n.format("tier." + unlocalisedName); + } + + /** + * Returns a {@code TextComponentTranslation} which will be translated to the display name of the tier, with + * formatting (i.e. coloured). + */ + public ITextComponent getNameForTranslationFormatted(){ + return new TextComponentTranslation("tier." + unlocalisedName).setStyle(this.colour); } public String getUnlocalisedName(){ diff --git a/src/main/java/electroblob/wizardry/data/BlockCastingData.java b/src/main/java/electroblob/wizardry/data/BlockCastingData.java new file mode 100644 index 00000000..a02d2de7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/data/BlockCastingData.java @@ -0,0 +1,183 @@ +package electroblob.wizardry.data; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.event.SpellCastEvent; +import electroblob.wizardry.packet.PacketDispenserCastSpell; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.None; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +/** + * Base class for {@link DispenserCastingData}. Originally this was written because command blocks had a similar system, + * but that was later removed in favour of spell emitters - however, this class has been kept so that others can use it + * for different spellcasting blocks if they wish. + * + * @since Wizardry 4.2 + * @author Electroblob + */ +public abstract class BlockCastingData implements INBTSerializable { + + /** The tile entity this BlockCastingData instance belongs to. */ + protected final T tileEntity; + + /** The continuous spell this tile entity is currently casting, or the {@link None} spell if it is not casting. */ + protected Spell spell; + /** The coordinates of the current continuous spell's origin. */ + protected double x, y, z; + /** The time for which this tile entity has been casting a continuous spell. Increments by 1 each tick. */ + protected int castingTick; + /** SpellModifiers object for the current continuous spell. */ + protected SpellModifiers modifiers; + + public BlockCastingData(T tileEntity){ + this.tileEntity = tileEntity; + this.spell = Spells.none; + this.modifiers = new SpellModifiers(); + this.castingTick = 0; + } + + /** Returns whether this tile entity is currently casting a continuous spell. */ + public boolean isCasting(){ + return this.spell != null && this.spell != Spells.none; + } + + /** Returns the continuous spell this tile entity is currently casting, or the {@link None} spell if it isn't + * casting anything. */ + public Spell currentlyCasting(){ + return spell; + } + + /** Starts casting the given continuous spell from this tile entity. */ + protected void startCasting(Spell spell, double x, double y, double z, SpellModifiers modifiers){ + + if(!spell.isContinuous){ + Wizardry.logger.warn("Tried to start casting a continuous spell from a tile entity, but the given spell was not continuous!"); + return; + } + + this.spell = spell; + this.x = x; + this.y = y; + this.z = z; + this.castingTick = 0; + this.modifiers = modifiers; + } + + /** Stops casting the current spell. */ + protected void stopCasting(){ + this.spell = Spells.none; + this.castingTick = 0; + this.modifiers.reset(); + } + + /** Stops casting the current spell and sends a packet to clients to update them. If called client-side, this just + * delegates to {@link BlockCastingData#stopCasting()}. */ + protected void stopCastingAndNotify(){ + + stopCasting(); + + if(!tileEntity.getWorld().isRemote){ + IMessage msg = new PacketDispenserCastSpell.Message(x, y, z, getDirection(), tileEntity.getPos(), spell, 0, modifiers); + WizardryPacketHandler.net.sendToDimension(msg, tileEntity.getWorld().provider.getDimension()); + } + } + + /** Called once per tick to update the block casting data. This is not called automatically, subclasses must + * do so using their own tick event handlers. */ + protected void update(){ + + if(this.tileEntity.isInvalid()){ + return; + } + + if(this.isCasting() && this.spell.isContinuous){ + + // If the dispenser has stopped receiving power, the spell stops immediately. + if(!shouldContinueCasting()){ + this.stopCasting(); // This seems to work fine on both sides, so no point sending a packet + return; + } + + EnumFacing direction = getDirection(); + + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(getSource(), spell, tileEntity.getWorld(), + x, y, z, direction, modifiers, castingTick))){ + // When the event is canceled client-side, this will stop the spell on the client only, as specified in + // the javadoc for SpellCastEvent.Tick. + this.stopCastingAndNotify(); + return; + } + + this.spell.cast(tileEntity.getWorld(), x, y, z, direction, castingTick, -1, modifiers); + + castingTick++; + + }else{ + this.castingTick = 0; + } + } + + /** Returns the direction to cast the current spell in. */ + protected abstract EnumFacing getDirection(); + + /** Returns the source of spells cast from this block. */ + protected abstract SpellCastEvent.Source getSource(); + + /** Called each tick during continuous spell casting to determine if the spell should continue or stop. */ + protected abstract boolean shouldContinueCasting(); + + @Override + public NBTTagCompound serializeNBT(){ + + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setInteger("spell", spell.metadata()); + nbt.setInteger("castingTick", castingTick); + nbt.setTag("modifiers", modifiers.toNBT()); + + return nbt; + } + + @Override + public void deserializeNBT(NBTTagCompound nbt){ + + if(nbt != null){ + + this.spell = Spell.byMetadata(nbt.getInteger("spell")); + this.castingTick = nbt.getInteger("castingTick"); + this.modifiers = SpellModifiers.fromNBT(nbt.getCompoundTag("modifiers")); + } + } + + // The two methods below broke EVERYTHING, somehow they made the server think it was the client... + +// // Only fired server-side +// @SubscribeEvent +// public static void onWorldTickEvent(TickEvent.WorldTickEvent event){ +// +// if(!event.world.isRemote && event.phase == TickEvent.Phase.END){ +// // This will fire once for each dimension, but since we want dispenser-casting to work in all dimensions, +// // this is correct (the loaded tile entity list will of course be different in each case. +// this.update(); +// } +// } +// +// // Only called client-side +// @SubscribeEvent +// public static void onClientTickEvent(TickEvent.ClientTickEvent event){ +// World world = net.minecraft.client.Minecraft.getMinecraft().world; +// if(event.phase == TickEvent.Phase.END && !net.minecraft.client.Minecraft.getMinecraft().isGamePaused() +// && world != null){ +// this.update(); +// } +// } + +} diff --git a/src/main/java/electroblob/wizardry/data/DispenserCastingData.java b/src/main/java/electroblob/wizardry/data/DispenserCastingData.java new file mode 100644 index 00000000..28d0fe56 --- /dev/null +++ b/src/main/java/electroblob/wizardry/data/DispenserCastingData.java @@ -0,0 +1,219 @@ +package electroblob.wizardry.data; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.event.SpellCastEvent.Source; +import electroblob.wizardry.item.ItemScroll; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.block.BlockDispenser; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityDispenser; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.Capability.IStorage; +import net.minecraftforge.common.capabilities.CapabilityInject; +import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.common.capabilities.ICapabilitySerializable; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.ArrayList; +import java.util.List; + +/** + * Internal capability for attaching data to dispensers. The sole purpose of this class is to keep track of continuous + * spell casting for dispensers. + *

    + * Forge seems to have separate classes to hold the Capability<...> instance ('key') and methods for getting the + * capability, but in my opinion there are already too many classes to deal with, so I'm not adding any more than are + * necessary, meaning those constants and values are kept here instead. + * + * @since Wizardry 4.2 + * @author Electroblob + */ +@Mod.EventBusSubscriber +public class DispenserCastingData extends BlockCastingData { + + /** Static instance of what I like to refer to as the capability key. Private because, well, it's internal! */ + // This annotation does some crazy Forge magic behind the scenes and assigns this field a value. + @CapabilityInject(DispenserCastingData.class) + private static final Capability DISPENSER_CASTING_CAPABILITY = null; + + /** The time for which this dispenser will continue casting a continuous spell. When castingTick exceeds this value, + * the dispenser will either stop casting or, if it contains more of the same type of scroll, continue casting and + * increase this value by the duration that the spell should be cast for. */ + private int duration; + + public DispenserCastingData(){ + this(null); // Nullary constructor for the registration method factory parameter + } + + public DispenserCastingData(TileEntityDispenser dispenser){ + super(dispenser); + } + + /** Starts casting the given continuous spell from this dispenser. */ + public void startCasting(Spell spell, double x, double y, double z, int duration, SpellModifiers modifiers){ + startCasting(spell, x, y, z, modifiers); + this.castingTick = 1; // 1 because we already cast it once in BehaviourSpellDispense + this.duration = duration; + } + + @Override + public void stopCasting(){ + super.stopCasting(); + } + + @Override + protected Source getSource(){ + return Source.DISPENSER; + } + + @Override + protected EnumFacing getDirection(){ + return tileEntity.getWorld().getBlockState(tileEntity.getPos()).getValue(BlockDispenser.FACING); + } + + @Override + protected boolean shouldContinueCasting(){ + return tileEntity.getWorld().isBlockPowered(tileEntity.getPos()); + } + + @Override + public void update(){ + + super.update(); + + // Check whether enough scrolls are left + if(this.isCasting() && this.spell.isContinuous){ + + if(castingTick > duration && !tileEntity.getWorld().isRemote){ + + if(findNewScroll()){ + duration += ItemScroll.CASTING_TIME; // Best way to do it for now. + }else{ + this.stopCastingAndNotify(); + } + } + } + } + + /** Searches through the dispenser's inventory for a new stack of scrolls of the same spell that is currently being + * cast and returns true if at least one such stack is found. Also consumes one scroll if a stack is found; if more + * than one applicable stack is found then one will be chosen at random. */ + private boolean findNewScroll(){ + + if(spell == Spells.none) return false; + + List slots = new ArrayList(); + + for(int i = 0; i < tileEntity.getSizeInventory(); i++){ + ItemStack stack = tileEntity.getStackInSlot(i); + if(stack.getItem() instanceof ItemScroll && stack.getMetadata() == spell.metadata()) slots.add(i); + } + + if(slots.isEmpty()) return false; // If no stack was found that matched the current spell + + tileEntity.decrStackSize(slots.get(tileEntity.getWorld().rand.nextInt(slots.size())), 1); // Consumes 1 scroll + return true; + } + + /** Returns the DispenserCastingData instance for the specified dispenser. */ + public static DispenserCastingData get(TileEntityDispenser dispenser){ + return dispenser.getCapability(DISPENSER_CASTING_CAPABILITY, null); + } + + /** Called from preInit in the main mod class to register the DispenserCastingData capability. */ + public static void register(){ + + CapabilityManager.INSTANCE.register(DispenserCastingData.class, new IStorage(){ + + @Override + public NBTBase writeNBT(Capability capability, DispenserCastingData instance, EnumFacing side){ + return null; + } + + @Override + public void readNBT(Capability capability, DispenserCastingData instance, EnumFacing side, NBTBase nbt){} + + }, DispenserCastingData::new); + } + + // Event handlers + + @SubscribeEvent + // The type parameter here has to be SoundLoopSpellDispenser, not TileEntityDispenser, or the event won't get fired. + public static void onCapabilityLoad(AttachCapabilitiesEvent event){ + + if(event.getObject() instanceof TileEntityDispenser) + event.addCapability(new ResourceLocation(Wizardry.MODID, "casting_data"), + new DispenserCastingData.Provider((TileEntityDispenser)event.getObject())); + } + + // Only fired server-side + @SubscribeEvent + public static void onWorldTickEvent(TickEvent.WorldTickEvent event){ + + if(event.phase == TickEvent.Phase.END){ + + // This will fire once for each dimension, but since we want dispenser-casting to work in all dimensions, + // this is correct (the loaded tile entity list will of course be different in each case. + + for(TileEntity tileentity : event.world.loadedTileEntityList){ + if(tileentity instanceof TileEntityDispenser){ + if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){ + DispenserCastingData.get((TileEntityDispenser)tileentity).update(); + } + } + } + } + } + + /** + * This is a nested class for a few reasons: firstly, it makes sense because instances of this and + * DispenserCastingData go hand-in-hand; secondly, it's too short to be worth a separate file; and thirdly (and most + * importantly) it allows me to access DISPENSER_CASTING_CAPABILITY while keeping it private. + */ + public static class Provider implements ICapabilitySerializable { + + private final DispenserCastingData data; + + public Provider(TileEntityDispenser dispenser){ + data = new DispenserCastingData(dispenser); + } + + @Override + public boolean hasCapability(Capability capability, EnumFacing facing){ + return capability == DISPENSER_CASTING_CAPABILITY; + } + + @Override + public T getCapability(Capability capability, EnumFacing facing){ + + if(capability == DISPENSER_CASTING_CAPABILITY){ + return DISPENSER_CASTING_CAPABILITY.cast(data); + } + + return null; + } + + @Override + public NBTTagCompound serializeNBT(){ + return data.serializeNBT(); + } + + @Override + public void deserializeNBT(NBTTagCompound nbt){ + data.deserializeNBT(nbt); + } + + } + +} diff --git a/src/main/java/electroblob/wizardry/data/IStoredVariable.java b/src/main/java/electroblob/wizardry/data/IStoredVariable.java new file mode 100644 index 00000000..f6594f57 --- /dev/null +++ b/src/main/java/electroblob/wizardry/data/IStoredVariable.java @@ -0,0 +1,256 @@ +package electroblob.wizardry.data; + +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.*; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.common.network.ByteBufUtils; + +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Extension of {@link IVariable} which adds NBT read/write methods. Instances of this interface must be + * registered on load using {@link WizardData#registerStoredVariables(IStoredVariable...)} in order for NBT storage + * to work. A good place to do this is in spell constructors, if that's where the variable is being used. + *

    + * This interface is provided for complex cases that require custom NBT handling of some kind. In most cases, + * {@link StoredVariable} should be sufficient. + *

    + * @param The type of variable stored. + */ +public interface IStoredVariable extends IVariable { + + /** Writes the value to the given NBT tag. */ + void write(NBTTagCompound nbt, T value); + + /** Reads the value from the given NBT tag. */ + T read(NBTTagCompound nbt); + + /** + * General-purpose implementation of {@link IStoredVariable}. In most cases, this should be sufficient. This class + * also contains a number of static methods for common implementations (primitives, {@code String}, {@code UUID}, + * {@code BlockPos} and {@code ItemStack}). + *

    + * @param The type of variable stored. + * @param The type of NBT tag the variable will be stored as. + */ + class StoredVariable implements IStoredVariable { + + private final String key; + private final Persistence persistence; + + private final Function serialiser; + private final Function deserialiser; + + private boolean synced; + + private BiFunction ticker; + + /** + * Creates a new {@code StoredVariable} with the given key and serialisation behaviour. + * @param key The string key used to write the value to NBT (should be unique). This serves no other purpose. + * @param serialiser A function used to write the value to NBT. + * @param deserialiser A function used to read the value from NBT. + */ + public StoredVariable(String key, Function serialiser, Function deserialiser, Persistence persistence){ + this.key = key; + this.serialiser = serialiser; + this.deserialiser = deserialiser; + this.persistence = persistence; + this.ticker = (p, t) -> t; // Initialise this with a do-nothing function, can be overwritten later + } + + /** + * Replaces this variable's update method with the given update function. Beware of auto-unboxing of + * primitive types! For lambda expressions, check the second parameter isn't null before operating on it. + * For method references, do not reference a method that takes a primitive type. Otherwise, this will cause + * a (difficult to debug) {@link NullPointerException} if the key was not stored. + * @param ticker A {@link BiFunction} specifying the actions to be performed on this variable each tick. The + * {@code BiFunction} returns the new value for this variable. + * @return This {@code StoredVariable} object, allowing this method to be chained onto object creation. + */ + public StoredVariable withTicker(BiFunction ticker){ + this.ticker = ticker; + return this; + } + + /** + * Adds synchronisation to this variable, meaning it will be sent to clients whenever {@link WizardData#sync()} + * is called (this always happens on player login, but other than that you'll need to do it yourself). + * @return This {@code StoredVariable} object, allowing this method to be chained onto object creation. + */ + public StoredVariable setSynced(){ + this.synced = true; + return this; + } + + @Override + public void write(NBTTagCompound nbt, T value){ + if(value != null) nbt.setTag(key, serialiser.apply(value)); + } + + @Override + @SuppressWarnings("unchecked") // Can't check it due to type erasure + public T read(NBTTagCompound nbt){ + // A system allowing any kind of variable to be stored on the fly cannot be made without casting somewhere. + // However, doing it like this means we only cast once, below, and proper regulation of access means we + // can effectively guarantee the cast is safe. + return nbt.hasKey(key) ? deserialiser.apply((E)nbt.getTag(key)) : null; // Still gotta check it ain't null + } + + @Override + public T update(EntityPlayer player, T value){ + return ticker.apply(player, value); + } + + @Override + public boolean isPersistent(boolean respawn){ + return respawn ? persistence.persistsOnRespawn() : persistence.persistsOnDimensionChange(); + } + + @Override + public boolean isSynced(){ + return synced; + } + + @Override + public void write(ByteBuf buf, T value){ + if(!synced) return; + NBTTagCompound nbt = new NBTTagCompound(); + write(nbt, value); + ByteBufUtils.writeTag(buf, nbt); // Sure, it's not super-efficient, but it's by far the simplest way! + } + + @Override + public T read(ByteBuf buf){ + if(!synced) return null; // Better to check in here because this method should only read if it needs to + NBTTagCompound nbt = ByteBufUtils.readTag(buf); + if(nbt == null) return null; + return read(nbt); + } + + // Standard implementations to shorten common usages a bit + + /** Creates a new {@code StoredVariable} for a byte value with the given key. */ + public static StoredVariable ofByte(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTTagByte::new, NBTTagByte::getByte, persistence); + } + + /** Creates a new {@code StoredVariable} for a boolean value with the given key. As per Minecraft's usual + * NBT conventions, the boolean value is stored as an {@link NBTTagByte} (1 = true, 0 = false). */ + public static StoredVariable ofBoolean(String key, Persistence persistence){ + return new StoredVariable<>(key, b -> new NBTTagByte((byte)(b?1:0)), t -> t.getByte() == 1, persistence); + } + + /** Creates a new {@code StoredVariable} for an integer value with the given key. */ + public static StoredVariable ofInt(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTTagInt::new, NBTTagInt::getInt, persistence); + } + + // I'm not going to do byte and long arrays here, if you really need them it's pretty obvious how to do it + + /** Creates a new {@code StoredVariable} for an integer array value with the given key. */ + public static StoredVariable ofIntArray(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTTagIntArray::new, NBTTagIntArray::getIntArray, persistence); + } + + /** Creates a new {@code StoredVariable} for a float value with the given key. */ + public static StoredVariable ofFloat(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTTagFloat::new, NBTTagFloat::getFloat, persistence); + } + + /** Creates a new {@code StoredVariable} for a double value with the given key. */ + public static StoredVariable ofDouble(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTTagDouble::new, NBTTagDouble::getDouble, persistence); + } + + /** Creates a new {@code StoredVariable} for a short value with the given key. */ + public static StoredVariable ofShort(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTTagShort::new, NBTTagShort::getShort, persistence); + } + + /** Creates a new {@code StoredVariable} for a long value with the given key. */ + public static StoredVariable ofLong(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTTagLong::new, NBTTagLong::getLong, persistence); + } + + /** Creates a new {@code StoredVariable} for a {@link String} value with the given key. */ + public static StoredVariable ofString(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTTagString::new, NBTTagString::getString, persistence); + } + + /** Creates a new {@code StoredVariable} for a {@link BlockPos} value with the given key. */ + public static StoredVariable ofBlockPos(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTUtil::createPosTag, NBTUtil::getPosFromTag, persistence); + } + + /** Creates a new {@code StoredVariable} for a {@link UUID} value with the given key. */ + public static StoredVariable ofUUID(String key, Persistence persistence){ + return new StoredVariable<>(key, NBTUtil::createUUIDTag, NBTUtil::getUUIDFromTag, persistence); + } + + /** Creates a new {@code StoredVariable} for an {@link ItemStack} value with the given key. */ + public static StoredVariable ofItemStack(String key, Persistence persistence){ + return new StoredVariable<>(key, ItemStack::serializeNBT, ItemStack::new, persistence); + } + + /** Creates a new {@code StoredVariable} for an {@link NBTTagCompound} value with the given key. */ + public static StoredVariable ofNBT(String key, Persistence persistence){ + return new StoredVariable<>(key, t -> t, t -> t, persistence); // No conversion required! + } + + // Neither of these work just ignore them + +// /** Creates a new {@code StoredVariable} for an {@link NBTTagCompound} value with the given key which stores the +// * given {@code IVariable} for an entity. Entities cannot be stored directly as an {@code IStoredVariable} +// * because they require a world instance on construction. */ +// @SuppressWarnings("unchecked") // Can't check it due to type erasure +// public static StoredVariable ofNBTForEntity(String key, Persistence persistence, IVariable toStore){ +// return ofNBT(key, persistence).withTicker((p, t) -> { +// if(WizardData.get(p) != null){ +// try{ +// T e = (T)EntityList.createEntityByIDFromName(new ResourceLocation(t.getString("entityType")), p.world); +// e.readFromNBT(t); +// WizardData.get(p).setVariable(toStore, e); +// }catch(ClassCastException e){ +// Wizardry.logger.error("Error reading entity from NBT: entity not of expected type", e); +// } +// } +// return t; +// }); +// } + +// /** Creates a new {@code StoredVariable} for an {@link Entity} value with the given key. The returned +// * {@code StoredVariable} has a ticker which extracts the entity from the given; this functionality will need to be +// * replicated in any replacement ticker function. */ +// @SuppressWarnings("unchecked") // Can't check it due to type erasure +// public static StoredVariable ofEntity(String key, Persistence persistence, IVariable storage){ +// // Well this is horrible +// return new IStoredVariable.StoredVariable<>(key, +// (T e) -> { +// NBTTagCompound nbt = new NBTTagCompound(); +// nbt.setString("entityType", EntityList.getKey(e).toString()); +// e.writeToNBT(nbt); +// return nbt; +// }, +// t -> null, persistence) +// .withTicker((p, e) -> { +// if(e == null){ +// try{ +// NBTTagCompound nbt = WizardData.get(p).getVariable(storage); +// if(nbt == null) return null; +// e = (T)EntityList.createEntityByIDFromName(new ResourceLocation(nbt.getString("entityType")), p.world); +// e.readFromNBT(nbt); +// return e; +// }catch(ClassCastException x){ +// Wizardry.logger.error("Error reading stored variable from NBT: entity not of expected type", x); +// } +// } +// return null; +// }); +// } + } +} diff --git a/src/main/java/electroblob/wizardry/data/IVariable.java b/src/main/java/electroblob/wizardry/data/IVariable.java new file mode 100644 index 00000000..3388be93 --- /dev/null +++ b/src/main/java/electroblob/wizardry/data/IVariable.java @@ -0,0 +1,118 @@ +package electroblob.wizardry.data; + +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayer; + +import java.util.function.BiFunction; + +/** + * Instances of this interface act as keys which allow spellData of any type to be stored in {@link WizardData} at + * runtime. This means spells (or anything else, for that matter) may define their own storedVariables to be stored + * with the player and handle those storedVariables themselves. This prevents {@code WizardData} from being cluttered + * with spell-specific fields and allows addon mods to leverage {@code WizardData} for their own spells or other data, + * rather than defining their own capability. This system is somewhat similar to {@code DataManager}. + *

    + * Instances should be created once and stored statically (or pseudo-statically) in some sensible location, such + * as a spell class. They can then be used as keys to access the values themselves via {@link WizardData}. + * Encapsulation can also be achieved by simply restricting access to the keys. + *

    + * @param The type of variable stored. + */ +public interface IVariable { + + // To reiterate, instances of this interface are KEYS. They are both accessors for the data and define how + // it is stored and handled, but they DO NOT CONTAIN THE ACTUAL DATA. + // Only one instance exists for each thing to be stored, and is shared across instances of WizardData. + + /** Convenience method that allows this variable to define tick behaviour. This is particularly useful for + * trivial operations such as decrementing a value, for which a dedicated event handling method would be + * unnecessarily verbose. */ + T update(EntityPlayer player, T value); + + /** + * Returns whether this variable persists when data is copied. + * @param respawn True if the player died and is respawning, false if they are just travelling between dimensions. + * @return True if the variable should be copied over, false if not. + */ + boolean isPersistent(boolean respawn); + + /** + * Returns whether this variable requires syncing with clients. + * @return True if the variable should be synced with clients, false if not. + */ + boolean isSynced(); + + /** + * Writes this variable's value to the given {@link ByteBuf}. + */ + void write(ByteBuf buf, T value); + + /** + * Reads this variable's value from the given {@link ByteBuf}. + */ + T read(ByteBuf buf); + + /** If you're storing a lot of data, you can optionally implement this method to define a condition which, if + * satisfied, will result in the data being removed from storage, reducing unnecessary syncing and saving. This + * is particularly relevant if the value is synced as it reduces packet size. */ + default boolean canPurge(EntityPlayer player, T value){ + return false; + } + + /** + * General-purpose implementation of {@link IVariable} for non-stored variables. These may still, however, persist + * across player respawn/dimension change. + *

    + * @param The type of variable stored. + */ + class Variable implements IVariable { + + private final Persistence persistence; + + private BiFunction ticker; + + public Variable(Persistence persistence){ + this.persistence = persistence; + this.ticker = (p, t) -> t; + } + + /** + * Replaces this variable's update method with the given update function. Beware of auto-unboxing of + * primitive types! For lambda expressions, check the second parameter isn't null before operating on it. + * For method references, do not reference a method that takes a primitive type. Otherwise, this will cause + * a (difficult to debug) {@link NullPointerException} if the key was not stored. + * @param ticker A {@link BiFunction} specifying the actions to be performed on this variable each tick. The + * {@code BiFunction} returns the new value for this variable. + * @return This {@code Variable} object, allowing this method to be chained onto object creation. + */ + public Variable withTicker(BiFunction ticker){ + this.ticker = ticker; + return this; + } + + @Override + public T update(EntityPlayer player, T value){ + return ticker.apply(player, value); + } + + @Override + public boolean isPersistent(boolean respawn){ + return respawn ? persistence.persistsOnRespawn() : persistence.persistsOnDimensionChange(); + } + + @Override + public boolean isSynced(){ + return false;// Not implemented for now, maybe we will one day + } + + @Override + public void write(ByteBuf buf, T value){ + // NYI + } + + @Override + public T read(ByteBuf buf){ + return null; // NYI + } + } +} diff --git a/src/main/java/electroblob/wizardry/data/Persistence.java b/src/main/java/electroblob/wizardry/data/Persistence.java new file mode 100644 index 00000000..8babc457 --- /dev/null +++ b/src/main/java/electroblob/wizardry/data/Persistence.java @@ -0,0 +1,25 @@ +package electroblob.wizardry.data; + +/** Enum which defines the circumstances in which an {@link IVariable} persists, i.e. whether its value is carried over. */ +public enum Persistence { + + NEVER(false, false), + DIMENSION_CHANGE(false, true), + RESPAWN(true, false), + ALWAYS(true, true); + + private boolean persistsOnRespawn, persistsOnDimensionChange; + + Persistence(boolean persistsOnRespawn, boolean persistsOnDimensionChange){ + this.persistsOnRespawn = persistsOnRespawn; + this.persistsOnDimensionChange = persistsOnDimensionChange; + } + + public boolean persistsOnRespawn(){ + return persistsOnRespawn; + } + + public boolean persistsOnDimensionChange(){ + return persistsOnDimensionChange; + } +} diff --git a/src/main/java/electroblob/wizardry/data/SpellEmitterData.java b/src/main/java/electroblob/wizardry/data/SpellEmitterData.java new file mode 100644 index 00000000..a3178303 --- /dev/null +++ b/src/main/java/electroblob/wizardry/data/SpellEmitterData.java @@ -0,0 +1,128 @@ +package electroblob.wizardry.data; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.command.SpellEmitter; +import electroblob.wizardry.packet.PacketEmitterData; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.NBTExtras; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; +import net.minecraft.world.storage.WorldSavedData; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class responsible for storing and keeping track of {@link SpellEmitter}s. Each world has its own instance of + * {@code SpellEmitterData} which can be retrieved using {@link SpellEmitterData#get(World)}.
    + *
    + * To add a new {@code SpellEmitter}, use {@link SpellEmitter#add(Spell, World, double, double, double, EnumFacing, int, SpellModifiers)}. + * + * @since Wizardry 4.2 + * @author Electroblob + */ +@Mod.EventBusSubscriber +public class SpellEmitterData extends WorldSavedData { + + public static final String NAME = Wizardry.MODID + "_spell_emitters"; + + private final List emitters = new ArrayList<>(); + + private NBTTagList emitterTags = null; + + // Required constructors + public SpellEmitterData(){ + this(NAME); + } + + public SpellEmitterData(String name){ + super(name); + } + + /** Returns the spell emitter data for this world, or creates a new instance if it doesn't exist yet. */ + public static SpellEmitterData get(World world){ + + SpellEmitterData instance = (SpellEmitterData)world.getPerWorldStorage().getOrLoadData(SpellEmitterData.class, NAME); + + if(instance == null){ + instance = new SpellEmitterData(); + world.getPerWorldStorage().setData(NAME, instance); + }else if(instance.emitters.isEmpty() && instance.emitterTags != null){ + instance.loadEmitters(world); + } + + return instance; + } + + /** Sends the active spell emitters for this world to the specified player's client. */ + public void sync(EntityPlayerMP player){ + PacketEmitterData.Message msg = new PacketEmitterData.Message(emitters); + WizardryPacketHandler.net.sendTo(msg, player); + Wizardry.logger.info("Synchronising spell emitters for " + player.getName()); + } + + /** Adds the given {@link SpellEmitter} to the list of emitters for this {@code SpellEmitterData}. */ + public void add(SpellEmitter emitter){ + emitters.add(emitter); + markDirty(); + } + + @Override + public void readFromNBT(NBTTagCompound nbt){ + emitterTags = nbt.getTagList("emitters", Constants.NBT.TAG_COMPOUND); + } + + private void loadEmitters(World world){ + emitters.clear(); + emitters.addAll(NBTExtras.NBTToList(emitterTags, (NBTTagCompound t) -> SpellEmitter.fromNBT(world, t))); + emitterTags = null; // Now we know it's loaded + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound compound){ + compound.setTag("emitters", NBTExtras.listToNBT(emitters, SpellEmitter::toNBT)); + return compound; + } + + public static void update(World world){ + SpellEmitterData data = SpellEmitterData.get(world); + if(!data.emitters.isEmpty()){ + data.emitters.forEach(SpellEmitter::update); + data.emitters.removeIf(SpellEmitter::needsRemoving); + data.markDirty(); // Mark dirty if there are changes to be saved + } + } + + @SubscribeEvent + public static void tick(TickEvent.WorldTickEvent event){ + if(!event.world.isRemote && event.phase == TickEvent.Phase.END){ + update(event.world); + } + } + + @SubscribeEvent + public static void onWorldLoadEvent(WorldEvent.Load event){ + // Called to initialise the spell emitter data when a world loads, if it isn't already. + SpellEmitterData.get(event.getWorld()); + } + + @SubscribeEvent + public static void onPlayerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event){ + // Needs to be done here as well as PlayerLoggedInEvent because SpellEmitterData is dimension-specific + if(event.player instanceof EntityPlayerMP){ + SpellEmitterData.get(event.player.world).sync((EntityPlayerMP)event.player); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/SpellGlyphData.java b/src/main/java/electroblob/wizardry/data/SpellGlyphData.java similarity index 85% rename from src/main/java/electroblob/wizardry/SpellGlyphData.java rename to src/main/java/electroblob/wizardry/data/SpellGlyphData.java index 58f0635a..03fc3f89 100644 --- a/src/main/java/electroblob/wizardry/SpellGlyphData.java +++ b/src/main/java/electroblob/wizardry/data/SpellGlyphData.java @@ -1,13 +1,6 @@ -package electroblob.wizardry; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import org.apache.commons.lang3.RandomStringUtils; +package electroblob.wizardry.data; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.packet.PacketGlyphData; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.spell.Spell; @@ -20,6 +13,9 @@ import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.commons.lang3.RandomStringUtils; + +import java.util.*; /** * Class responsible for generating and storing the randomised spell names and descriptions for each world, which are @@ -32,8 +28,8 @@ public class SpellGlyphData extends WorldSavedData { public static final String NAME = Wizardry.MODID + "_glyphData"; - public Map randomNames = new HashMap(Spell.getTotalSpellCount()); - public Map randomDescriptions = new HashMap(Spell.getTotalSpellCount()); + public Map randomNames = new HashMap<>(Spell.getTotalSpellCount()); + public Map randomDescriptions = new HashMap<>(Spell.getTotalSpellCount()); // Required constructors public SpellGlyphData(){ @@ -110,12 +106,16 @@ public class SpellGlyphData extends WorldSavedData { /** Sends the random spell names for this world to the specified player's client. */ public void sync(EntityPlayerMP player){ - List names = new ArrayList(); - List descriptions = new ArrayList(); + List names = new ArrayList<>(); + List descriptions = new ArrayList<>(); - for(Spell spell : Spell.getSpells(Spell.allSpells)){ + int id = 0; + + while(id < Spell.getTotalSpellCount()){ + Spell spell = Spell.byNetworkID(id + 1); // +1 because the None spell is not included names.add(this.randomNames.get(spell)); descriptions.add(this.randomDescriptions.get(spell)); + id++; } PacketGlyphData.Message msg = new PacketGlyphData.Message(names, descriptions); @@ -144,15 +144,15 @@ public class SpellGlyphData extends WorldSavedData { @Override public void readFromNBT(NBTTagCompound nbt){ - this.randomNames = new HashMap(); - this.randomDescriptions = new HashMap(); + this.randomNames = new HashMap<>(); + this.randomDescriptions = new HashMap<>(); NBTTagList tagList = nbt.getTagList("spellGlyphData", NBT.TAG_COMPOUND); for(int i = 0; i < tagList.tagCount(); i++){ NBTTagCompound tag = tagList.getCompoundTagAt(i); - randomNames.put(Spell.get(tag.getInteger("spell")), tag.getString("name")); - randomDescriptions.put(Spell.get(tag.getInteger("spell")), tag.getString("description")); + randomNames.put(Spell.byMetadata(tag.getInteger("spell")), tag.getString("name")); + randomDescriptions.put(Spell.byMetadata(tag.getInteger("spell")), tag.getString("description")); } } @@ -165,7 +165,7 @@ public class SpellGlyphData extends WorldSavedData { // Much like the enchantments tag for items, this stores a list of spell-id-to-name tag pairs // The description is now also included; there's no point in making a second compound tag! NBTTagCompound tag = new NBTTagCompound(); - tag.setInteger("spell", spell.id()); + tag.setInteger("spell", spell.metadata()); tag.setString("name", this.randomNames.get(spell)); tag.setString("description", this.randomDescriptions.get(spell)); tagList.appendTag(tag); @@ -180,7 +180,6 @@ public class SpellGlyphData extends WorldSavedData { public static void onWorldLoadEvent(WorldEvent.Load event){ if(!event.getWorld().isRemote && event.getWorld().provider.getDimension() == 0){ // Called to initialise the spell glyph data when a world loads, if it isn't already. - // NOTE: Do we actually need this, or can we just let it initialise the first time it is needed? (see below) SpellGlyphData.get(event.getWorld()); } } diff --git a/src/main/java/electroblob/wizardry/WizardData.java b/src/main/java/electroblob/wizardry/data/WizardData.java similarity index 51% rename from src/main/java/electroblob/wizardry/WizardData.java rename to src/main/java/electroblob/wizardry/data/WizardData.java index fd27d9c0..433e3855 100644 --- a/src/main/java/electroblob/wizardry/WizardData.java +++ b/src/main/java/electroblob/wizardry/data/WizardData.java @@ -1,53 +1,35 @@ -package electroblob.wizardry; +package electroblob.wizardry.data; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.UUID; - -import electroblob.wizardry.constants.Element; +import com.google.common.collect.EvictingQueue; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.enchantment.Imbuement; -import electroblob.wizardry.entity.EntityShield; import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent.Source; -import electroblob.wizardry.integration.DamageSafetyChecker; import electroblob.wizardry.packet.PacketCastContinuousSpell; import electroblob.wizardry.packet.PacketPlayerSync; -import electroblob.wizardry.packet.PacketTransportation; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.spell.None; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.MagicDamage; -import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.Enchantment; -import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Items; -import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.item.ItemEnchantedBook; import net.minecraft.item.ItemStack; import net.minecraft.nbt.*; -import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.BlockPos; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.Capability.IStorage; import net.minecraftforge.common.capabilities.CapabilityInject; +import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.INBTSerializable; @@ -59,11 +41,16 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.*; +import java.util.stream.Collectors; + /** * Capability-based replacement for the old ExtendedPlayer class from 1.7.10. This has been reworked to leave minimum * external changes (for my own sanity, mainly!). Turns out the only major difference between an internal capability and * an IEEP is a couple of redundant classes and a different way of registering it. - *

    + *

    * Forge seems to have separate classes to hold the Capability<...> instance ('key') and methods for getting the * capability, but in my opinion there are already too many classes to deal with, so I'm not adding any more than are * necessary, meaning those constants and values are kept here instead. @@ -80,86 +67,172 @@ public class WizardData implements INBTSerializable { @CapabilityInject(WizardData.class) private static final Capability WIZARD_DATA_CAPABILITY = null; + /** Internal storage of registered variable keys. This only contains the stored keys. */ + private static final Set storedVariables = new HashSet<>(); + + /** The maximum number of recent spells to track. */ + public static final int MAX_RECENT_SPELLS = 10; + /** The player this WizardData instance belongs to. */ private final EntityPlayer player; - // This one is still necessary, because I can't override the equip animation for items that aren't from Wizardry. - private Map imbuementDurations; + /** An instance of {@link Random} which is guaranteed to produce the same number sequence client and server + * side provided that it is always called from common code. This can be useful in reducing the number of + * packets sent in certain situations.
    + *
    + * This is achieved by setting the seed to a new random value each time {@link WizardData#sync()} is called and + * sending this to the client so it can also set its seed to that value. */ + public final Random synchronisedRandom; - public boolean hasSpiritWolf; - public boolean hasSpiritHorse; + /** Whether this player is currently casting a continuous spell via commands. Not saved over world reload and reset + * on player death. */ + private Spell castCommandSpell; + /** The time for which this player has been casting a continuous spell via commands. Increments by 1 each tick. Not + * saved over world reload and reset on player death. */ + private int castCommandTick; + /** SpellModifiers object for the current continuous spell cast via commands. Not saved over world reload and reset + * on player death. */ + private SpellModifiers castCommandModifiers; + /** The number of ticks this player's current continuous spell lasts for, or null if there is none. Not saved over + * world reload and reset on player death. */ + private int castCommandDuration; - /** - * Whether this player is currently casting a continuous spell via commands. Not saved over world reload and reset - * on player death. - */ - private Spell currentlyCasting; - /** - * The time for which this player has been casting a continuous spell via commands. Increments by 1 each tick. Not - * saved over world reload and reset on player death. - */ - private int castingTick; - /** - * SpellModifiers object for the current continuous spell cast via commands. Not saved over world reload and reset - * on player death. - */ - private SpellModifiers spellModifiers; - /** Coordinates for the saved transportation stone circle location. Will be null if no location is saved. */ - private BlockPos stoneCircleLocation; - /** Dimension id which the saved stone circle is in. */ - private int stoneCircleDimension; - /** Time left until the player teleports under the effect of transportation */ - private int tpCountdown; - - /** Coordinates for the saved clairvoyance location. Will be null if no location is saved. */ - private BlockPos clairvoyanceLocation; - /** Dimension id which the saved clairvoyance point is in. */ - private int clairvoyanceDimension; - - public EntityShield shield; + /** SpellModifiers object for the current continuous spell cast via items. Not saved over world reload and reset + * on player death. N.B. Since a player can only use one item at a time, this can be reused for any item that + * casts spells, it's not just for wands.*/ + public SpellModifiers itemCastingModifiers; public WeakReference selectedMinion; - /** - * Set of this player's discovered spells. Do not write to this list directly, use - * {@link WizardData#discoverSpell(Spell)} instead. - */ + /** Set of this player's discovered spells. Do not write to this list directly, use + * {@link WizardData#discoverSpell(Spell)} instead. */ public Set spellsDiscovered; private Set allies; - /** - * List of usernames of this player's allies. May not be accurate 100% of the time. This is here so that a player + /** List of usernames of this player's allies. May not be accurate 100% of the time. This is here so that a player * can view the usernames of their allies even when those allies are not online. Do not use this for any other - * purpose than displaying the names! - */ + * purpose than displaying the names! */ public Set allyNames; - private Set soulboundCreatures; - + /** Internal storage of custom (spell-specific) data. Note that a {@code Map} cannot specify that its values are of + * the same type as the type parameter of its keys, so to ensure this condition always holds, the map must only + * be modified via {@link WizardData#setVariable(IVariable, Object)}, which (as a method) is able to enforce it. */ + private final Map spellData; + + private Queue recentSpells; + + // This one is still necessary, because I can't override the equip animation for items that aren't from Wizardry. + // Leaving this for now because merging it into the spell data system will be more tricky + private Map imbuementDurations; + + /** Stores this player's y velocity from the previous tick; used for the velocity-based fall damage replacement. */ + public double prevMotionY; + public WizardData(){ this(null); // Nullary constructor for the registration method factory parameter } public WizardData(EntityPlayer player){ this.player = player; - this.imbuementDurations = new HashMap(); - this.spellsDiscovered = new HashSet(); + this.synchronisedRandom = new Random(); + this.imbuementDurations = new HashMap<>(); + this.spellsDiscovered = new HashSet<>(); // All players can recognise magic missile. This is not done using discoverSpell because that seems to cause - // a crash on load occasionally (probably something to do with achievements being initalised) + // a crash on load occasionally (probably something to do with achievements being initialised) this.spellsDiscovered.add(Spells.magic_missile); - this.hasSpiritWolf = false; - this.hasSpiritHorse = false; - this.currentlyCasting = Spells.none; - this.spellModifiers = new SpellModifiers(); - this.castingTick = 0; - this.stoneCircleDimension = 0; - this.clairvoyanceDimension = 0; - this.setTpCountdown(0); - this.allies = new HashSet(); - this.allyNames = new HashSet(); - this.soulboundCreatures = new HashSet(); + this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS); // Only keeps a reference to the last 10 spells cast + this.castCommandSpell = Spells.none; + this.castCommandModifiers = new SpellModifiers(); + this.castCommandTick = 0; + this.itemCastingModifiers = new SpellModifiers(); + this.allies = new HashSet<>(); + this.allyNames = new HashSet<>(); + this.spellData = new HashMap<>(); } + /** Called from preInit in the main mod class to register the WizardData capability. */ + public static void register(){ + + // Yes - by the looks of it, having an interface is completely unnecessary in this case. + CapabilityManager.INSTANCE.register(WizardData.class, new IStorage(){ + // These methods are only called by Capability.writeNBT() or Capability.readNBT(), which in turn are + // NEVER CALLED. Unless I'm missing some reflective invocation, that means this entire class serves only + // to allow capabilities to be saved and loaded manually. What that would be useful for I don't know. + // (If an API forces most users to write redundant code for no reason, it's not user friendly, is it?) + // ... well, that's my rant for today! + @Override + public NBTBase writeNBT(Capability capability, WizardData instance, EnumFacing side){ + return null; + } + + @Override + public void readNBT(Capability capability, WizardData instance, EnumFacing side, NBTBase nbt){} + + }, WizardData::new); + } + + /** Returns the WizardData instance for the specified player. */ + public static WizardData get(EntityPlayer player){ + return player.getCapability(WIZARD_DATA_CAPABILITY, null); + } + + // ============================================= Variable Storage ============================================= + + // This is my answer to having spells define their own player variables. It's not the prettiest system ever, but + // I think the ability to add arbitrary data to this class and have it save itself to NBT automatically is pretty + // powerful. If it doesn't need saving, this can even be done on the fly - no registration necessary. + + // The reason we have interfaces here is to allow custom implementations of the NBT read/write methods, for + // example, reading/writing multiple keys without having to wrap them in an NBTTagCompound. + + /** Registers the given {@link IStoredVariable} objects as keys that will be stored to NBT for each {@code WizardData} + * instance. */ + public static void registerStoredVariables(IStoredVariable... variables){ + storedVariables.addAll(Arrays.asList(variables)); + } + + /** Returns a set containing the registered {@link IStoredVariable} objects for which {@link IVariable#isSynced()} + * returns true. Used internally for packet reading. */ + public static Set getSyncedVariables(){ + return storedVariables.stream().filter(IVariable::isSynced).collect(Collectors.toSet()); + } + + /** + * Stores the given value under the given key in this {@code WizardData} object. + * @param variable The key under which the value is to be stored. See {@link IVariable} for more details. + * @param value The value to be stored. + * @param The type of the value to be stored. Note that the given variable (key) may be of a supertype of the + * stored value itself; however, when the value is retrieved its type will match that of the key. In + * other words, if an {@code Integer} is stored under a {@code IVariable}, a {@code Number} will + * be returned when the value is retrieved. + */ + // This use of type parameters guarantees that spellData may only be stored (and therefore may only be accessed) + // using a compatible key. For instance, the following code will not compile: + // Number i = 1; + // setVariable(StoredVariable.ofInt("key", Persistence.ALWAYS), i); + public void setVariable(IVariable variable, T value){ + this.spellData.put(variable, value); + } + + /** + * Returns the value stored under the given key in this {@code WizardData} object, or null if the key was not + * stored. + * @param variable The key whose associated value is to be returned. + * @param The type of the returned value. + * @return The value associated with the given key, or null no such key was stored. Beware of auto-unboxing + * of primitive types! Directly assigning the result to a primitive type, as in {@code int i = getVariable(...)}, + * will cause a {@link NullPointerException} if the key was not stored. + */ + @SuppressWarnings("unchecked") // The spellData map is fully encapsulated so we can be sure that the cast is safe + @Nullable + public T getVariable(IVariable variable){ + return (T)spellData.get(variable); + } + + // ============================================== Miscellaneous ============================================== + + // Spell discovery + public boolean hasSpellBeenDiscovered(Spell spell){ return spellsDiscovered.contains(spell) || spell instanceof None; } @@ -175,66 +248,34 @@ public class WizardData implements INBTSerializable { public boolean discoverSpell(Spell spell){ if(spellsDiscovered == null){ - spellsDiscovered = new HashSet(); + spellsDiscovered = new HashSet<>(); } // The 'none' spell cannot be discovered if(spell instanceof None) return false; // Tries to add the spell to the list of discovered spells, and returns false if it was already present - if(!spellsDiscovered.add(spell)) return false; - // If the spell had not already been discovered, achievements can be triggered and the method returns true - if(spellsDiscovered.containsAll(Spell.getSpells(Spell::isEnabled))){ - WizardryAdvancementTriggers.all_spells.triggerFor(this.player); - } - - for(Element element : Element.values()){ - if(element != Element.MAGIC - && spellsDiscovered.containsAll(Spell.getSpells(new Spell.TierElementFilter(null, element)))){ - WizardryAdvancementTriggers.element_master.triggerFor(this.player); - } - } - - return true; + return spellsDiscovered.add(spell); } - /** Sets the player's saved transportation stone location and dimension. */ - public void setStoneCircleLocation(BlockPos pos, int dimensionID){ - this.stoneCircleLocation = pos; - this.stoneCircleDimension = dimensionID; + // Recent spell tracking + + /** + * Adds the given spell to this player's recently-cast spells. Spells can (and will) be added multiple times, and + * will be automatically removed when enough spells are added after them. + * @param spell The spell to be tracked. + */ + public void trackRecentSpell(Spell spell){ + this.recentSpells.add(spell); } - /** Returns the coordinates of the associated player's saved transportation stone circle. */ - public BlockPos getStoneCircleLocation(){ - return stoneCircleLocation; + /** + * Returns the number of times the given spell is tracked in this player's recently-cast spells. + * @param spell The spell to count casts for. + */ + public int countRecentCasts(Spell spell){ + return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 10 } - /** Returns the dimension ID of the associated player's saved transportation stone circle. */ - public int getStoneCircleDimension(){ - return stoneCircleDimension; - } - - public int getTpCountdown(){ - return tpCountdown; - } - - public void setTpCountdown(int tpCountdown){ - this.tpCountdown = tpCountdown; - } - - /** Sets the player's saved clairvoyance location. */ - public void setClairvoyancePoint(BlockPos pos, int dimensionID){ - this.clairvoyanceLocation = pos; - this.clairvoyanceDimension = dimensionID; - } - - /** Returns the coordinates for the saved clairvoyance location. Will be null if no location is saved. */ - public BlockPos getClairvoyanceLocation(){ - return clairvoyanceLocation; - } - - /** Returns the dimension ID for the saved clairvoyance location. Will be null if no location is saved. */ - public int getClairvoyanceDimension(){ - return clairvoyanceDimension; - } + // Imbuements /** * Overwrites the imbuement duration associated with the given imubement for this player, or creates it if there was @@ -282,7 +323,7 @@ public class WizardData implements INBTSerializable { NBTTagList enchantmentList = stack.getItem() == Items.ENCHANTED_BOOK ? ItemEnchantedBook.getEnchantments(stack) : stack.getEnchantmentTagList(); - Iterator iterator =enchantmentList.iterator(); + Iterator iterator = enchantmentList.iterator(); // For each of the item's enchantments while(iterator.hasNext()){ NBTTagCompound enchantmentTag = (NBTTagCompound) iterator.next(); @@ -296,9 +337,8 @@ public class WizardData implements INBTSerializable { this.imbuementDurations.put((Imbuement)enchantment, duration - 1); // Adds this imbuement to the set of imbuements that need to be kept activeImbuements.add((Imbuement)enchantment); - // Otherwise: }else{ - // Removes the enchantment from the item + // Otherwise, removes the enchantment from the item iterator.remove(); } } @@ -309,6 +349,8 @@ public class WizardData implements INBTSerializable { this.imbuementDurations.keySet().retainAll(activeImbuements); } + // Ally designation system + /** * Adds the given player to the list of allies belonging to the associated player, or removes the player if they are * already in the list of allies. Returns true if the player was added, false if they were removed. @@ -331,48 +373,26 @@ public class WizardData implements INBTSerializable { return this.allies.contains(player.getUniqueID()) || this.player.isOnSameTeam(player); } - /** Adds the given entity to this player's list of soulbound creatures, and returns whether it succeeded. */ - public boolean soulbind(EntityLivingBase target){ - return this.soulboundCreatures.add(target.getUniqueID()); + /** Returns whether the player with the given UUID is in this player's list of allies. The player to whom the given + * UUID belongs need not be logged in. This method is intended for use by owned entities so that their owner's + * allies don't accidentally damage them, even when the owner is offline. */ + public boolean isPlayerAlly(UUID playerUUID){ + // Scoreboard teams use usernames, but since we keep a cache of those... + return this.allies.contains(playerUUID) || (this.player.getTeam() != null && this.player.getTeam().getMembershipCollection() != null + && this.player.getTeam().getMembershipCollection().stream().anyMatch(allyNames::contains)); } - /** Returns whether the given entity has been soulbound to this player. */ - public boolean isCreatureSoulbound(EntityPlayer target){ - return this.soulboundCreatures.contains(target.getUniqueID()); - } - - /** - * Damages all creatures soulbound to this player by the given amount, and removes from the list any that no longer - * exist. - */ - public void damageAllSoulboundCreatures(float damage, String originalSourceName){ - - for(Iterator iterator = this.soulboundCreatures.iterator(); iterator.hasNext();){ - - Entity entity = WizardryUtilities.getEntityByUUID(this.player.world, iterator.next()); - - if(entity == null) iterator.remove(); - - if(entity instanceof EntityLivingBase){ - // Retaliatory effect - if(DamageSafetyChecker.attackEntitySafely(entity, MagicDamage.causeDirectMagicDamage(this.player, - DamageType.MAGIC, true), damage, originalSourceName)){ - // Sound only plays if the damage succeeds - player.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, player.world.rand.nextFloat() * 0.2F + 1.0F); - } - } - } - } + // Command continuous spell casting /** Starts casting the given spell with the given modifiers. */ - public void startCastingContinuousSpell(Spell spell, SpellModifiers modifiers){ + public void startCastingContinuousSpell(Spell spell, SpellModifiers modifiers, int duration){ - this.currentlyCasting = spell; - this.spellModifiers = modifiers; + this.castCommandSpell = spell; + this.castCommandModifiers = modifiers; + this.castCommandDuration = duration; if(!this.player.world.isRemote){ - PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(), - spell.id(), this.spellModifiers); + PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player, spell, modifiers, duration); WizardryPacketHandler.net.sendToDimension(message, this.player.world.provider.getDimension()); } } @@ -380,46 +400,48 @@ public class WizardData implements INBTSerializable { /** Stops casting the current spell. */ public void stopCastingContinuousSpell(){ - this.currentlyCasting = Spells.none; - this.castingTick = 0; - this.spellModifiers.reset(); + this.castCommandSpell = Spells.none; + this.castCommandTick = 0; + this.castCommandModifiers.reset(); if(!this.player.world.isRemote){ - PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(), - Spells.none.id(), this.spellModifiers); + PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player, Spells.none, this.castCommandModifiers, this.castCommandDuration); WizardryPacketHandler.net.sendToDimension(message, this.player.world.provider.getDimension()); } } - /** Casts the current continuous spell, fires relevant events and updates the castingTick field. */ + /** Casts the current continuous spell, fires relevant events and updates the castCommandTick field. */ public void updateContinuousSpellCasting(){ - if(this.currentlyCasting != null && this.currentlyCasting.isContinuous){ + if(this.castCommandSpell != null && this.castCommandSpell.isContinuous){ - if(MinecraftForge.EVENT_BUS.post( - new SpellCastEvent.Tick(player, currentlyCasting, spellModifiers, Source.COMMAND, castingTick))){ + if(castCommandTick >= castCommandDuration){ this.stopCastingContinuousSpell(); return; } - if(this.currentlyCasting.cast(player.world, player, EnumHand.MAIN_HAND, castingTick, this.spellModifiers) - && this.castingTick == 0){ - // On the first tick casting a continuous spell via commands, SpellCastEvent.Post is fired. - MinecraftForge.EVENT_BUS - .post(new SpellCastEvent.Post(player, currentlyCasting, spellModifiers, Source.COMMAND)); + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(Source.COMMAND, castCommandSpell, player, castCommandModifiers, castCommandTick))){ + this.stopCastingContinuousSpell(); + return; } - castingTick++; + if(this.castCommandSpell.cast(player.world, player, EnumHand.MAIN_HAND, castCommandTick, this.castCommandModifiers) + && this.castCommandTick == 0){ + // On the first tick casting a continuous spell via commands, SpellCastEvent.Post is fired. + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.COMMAND, castCommandSpell, player, castCommandModifiers)); + } + + castCommandTick++; }else{ - // Why is this here? Surely castingTick will always be 0 if currentlyCasting is null? - this.castingTick = 0; + // Why is this here? Surely castCommandTick will always be 0 if castCommandSpell is null? + this.castCommandTick = 0; } } /** Returns whether this player is currently casting a continuous spell via commands. */ public boolean isCasting(){ - return this.currentlyCasting != null && this.currentlyCasting != Spells.none; + return this.castCommandSpell != null && this.castCommandSpell != Spells.none; } /** @@ -427,69 +449,50 @@ public class WizardData implements INBTSerializable { * casting anything. */ public Spell currentlyCasting(){ - return currentlyCasting; + return castCommandSpell; } + // ============================================== Data Handling ============================================== + /** Called each time the associated player is updated. */ + @SuppressWarnings("unchecked") // Again, we know it must be ok private void update(){ if(this.selectedMinion != null && this.selectedMinion.get() == null) this.selectedMinion = null; - // This new system removes a lot of repetitive event handler code and inflexible variables which had duplicate + prevMotionY = player.motionY; + + // This new system removes a lot of repetitive event handler code and inflexible spellData which had duplicate // functions, just for different enchantments. updateImbuedItems(); - - if(!player.world.isRemote){ - if(getTpCountdown() == 1){ - player.setPositionAndUpdate(this.stoneCircleLocation.getX() + 0.5, this.stoneCircleLocation.getY(), - this.stoneCircleLocation.getZ() + 0.5); - player.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 50, 0)); - IMessage msg = new PacketTransportation.Message(player.getEntityId()); - WizardryPacketHandler.net.sendToDimension(msg, player.world.provider.getDimension()); - } - - if(getTpCountdown() > 0){ - setTpCountdown(getTpCountdown() - 1); - } - } - updateContinuousSpellCasting(); - } - /** - * Returns the WizardData instance for the specified player. - */ - public static final WizardData get(EntityPlayer player){ - return player.getCapability(WIZARD_DATA_CAPABILITY, null); + this.spellData.forEach((k, v) -> this.spellData.put(k, k.update(player, v))); + this.spellData.keySet().removeIf(k -> k.canPurge(player, this.spellData.get(k))); } /** * Called from the event handler each time the associated player entity is cloned, i.e. on respawn or when - * travelling to a different dimension. Used to copy over any variables that should persist over player death. This - * is the inverse of the old onPlayerDeath method, which reset the variables that shouldn't persist. + * travelling to a different dimension. Used to copy over any spellData that should persist over player death. This + * is the inverse of the old onPlayerDeath method, which reset the spellData that shouldn't persist. * - * @param data The old WizardData whose variables are to be copied over. + * @param data The old WizardData whose spellData are to be copied over. * @param respawn True if the player died and is respawning, false if they are just travelling between dimensions. */ public void copyFrom(WizardData data, boolean respawn){ - // TODO: What happens with spirit wolf and spirit horse? - this.hasSpiritHorse = data.hasSpiritHorse; - this.hasSpiritWolf = data.hasSpiritWolf; + this.allies = data.allies; this.allyNames = data.allyNames; - this.clairvoyanceDimension = data.clairvoyanceDimension; - this.clairvoyanceLocation = data.clairvoyanceLocation; this.selectedMinion = data.selectedMinion; - // Curse of soulbinding is lifted when the caster dies, but not when they switch dimensions. - if(!respawn) this.soulboundCreatures = data.soulboundCreatures; this.spellsDiscovered = data.spellsDiscovered; - this.stoneCircleDimension = data.stoneCircleDimension; - this.stoneCircleLocation = data.stoneCircleLocation; + this.recentSpells = data.recentSpells; + + for(IVariable variable : data.spellData.keySet()){ + if(variable.isPersistent(respawn)) this.spellData.put(variable, data.spellData.get(variable)); + } // Imbuements are lost on death so their durations do not persist. // Command spell casting is reset on death so the associated variables do not persist. - // tpCountdown is reset both when the player dies and when they switch dimensions. - } /** Sends a packet to this player's client to synchronise necessary information. Only called server side. */ @@ -498,45 +501,39 @@ public class WizardData implements INBTSerializable { int id = -1; if(this.selectedMinion != null && this.selectedMinion.get() instanceof Entity) id = ((Entity)this.selectedMinion.get()).getEntityId(); - IMessage msg = new PacketPlayerSync.Message(this.spellsDiscovered, id); + long seed = player.world.rand.nextLong(); + this.synchronisedRandom.setSeed(seed); + IMessage msg = new PacketPlayerSync.Message(seed, this.spellsDiscovered, id, this.spellData); WizardryPacketHandler.net.sendTo(msg, (EntityPlayerMP)this.player); } } @Override + @SuppressWarnings("unchecked") public NBTTagCompound serializeNBT(){ NBTTagCompound properties = new NBTTagCompound(); - properties.setTag("imbuements", WizardryUtilities.mapToNBT(this.imbuementDurations, + properties.setTag("imbuements", NBTExtras.mapToNBT(this.imbuementDurations, imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new)); - properties.setBoolean("hasSpiritWolf", this.hasSpiritWolf); - properties.setBoolean("hasSpiritHorse", this.hasSpiritHorse); - - if(this.stoneCircleLocation != null) - properties.setLong("stoneCircleLocation", this.stoneCircleLocation.toLong()); - properties.setInteger("stoneCircleDimension", this.stoneCircleDimension); - properties.setInteger("tpCountdown", this.tpCountdown); - - if(this.clairvoyanceLocation != null) - properties.setLong("clairvoyanceLocation", this.clairvoyanceLocation.toLong()); - properties.setInteger("clairvoyanceDimension", this.getClairvoyanceDimension()); - // Mmmmmm Java 8.... - properties.setTag("allies", WizardryUtilities.listToNBT(this.allies, WizardryUtilities::UUIDtoTagCompound)); - properties.setTag("allyNames", WizardryUtilities.listToNBT(this.allyNames, NBTTagString::new)); - properties.setTag("soulboundCreatures", WizardryUtilities.listToNBT(this.soulboundCreatures, WizardryUtilities::UUIDtoTagCompound)); + properties.setTag("allies", NBTExtras.listToNBT(this.allies, NBTUtil::createUUIDTag)); + properties.setTag("allyNames", NBTExtras.listToNBT(this.allyNames, NBTTagString::new)); // Might be worth converting this over to WizardryUtilities.listToNBT. int[] spells = new int[this.spellsDiscovered.size()]; int i = 0; for(Spell spell : this.spellsDiscovered){ - spells[i] = spell.id(); + spells[i] = spell.metadata(); i++; } properties.setIntArray("discoveredSpells", spells); + properties.setTag("recentSpells", NBTExtras.listToNBT(recentSpells, s -> new NBTTagInt(s.metadata()))); + + storedVariables.forEach(k -> k.write(properties, this.spellData.get(k))); + return properties; } @@ -545,36 +542,32 @@ public class WizardData implements INBTSerializable { if(nbt != null){ - this.imbuementDurations = WizardryUtilities.NBTToMap(nbt.getTagList("imbuements", NBT.TAG_COMPOUND), + this.imbuementDurations = NBTExtras.NBTToMap(nbt.getTagList("imbuements", NBT.TAG_COMPOUND), (NBTTagInt tag) -> (Imbuement)Enchantment.getEnchantmentByID(tag.getInt()), NBTTagInt::getInt); - this.hasSpiritWolf = nbt.getBoolean("hasSpiritWolf"); - this.hasSpiritHorse = nbt.getBoolean("hasSpiritHorse"); + this.allies = new HashSet<>(NBTExtras.NBTToList(nbt.getTagList("allies", NBT.TAG_COMPOUND), NBTUtil::getUUIDFromTag)); + this.allyNames = new HashSet<>(NBTExtras.NBTToList(nbt.getTagList("allyNames", NBT.TAG_STRING), NBTTagString::getString)); - this.stoneCircleLocation = BlockPos.fromLong(nbt.getLong("stoneCircleLocation")); - this.stoneCircleDimension = nbt.getInteger("stoneCircleDimension"); - this.tpCountdown = nbt.getInteger("tpCountdown"); - - this.clairvoyanceLocation = BlockPos.fromLong(nbt.getLong("clairvoyanceLocation")); - this.clairvoyanceDimension = nbt.getInteger("clairvoyanceDimension"); - - this.allies = new HashSet(WizardryUtilities.NBTToList(nbt.getTagList("allies", NBT.TAG_COMPOUND), - WizardryUtilities::tagCompoundToUUID)); - - this.allyNames = new HashSet( - WizardryUtilities.NBTToList(nbt.getTagList("allyNames", NBT.TAG_STRING), NBTTagString::getString)); - - this.soulboundCreatures = new HashSet(WizardryUtilities.NBTToList( - nbt.getTagList("soulboundCreatures", NBT.TAG_COMPOUND), WizardryUtilities::tagCompoundToUUID)); - - this.spellsDiscovered = new HashSet(); + this.spellsDiscovered = new HashSet<>(); for(int id : nbt.getIntArray("discoveredSpells")){ - spellsDiscovered.add(Spell.get(id)); + spellsDiscovered.add(Spell.byMetadata(id)); + } + + // Probably won't be null but we may as well just reinitialise it instead of clearing it + this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS); + this.recentSpells.addAll(NBTExtras.NBTToList(nbt.getTagList("recentSpells", NBT.TAG_INT), + (NBTTagInt tag) -> Spell.byMetadata(tag.getInt()))); + + try{ + storedVariables.forEach(k -> this.spellData.put(k, k.read(nbt))); + }catch(ClassCastException e){ + // Should only happen if someone manually edits the save file + Wizardry.logger.error("Wizard data NBT tag was not of expected type!", e); } } } - // Event handlers + // ============================================== Event Handlers ============================================== @SubscribeEvent // The type parameter here has to be Entity, not EntityPlayer, or the event won't get fired. @@ -583,11 +576,6 @@ public class WizardData implements INBTSerializable { if(event.getObject() instanceof EntityPlayer) event.addCapability(new ResourceLocation(Wizardry.MODID, "WizardData"), new WizardData.Provider((EntityPlayer)event.getObject())); - - // This demonstrates why capabilities are badly structured: The following code compiles, but what it does is put - // a player into a CapabilityDispatcher, which is in turn stored in that very same player, which makes no sense - // at all! - // event.addCapability(new ResourceLocation(Wizardry.MODID, "WizardData"), event.getObject()); } @SubscribeEvent @@ -597,6 +585,8 @@ public class WizardData implements INBTSerializable { WizardData oldData = WizardData.get(event.getOriginal()); newData.copyFrom(oldData, event.isWasDeath()); + + newData.sync(); // In theory this should fix client/server discrepancies (see #69) } @SubscribeEvent @@ -621,6 +611,8 @@ public class WizardData implements INBTSerializable { } } + // ========================================== Capability Boilerplate ========================================== + /** * This is a nested class for a few reasons: firstly, it makes sense because instances of this and WizardData go * hand-in-hand; secondly, it's too short to be worth a separate file; and thirdly (and most importantly) it allows diff --git a/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicProtection.java b/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicProtection.java new file mode 100644 index 00000000..c397d37b --- /dev/null +++ b/src/main/java/electroblob/wizardry/enchantment/EnchantmentMagicProtection.java @@ -0,0 +1,111 @@ +package electroblob.wizardry.enchantment; + +import electroblob.wizardry.util.IElementalDamage; +import electroblob.wizardry.util.MagicDamage; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentProtection; +import net.minecraft.enchantment.EnumEnchantmentType; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.util.DamageSource; + +import java.util.function.Predicate; + +/** + * This class is for the various magic protection enchantments added by wizardry. + */ +// This was mostly copied from EnchantmentProtection, with the code cleaned up a lot (the vanilla one is awful java...) +public class EnchantmentMagicProtection extends Enchantment { + + /** The type of protection this enchantment gives. */ + public final EnchantmentMagicProtection.Type protectionType; + + public EnchantmentMagicProtection(Enchantment.Rarity rarity, EnchantmentMagicProtection.Type protectionType, EntityEquipmentSlot... slots){ + super(rarity, EnumEnchantmentType.ARMOR, slots); + this.protectionType = protectionType; + } + + // Who knew this was so complicated? + // https://minecraft.gamepedia.com/Tutorials/Enchantment_mechanics#How_enchantments_are_chosen + // https://minecraft.gamepedia.com/Enchanting/Levels <- This is what the results of the 2 methods below are compared to + + @Override + public int getMinEnchantability(int enchantmentLevel){ + return this.protectionType.getMinimalEnchantability() + (enchantmentLevel - 1) * this.protectionType.getEnchantIncreasePerLevel(); + } + + @Override + public int getMaxEnchantability(int enchantmentLevel){ + return this.getMinEnchantability(enchantmentLevel) + this.protectionType.getEnchantIncreasePerLevel(); + } + + @Override + public int getMaxLevel(){ + return 4; + } + + @Override + public int calcModifierDamage(int level, DamageSource source){ + if(source.canHarmInCreative()) return 0; + if(this.protectionType.protectsAgainst(source)) return this.protectionType.getProtectionMultiplier() * level; + return 0; + } + + @Override + public String getName(){ + return "enchantment.ebwizardry:" + this.protectionType.getTypeName() + "_protection"; + } + + @Override + public boolean canApplyTogether(Enchantment ench){ + if(ench instanceof EnchantmentMagicProtection){ + return false; // As per EnchantmentProtection, only feather falling can be applied with other protection types + }else if(ench instanceof EnchantmentProtection){ + return ((EnchantmentProtection)ench).protectionType == EnchantmentProtection.Type.FALL; + }else{ + return super.canApplyTogether(ench); + } + } + + public enum Type { + + MAGIC("magic", 1, 5, 8, s -> s instanceof IElementalDamage), + FROST("frost", 2, 10, 8, s -> s instanceof IElementalDamage && ((IElementalDamage)s).getType() == MagicDamage.DamageType.FROST), + SHOCK("shock", 2, 10, 8, s -> s instanceof IElementalDamage && ((IElementalDamage)s).getType() == MagicDamage.DamageType.SHOCK); + // Fire already exists, and the other types aren't used enough to be worth having + + private final String typeName; + private final int minEnchantability; + private final int levelCost; + // What the heck was levelCostSpan for? Removed since it's never used. + private final Predicate criteria; + private final int protectionMultiplier; + + Type(String name, int protectionMultiplier, int minEnchantability, int perLevelEnchantability, Predicate criteria){ + this.typeName = name; + this.minEnchantability = minEnchantability; + this.levelCost = perLevelEnchantability; + this.criteria = criteria; + this.protectionMultiplier = protectionMultiplier; + } + + public String getTypeName(){ + return this.typeName; + } + + public boolean protectsAgainst(DamageSource source){ + return criteria.test(source); + } + + public int getMinimalEnchantability(){ + return this.minEnchantability; + } + + public int getEnchantIncreasePerLevel(){ + return this.levelCost; + } + + public int getProtectionMultiplier(){ + return protectionMultiplier; + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/enchantment/Imbuement.java b/src/main/java/electroblob/wizardry/enchantment/Imbuement.java index 18eee9bf..53906427 100644 --- a/src/main/java/electroblob/wizardry/enchantment/Imbuement.java +++ b/src/main/java/electroblob/wizardry/enchantment/Imbuement.java @@ -1,12 +1,10 @@ package electroblob.wizardry.enchantment; -import java.util.Iterator; -import java.util.Map; - import com.google.common.collect.Iterables; import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.spell.FreezingWeapon; +import electroblob.wizardry.spell.ImbueWeapon; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.EntityLivingBase; @@ -15,7 +13,6 @@ import net.minecraft.entity.projectile.EntityArrow; import net.minecraft.init.Items; import net.minecraft.inventory.ContainerChest; import net.minecraft.inventory.Slot; -import net.minecraft.item.ItemBow; import net.minecraft.item.ItemEnchantedBook; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTBase; @@ -28,6 +25,8 @@ import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.util.Iterator; + /** * Interface for temporary enchantments that last for a certain duration ('imbuements'). This interface allows * {@link EnchantmentMagicSword} and {@link EnchantmentTimed} to both be treated as instances of a single type, rather @@ -59,8 +58,7 @@ public interface Imbuement { /** Removes all imbuements from the given itemstack. */ static void removeImbuements(ItemStack stack){ if(stack.isItemEnchanted()){ - // No need to check what enchantments the item has, since remove() does nothing if the element does not - // exist. + // No need to check what enchantments the item has, since remove() does nothing if the element does not exist NBTTagList enchantmentList = stack.getItem() == Items.ENCHANTED_BOOK ? ItemEnchantedBook.getEnchantments(stack) : stack.getEnchantmentTagList(); // Check all enchantments of the item @@ -96,7 +94,7 @@ public interface Imbuement { // If any imbuements were removed, inform about the removal of the enchantment(s), or // delete the book entirely if there are none left. if(enchantmentList.isEmpty()){ - slot.putStack(ItemStack.EMPTY); // NOTE: Will need changing in 1.11 + slot.putStack(ItemStack.EMPTY); Wizardry.logger.info("Deleted enchanted book with illegal enchantments"); }else{ // Inform about enchantment removal @@ -122,9 +120,9 @@ public interface Imbuement { ItemStack bow = archer.getHeldItemMainhand(); - if(!(bow.getItem() instanceof ItemBow)){ + if(!ImbueWeapon.isBow(bow.getItem())){ bow = archer.getHeldItemOffhand(); - if(!(bow.getItem() instanceof ItemBow)) return; + if(!ImbueWeapon.isBow(bow.getItem())) return; } // Taken directly from ItemBow, so it works exactly the same as the power enchantment. diff --git a/src/main/java/electroblob/wizardry/entity/EntityLevitatingBlock.java b/src/main/java/electroblob/wizardry/entity/EntityLevitatingBlock.java new file mode 100644 index 00000000..84305760 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/EntityLevitatingBlock.java @@ -0,0 +1,296 @@ +package electroblob.wizardry.entity; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.AllyDesignationSystem; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; +import net.minecraft.block.Block; +import net.minecraft.block.BlockFalling; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.MoverType; +import net.minecraft.entity.item.EntityFallingBlock; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.List; +import java.util.UUID; + +/** Custom extended version of {@link EntityFallingBlock} for use with the greater telekinesis spell. */ +public class EntityLevitatingBlock extends EntityFallingBlock implements IEntityAdditionalSpawnData { + + private static final Field fallTile; + + static { + fallTile = ObfuscationReflectionHelper.findField(EntityFallingBlock.class, "field_175132_d"); + fallTile.setAccessible(true); + } + + /** The entity that created this levitating block */ + private WeakReference caster; + + /** + * The UUID of the caster. Note that this is only for loading purposes; during normal updates the actual entity + * instance is stored (so that getEntityByUUID is not called constantly), so this will not always be synced (this is + * why it is private). + */ + private UUID casterUUID; + + /** The damage multiplier for this levitating block, determined by the wand with which it was cast. */ + public float damageMultiplier = 1.0f; + + private int suspendTimer = 5; + + public EntityLevitatingBlock(World world){ + super(world); + // EntityFallingBlock never uses this constructor so doesn't bother setting this, but we need to + this.setSize(0.98F, 0.98F); + } + + public EntityLevitatingBlock(World world, double x, double y, double z, IBlockState state){ + super(world, x, y, z, state); + } + + /** Resets the suspension timer to 5 ticks, during which this block will not re-attach itself to the ground. */ + public void suspend(){ + suspendTimer = 5; + } + + @Override + public void onUpdate(){ + + if(suspendTimer > 0){ + suspendTimer--; + } + + if(this.getCaster() == null && this.casterUUID != null){ + Entity entity = WizardryUtilities.getEntityByUUID(world, casterUUID); + if(entity instanceof EntityLivingBase){ + this.caster = new WeakReference<>((EntityLivingBase)entity); + } + } + + if(getBlock() != null){ + + // === Copied from super === + + Block block = getBlock().getBlock(); + + if(getBlock().getMaterial() == Material.AIR){ + this.setDead(); + + }else{ + + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + if(this.fallTime++ == 0){ + + BlockPos blockpos = new BlockPos(this); + + if(this.world.getBlockState(blockpos).getBlock() == block){ + this.world.setBlockToAir(blockpos); + }else if(!this.world.isRemote){ + this.setDead(); + return; + } + } + + if(!this.hasNoGravity()){ + this.motionY -= 0.03999999910593033D; + } + + this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ); + + if(!this.world.isRemote){ + + BlockPos blockpos1 = new BlockPos(this); + boolean isConcrete = getBlock().getBlock() == Blocks.CONCRETE_POWDER; + boolean isConcreteInWater = isConcrete && this.world.getBlockState(blockpos1).getMaterial() == Material.WATER; + double d0 = this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ; + + if(isConcrete && d0 > 1.0D){ + + RayTraceResult raytraceresult = this.world.rayTraceBlocks(new Vec3d(this.prevPosX, this.prevPosY, this.prevPosZ), new Vec3d(this.posX, this.posY, this.posZ), true); + + if(raytraceresult != null && this.world.getBlockState(raytraceresult.getBlockPos()).getMaterial() == Material.WATER){ + blockpos1 = raytraceresult.getBlockPos(); + isConcreteInWater = true; + } + } + + if(!this.onGround && !isConcreteInWater){ + + if(this.fallTime > 100 && !this.world.isRemote && (blockpos1.getY() < 1 || blockpos1.getY() > 256) || this.fallTime > 600){ + this.setDead(); + } + + }else{ + + IBlockState iblockstate = this.world.getBlockState(blockpos1); + + if(this.world.isAirBlock(new BlockPos(this.posX, this.posY - 0.009999999776482582D, this.posZ))){ + if(!isConcreteInWater && BlockFalling.canFallThrough(this.world.getBlockState(new BlockPos(this.posX, this.posY - 0.009999999776482582D, this.posZ)))){ + this.onGround = false; + return; + } + } + + this.motionX *= 0.699999988079071D; + this.motionZ *= 0.699999988079071D; + this.motionY *= -0.5D; + + if(iblockstate.getBlock() != Blocks.PISTON_EXTENSION){ + + if(suspendTimer == 0){ + + this.setDead(); // Moved inside the above if statement + + if(this.world.mayPlace(block, blockpos1, true, EnumFacing.UP, null) + && (isConcreteInWater || !BlockFalling.canFallThrough(this.world.getBlockState(blockpos1.down()))) + && this.world.setBlockState(blockpos1, getBlock(), 3)){ + + if(block instanceof BlockFalling){ + ((BlockFalling)block).onEndFalling(this.world, blockpos1, getBlock(), iblockstate); + } + + if(this.tileEntityData != null && block.hasTileEntity(getBlock())){ + + TileEntity tileentity = this.world.getTileEntity(blockpos1); + + if(tileentity != null){ + + NBTTagCompound nbttagcompound = tileentity.writeToNBT(new NBTTagCompound()); + + for(String s : this.tileEntityData.getKeySet()){ + NBTBase nbtbase = this.tileEntityData.getTag(s); + + if(!"x".equals(s) && !"y".equals(s) && !"z".equals(s)){ + nbttagcompound.setTag(s, nbtbase.copy()); + } + } + + tileentity.readFromNBT(nbttagcompound); + tileentity.markDirty(); + } + } + + }else{ + // Never drops the block, instead if it can't reattach to the world it breaks + world.playEvent(2001, this.getPosition(), Block.getStateId(getBlock())); + } + } + } + } + } + + this.motionX *= 0.9800000190734863D; + this.motionY *= 0.9800000190734863D; + this.motionZ *= 0.9800000190734863D; + } + + // === End super copy === + } + + double velocitySquared = motionX * motionX + motionY * motionY + motionZ * motionZ; + + if(velocitySquared >= 0.2){ + + List list = this.world.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox()); + + for(Entity entity : list){ + + if(entity instanceof EntityLivingBase && isValidTarget(entity)){ + + float damage = Spells.greater_telekinesis.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; + damage *= Math.min(1, velocitySquared/0.4); // Reduce damage at low speeds + + entity.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), + MagicDamage.DamageType.FORCE), damage); + + double dx = -this.motionX; + double dz; + for(dz = -this.motionZ; dx * dx + dz * dz < 1.0E-4D; dz = (Math.random() - Math.random()) * 0.01D){ + dx = (Math.random() - Math.random()) * 0.01D; + } + ((EntityLivingBase)entity).knockBack(this, 0.6f, dx, dz); + } + } + } + + } + + /** + * Returns the EntityLivingBase that created this construct, or null if it no longer exists. Cases where the entity + * may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported to + * another dimension, or this construct simply had no caster in the first place. + */ + public EntityLivingBase getCaster(){ + return caster == null ? null : caster.get(); + } + + public void setCaster(EntityLivingBase caster){ + if(getCaster() != caster) this.caster = new WeakReference<>(caster); + } + + /** + * Shorthand for {@link AllyDesignationSystem#isValidTarget(Entity, Entity)}, with the owner of this construct as the + * attacker. Also allows subclasses to override it if they wish to do so. + */ + public boolean isValidTarget(Entity target){ + return AllyDesignationSystem.isValidTarget(this.getCaster(), target); + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + casterUUID = nbttagcompound.getUniqueId("casterUUID"); + damageMultiplier = nbttagcompound.getFloat("damageMultiplier"); + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + if(this.getCaster() != null){ + nbttagcompound.setUniqueId("casterUUID", this.getCaster().getUniqueID()); + } + nbttagcompound.setFloat("damageMultiplier", damageMultiplier); + } + + @Override + public void readSpawnData(ByteBuf buf){ + if(buf.isReadable()){ + Block block = Block.REGISTRY.getObjectById(buf.readInt()); + try{ + fallTile.set(this, block.getStateFromMeta(buf.readInt())); + }catch(IllegalAccessException e){ + Wizardry.logger.error("Error reading levitating block data from packet: ", e); + } + } + } + + @Override + public void writeSpawnData(ByteBuf buf){ + if(getBlock() != null){ + buf.writeInt(Block.REGISTRY.getIDForObject(getBlock().getBlock())); + buf.writeInt(getBlock().getBlock().getMetaFromState(getBlock())); + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/EntityMeteor.java b/src/main/java/electroblob/wizardry/entity/EntityMeteor.java index 14784b3f..f41d63ad 100644 --- a/src/main/java/electroblob/wizardry/entity/EntityMeteor.java +++ b/src/main/java/electroblob/wizardry/entity/EntityMeteor.java @@ -1,15 +1,15 @@ package electroblob.wizardry.entity; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.spell.Meteor; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.MoverType; import net.minecraft.entity.item.EntityFallingBlock; -import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.math.BlockPos; +import net.minecraft.util.SoundCategory; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -20,6 +20,7 @@ public class EntityMeteor extends EntityFallingBlock { * The entity blast multiplier. */ public float blastMultiplier; + private boolean damageBlocks; public EntityMeteor(World world){ super(world); @@ -27,11 +28,12 @@ public class EntityMeteor extends EntityFallingBlock { this.setSize(0.98F, 0.98F); } - public EntityMeteor(World world, double x, double y, double z, float blastMultiplier){ + public EntityMeteor(World world, double x, double y, double z, float blastMultiplier, boolean damageBlocks){ super(world, x, y, z, WizardryBlocks.meteor.getDefaultState()); this.motionY = -1.0D; this.setFire(200); this.blastMultiplier = blastMultiplier; + this.damageBlocks = damageBlocks; } @Override @@ -43,7 +45,7 @@ public class EntityMeteor extends EntityFallingBlock { public void onUpdate(){ if(this.ticksExisted % 16 == 1 && world.isRemote){ - Wizardry.proxy.playMovingSound(this, WizardrySounds.SPELL_LOOP_FIRE, 3.0f, 1.0f, false); + Wizardry.proxy.playMovingSound(this, WizardrySounds.ENTITY_METEOR_FALLING, WizardrySounds.SPELLS, 3.0f, 1.0f, false); } // You'd think the best way to do this would be to call super and do all the exploding stuff in fall() instead. @@ -66,21 +68,9 @@ public class EntityMeteor extends EntityFallingBlock { this.motionX *= 0.699999988079071D; this.motionZ *= 0.699999988079071D; this.motionY *= -0.5D; - this.world.createExplosion(this, this.posX, this.posY, this.posZ, 2.0f * blastMultiplier, true); - for(int i1 = -3; i1 < 4; i1++){ - for(int j1 = -3; j1 < 4; j1++){ - int y = WizardryUtilities.getNearestFloorLevelB(this.world, - new BlockPos(this.posX + i1, this.posY, this.posZ + j1), 7); - // System.out.println(y); - double dist = this.getDistance((int)this.posX + i1, y, (int)this.posZ + j1); - // Randomised with weighting so that the nearer the block the more likely it is to be set on - // fire. - if(y != -1 && rand.nextInt((int)dist * 2 + 1) < 3 && dist < 4){ - this.world.setBlockState(new BlockPos(this.posX + i1, y, this.posZ + j1), - Blocks.FIRE.getDefaultState()); - } - } - } + this.world.newExplosion(this, this.posX, this.posY, this.posZ, + Spells.meteor.getProperty(Meteor.BLAST_STRENGTH).floatValue() * blastMultiplier, + damageBlocks, damageBlocks); this.setDead(); } } @@ -123,12 +113,19 @@ public class EntityMeteor extends EntityFallingBlock { public void readEntityFromNBT(NBTTagCompound nbttagcompound){ super.readEntityFromNBT(nbttagcompound); blastMultiplier = nbttagcompound.getFloat("blastMultiplier"); + damageBlocks = nbttagcompound.getBoolean("damageBlocks"); } @Override public void writeEntityToNBT(NBTTagCompound nbttagcompound){ super.writeEntityToNBT(nbttagcompound); nbttagcompound.setFloat("blastMultiplier", blastMultiplier); + nbttagcompound.setBoolean("damageBlocks", damageBlocks); + } + + @Override + public SoundCategory getSoundCategory(){ + return WizardrySounds.SPELLS; } } diff --git a/src/main/java/electroblob/wizardry/entity/EntityShield.java b/src/main/java/electroblob/wizardry/entity/EntityShield.java index 0f483493..7138dc22 100644 --- a/src/main/java/electroblob/wizardry/entity/EntityShield.java +++ b/src/main/java/electroblob/wizardry/entity/EntityShield.java @@ -1,18 +1,20 @@ package electroblob.wizardry.entity; -import java.lang.ref.WeakReference; - -import electroblob.wizardry.WizardData; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Shield; import net.minecraft.entity.Entity; import net.minecraft.entity.IProjectile; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; +import net.minecraft.util.SoundCategory; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.world.World; +import java.lang.ref.WeakReference; + public class EntityShield extends Entity { public WeakReference player; @@ -46,8 +48,8 @@ public class EntityShield extends Entity { entityplayer.posY + 1 + entityplayer.getLookVec().y * 0.3, entityplayer.posZ + entityplayer.getLookVec().z * 0.3, entityplayer.rotationYawHead, entityplayer.rotationPitch); - if(!entityplayer.isHandActive() || !(entityplayer.getHeldItem(entityplayer.getActiveHand()).getItem() instanceof ItemWand)){ - WizardData.get(entityplayer).shield = null; + if(!entityplayer.isHandActive() || !(entityplayer.getHeldItem(entityplayer.getActiveHand()).getItem() instanceof ISpellCastingItem)){ + WizardData.get(entityplayer).setVariable(Shield.SHIELD_KEY, null); this.setDead(); } }else if(!world.isRemote){ @@ -62,13 +64,19 @@ public class EntityShield extends Entity { this.setRotation(par7, par8); } - public boolean attackEntityFrom(DamageSource par1DamageSource, float par2){ - if(par1DamageSource != null && par1DamageSource.getImmediateSource() instanceof IProjectile){ - par1DamageSource.getImmediateSource().playSound(WizardrySounds.SPELL_DEFLECTION, 0.3f, 1.3f); + public boolean attackEntityFrom(DamageSource source, float damage){ + if(source != null && source.getImmediateSource() instanceof IProjectile){ + world.playSound(null, source.getImmediateSource().posX, source.getImmediateSource().posY, + source.getImmediateSource().posZ, WizardrySounds.ENTITY_SHIELD_DEFLECT, WizardrySounds.SPELLS, 0.3f, 1.3f); } - super.attackEntityFrom(par1DamageSource, par2); + super.attackEntityFrom(source, damage); return false; } + + @Override + public SoundCategory getSoundCategory(){ + return WizardrySounds.SPELLS; + } public boolean canBeCollidedWith(){ return !this.isDead; diff --git a/src/main/java/electroblob/wizardry/entity/ICustomHitbox.java b/src/main/java/electroblob/wizardry/entity/ICustomHitbox.java new file mode 100644 index 00000000..95c0baa9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/ICustomHitbox.java @@ -0,0 +1,31 @@ +package electroblob.wizardry.entity; + +import net.minecraft.util.math.Vec3d; + +/** This interface allows implementing entity classes to define their own hitbox for wizardry's raytracing and + * particle collision methods. Typically, entities implementing this interface will return null from the collision + * bounding box methods in {@code Entity} (there are two for some reason) but return true from + * {@link net.minecraft.entity.Entity#canBeCollidedWith()} */ +public interface ICustomHitbox { + + /** + * Calculates the point at which the line starting at the given origin and ending at the given endpoint hits this + * entity, if any. Used in raytracing to allow entities to define fully custom behaviour. See + * {@link electroblob.wizardry.entity.construct.EntityForcefield} for an example implementation of a spherical hitbox. + * @param origin The origin of the line. + * @param endpoint The endpoint of the line. + * @param fuzziness Maximum distance around the line that should still count as a hit. + * @return A {@link Vec3d} representing the point hit, or null if there is no intercept. This should be the first + * point that the line hits, i.e. if there is more than one intercept this method should return the one nearest to + * the given origin. + */ + Vec3d calculateIntercept(Vec3d origin, Vec3d endpoint, float fuzziness); + + /** + * Returns whether the given point is inside this entity. + * @param point The coordinates to test. + * @return True if the point is inside this entity, false if not. + */ + boolean contains(Vec3d point); + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java b/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java index b2ecca42..9f26e85b 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityArrowRain.java @@ -3,6 +3,7 @@ package electroblob.wizardry.entity.construct; import net.minecraft.entity.projectile.EntityTippedArrow; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; public class EntityArrowRain extends EntityMagicConstruct { @@ -20,9 +21,9 @@ public class EntityArrowRain extends EntityMagicConstruct { if(!this.world.isRemote){ EntityTippedArrow arrow = new EntityTippedArrow(world, this.posX + rand.nextDouble() * 6 - 3, this.posY + rand.nextDouble() * 4 - 2, this.posZ + rand.nextDouble() * 6 - 3); - arrow.motionX = Math.cos(Math.toRadians(this.rotationYaw + 90)); + arrow.motionX = MathHelper.cos((float)Math.toRadians(this.rotationYaw + 90)); arrow.motionY = -0.6; - arrow.motionZ = Math.sin(Math.toRadians(this.rotationYaw + 90)); + arrow.motionZ = MathHelper.sin((float)Math.toRadians(this.rotationYaw + 90)); arrow.shootingEntity = this.getCaster(); arrow.setDamage(7.0d * damageMultiplier); arrow.setPotionEffect(new ItemStack(Items.ARROW)); diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java index 68fc1ae6..378c9066 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBlackHole.java @@ -1,13 +1,15 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.init.SoundEvents; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.SPacketEntityVelocity; import net.minecraft.util.DamageSource; @@ -16,7 +18,11 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.List; + public class EntityBlackHole extends EntityMagicConstruct { + + private static final double SUCTION_STRENGTH = 0.075; public int[] randomiser; public int[] randomiser2; @@ -69,42 +75,49 @@ public class EntityBlackHole extends EntityMagicConstruct { } if(this.lifetime - this.ticksExisted == 75){ - this.playSound(SoundEvents.BLOCK_PORTAL_TRIGGER, 1.5f, 1.0f); + this.playSound(WizardrySounds.ENTITY_BLACK_HOLE_VANISH, 1.5f, 1.0f); }else if(this.ticksExisted % 80 == 1 && this.ticksExisted + 80 < this.lifetime){ - this.playSound(SoundEvents.BLOCK_PORTAL_AMBIENT, 1.5f, 1.0f); + this.playSound(WizardrySounds.ENTITY_BLACK_HOLE_AMBIENT, 1.5f, 1.0f); } - List targets = WizardryUtilities.getEntitiesWithinRadius(6.0d, this.posX, this.posY, - this.posZ, this.world); - if(!this.world.isRemote){ + List targets = WizardryUtilities.getEntitiesWithinRadius(6.0d, this.posX, this.posY, + this.posZ, this.world); + for(EntityLivingBase target : targets){ if(this.isValidTarget(target)){ - // Sucks the target in - if(this.posX > target.posX && target.motionX < 1){ - target.motionX += 0.1; - }else if(this.posX < target.posX && target.motionX > -1){ - target.motionX -= 0.1; - } + // If the target can't be moved, it isn't sucked in but is still damaged if it gets too close + if(!(target instanceof EntityPlayer && ((getCaster() instanceof EntityPlayer && !Wizardry.settings.playersMoveEachOther) + || ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring)))){ - if(this.posY > target.posY && target.motionY < 1){ - target.motionY += 0.1; - }else if(this.posY < target.posY && target.motionY > -1){ - target.motionY -= 0.1; - } + WizardryUtilities.undoGravity(target); - if(this.posZ > target.posZ && target.motionZ < 1){ - target.motionZ += 0.1; - }else if(this.posZ < target.posZ && target.motionZ > -1){ - target.motionZ -= 0.1; - } + // Sucks the target in + if(this.posX > target.posX && target.motionX < 1){ + target.motionX += SUCTION_STRENGTH; + }else if(this.posX < target.posX && target.motionX > -1){ + target.motionX -= SUCTION_STRENGTH; + } - // Player motion is handled on that player's client so needs packets - if(target instanceof EntityPlayerMP){ - ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + if(this.posY > target.posY && target.motionY < 1){ + target.motionY += SUCTION_STRENGTH; + }else if(this.posY < target.posY && target.motionY > -1){ + target.motionY -= SUCTION_STRENGTH; + } + + if(this.posZ > target.posZ && target.motionZ < 1){ + target.motionZ += SUCTION_STRENGTH; + }else if(this.posZ < target.posZ && target.motionZ > -1){ + target.motionZ -= SUCTION_STRENGTH; + } + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } } if(this.getDistance(target) <= 2){ @@ -128,4 +141,9 @@ public class EntityBlackHole extends EntityMagicConstruct { return true; } + @Override + public boolean shouldRenderInPass(int pass){ + return pass == 1; + } + } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java index 4d863e0f..9cc90a43 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java @@ -1,9 +1,9 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -14,6 +14,8 @@ import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; import net.minecraft.world.World; +import java.util.List; + public class EntityBlizzard extends EntityMagicConstruct { public EntityBlizzard(World world){ @@ -25,14 +27,18 @@ public class EntityBlizzard extends EntityMagicConstruct { public void onUpdate(){ if(this.ticksExisted % 120 == 1){ - this.playSound(WizardrySounds.SPELL_LOOP_WIND, 1.0f, 1.0f); + this.playSound(WizardrySounds.ENTITY_BLIZZARD_AMBIENT, 1.0f, 1.0f); } super.onUpdate(); + // This is a good example of why you might define a spell base property without necessarily using it in the + // spell - in fact, blizzard doesn't even have a spell class (yet) + double radius = Spells.blizzard.getProperty(Spell.EFFECT_RADIUS).doubleValue(); + if(!this.world.isRemote){ - List targets = WizardryUtilities.getEntitiesWithinRadius(3.0d, this.posX, this.posY, + List targets = WizardryUtilities.getEntitiesWithinRadius(radius, this.posX, this.posY, this.posZ, this.world); for(EntityLivingBase target : targets){ @@ -59,7 +65,7 @@ public class EntityBlizzard extends EntityMagicConstruct { for(int i=1; i<12; i++){ double speed = (rand.nextBoolean() ? 1 : -1) * 0.1 + 0.05 * rand.nextDouble(); ParticleBuilder.create(Type.SNOW).pos(this.posX, this.posY + rand.nextDouble() * 3, this.posZ).vel(0, 0, 0) - .time(100).scale(2).spin(rand.nextDouble() * 2.5 + 0.5, speed).spawn(world); + .time(100).scale(2).spin(rand.nextDouble() * (radius - 0.5) + 0.5, speed).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java index 58c3e0e5..e494c610 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBubble.java @@ -1,14 +1,14 @@ package electroblob.wizardry.entity.construct; -import java.lang.ref.WeakReference; - +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Entrapment; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.MoverType; -import net.minecraft.init.SoundEvents; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; @@ -17,6 +17,8 @@ import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.lang.ref.WeakReference; + @Mod.EventBusSubscriber public class EntityBubble extends EntityMagicConstruct { @@ -46,7 +48,7 @@ public class EntityBubble extends EntityMagicConstruct { if((this.rider == null || this.rider.get() == null) && WizardryUtilities.getRider(this) instanceof EntityLivingBase && !WizardryUtilities.getRider(this).isDead){ - this.rider = new WeakReference((EntityLivingBase)WizardryUtilities.getRider(this)); + this.rider = new WeakReference<>((EntityLivingBase)WizardryUtilities.getRider(this)); } // Prevents dismounting @@ -62,7 +64,8 @@ public class EntityBubble extends EntityMagicConstruct { if(isDarkOrb){ - if(WizardryUtilities.getRider(this) != null && this.ticksExisted % 30 == 0){ + if(WizardryUtilities.getRider(this) != null + && this.ticksExisted % Spells.entrapment.getProperty(Entrapment.DAMAGE_INTERVAL).intValue() == 0){ if(this.getCaster() != null){ WizardryUtilities.getRider(this).attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC), @@ -81,16 +84,16 @@ public class EntityBubble extends EntityMagicConstruct { (this.rand.nextDouble() - 0.5D) * 2.0D); } if(lifetime - this.ticksExisted == 75){ - this.playSound(SoundEvents.BLOCK_PORTAL_TRIGGER, 1.5f, 1.0f); + this.playSound(WizardrySounds.ENTITY_ENTRAPMENT_VANISH, 1.5f, 1.0f); }else if(this.ticksExisted % 100 == 1 && this.ticksExisted < 150){ - this.playSound(SoundEvents.BLOCK_PORTAL_AMBIENT, 1.5f, 1.0f); + this.playSound(WizardrySounds.ENTITY_ENTRAPMENT_AMBIENT, 1.5f, 1.0f); } } // Bubble bursts if the entity is hurt (see event handler) or killed, or if the bubble has existed for more than // 10 seconds. if(WizardryUtilities.getRider(this) == null && this.ticksExisted > 1){ - if(!this.isDarkOrb) this.playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f); + if(!this.isDarkOrb) this.playSound(WizardrySounds.ENTITY_BUBBLE_POP, 1.5f, 1.0f); this.setDead(); } } @@ -100,7 +103,7 @@ public class EntityBubble extends EntityMagicConstruct { if(WizardryUtilities.getRider(this) != null){ ((EntityLivingBase)WizardryUtilities.getRider(this)).dismountEntity(this); } - if(!this.isDarkOrb) this.playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f); + if(!this.isDarkOrb) this.playSound(WizardrySounds.ENTITY_BUBBLE_POP, 1.5f, 1.0f); super.despawn(); } @@ -133,7 +136,7 @@ public class EntityBubble extends EntityMagicConstruct { // Bursts bubble when the creature inside takes damage if(event.getEntityLiving().getRidingEntity() instanceof EntityBubble && !((EntityBubble)event.getEntityLiving().getRidingEntity()).isDarkOrb){ - event.getEntityLiving().getRidingEntity().playSound(SoundEvents.ENTITY_ITEM_PICKUP, 1.5f, 1.0f); + event.getEntityLiving().getRidingEntity().playSound(WizardrySounds.ENTITY_BUBBLE_POP, 1.5f, 1.0f); event.getEntityLiving().getRidingEntity().setDead(); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityCombustionRune.java b/src/main/java/electroblob/wizardry/entity/construct/EntityCombustionRune.java new file mode 100644 index 00000000..f9188d6c --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityCombustionRune.java @@ -0,0 +1,58 @@ +package electroblob.wizardry.entity.construct; + +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +import java.util.List; + +public class EntityCombustionRune extends EntityMagicConstruct { + + public EntityCombustionRune(World world){ + super(world); + this.height = 0.2f; + this.width = 2.0f; + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(!this.world.isRemote){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(width/2, posX, posY, posZ, world); + + for(EntityLivingBase target : targets){ + + if(this.isValidTarget(target)){ + + float strength = Spells.combustion_rune.getProperty(Spell.BLAST_RADIUS).floatValue(); + + world.newExplosion(this.getCaster(), this.posX, this.posY, this.posZ, strength, true, true); + + // The trap is destroyed once triggered. + this.setDead(); + } + } + }else if(this.rand.nextInt(15) == 0){ + double radius = 0.5 + rand.nextDouble() * 0.3; + float angle = rand.nextFloat() * (float)Math.PI * 2; + world.spawnParticle(EnumParticleTypes.FLAME, this.posX + radius * MathHelper.cos(angle), this.posY + 0.1, + this.posZ + radius * MathHelper.sin(angle), 0, 0, 0); + } + } + + @Override + protected void entityInit(){} + + @Override + public boolean canRenderOnFire(){ + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java index 7507cbca..e781a2d9 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java @@ -1,17 +1,20 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class EntityDecay extends EntityMagicConstruct { public int textureIndex = 0; @@ -29,7 +32,7 @@ public class EntityDecay extends EntityMagicConstruct { super.onUpdate(); if(this.rand.nextInt(700) == 0 && this.ticksExisted + 100 < lifetime) - this.playSound(SoundEvents.BLOCK_LAVA_AMBIENT, 0.2F + rand.nextFloat() * 0.2F, + this.playSound(WizardrySounds.ENTITY_DECAY_AMBIENT, 0.2F + rand.nextFloat() * 0.2F, 0.6F + rand.nextFloat() * 0.15F); if(!this.world.isRemote){ @@ -41,18 +44,19 @@ public class EntityDecay extends EntityMagicConstruct { // damaged each tick. // In this case, we do want particles to be shown. if(!target.isPotionActive(WizardryPotions.decay)) - target.addPotionEffect(new PotionEffect(WizardryPotions.decay, lifetime, 0)); + target.addPotionEffect(new PotionEffect(WizardryPotions.decay, + Spells.decay.getProperty(Spell.EFFECT_DURATION).intValue(), 0)); } } }else if(this.rand.nextInt(15) == 0){ double radius = rand.nextDouble() * 0.8; - double angle = rand.nextDouble() * Math.PI * 2; + float angle = rand.nextFloat() * (float)Math.PI * 2; float brightness = rand.nextFloat() * 0.4f; ParticleBuilder.create(Type.DARK_MAGIC) - .pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle)) + .pos(this.posX + radius * MathHelper.cos(angle), this.posY, this.posZ + radius * MathHelper.sin(angle)) .clr(brightness, 0, brightness + 0.1f) .spawn(world); } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java b/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java index 4a26e83f..2a6f455a 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityEarthquake.java @@ -1,7 +1,7 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Earthquake; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.WizardryUtilities; @@ -13,8 +13,11 @@ import net.minecraft.init.MobEffects; import net.minecraft.network.play.server.SPacketEntityVelocity; import net.minecraft.potion.PotionEffect; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class EntityEarthquake extends EntityMagicConstruct { public EntityEarthquake(World world){ @@ -27,21 +30,20 @@ public class EntityEarthquake extends EntityMagicConstruct { super.onUpdate(); + double speed = Spells.earthquake.getProperty(Earthquake.SPREAD_SPEED).doubleValue(); + if(!world.isRemote){ - double speed = 0.4; - // The further the earthquake is going to spread, the finer the angle increments. - for(double angle = 0; angle < 2 * Math.PI; angle += Math.PI / (lifetime * 1.5)){ + for(float angle = 0; angle < 2 * Math.PI; angle += Math.PI / (lifetime * 1.5)){ // Calculates coordinates for the block to be moved. The radius increases with time. The +1.5 is to - // leave - // blocks in the centre untouched. - int x = this.posX < 0 ? (int)(this.posX + ((this.ticksExisted * speed) + 1.5) * Math.sin(angle) - 1) - : (int)(this.posX + ((this.ticksExisted * speed) + 1.5) * Math.sin(angle)); + // leave blocks in the centre untouched. + int x = this.posX < 0 ? (int)(this.posX + ((this.ticksExisted * speed) + 1.5) * MathHelper.sin(angle) - 1) + : (int)(this.posX + ((this.ticksExisted * speed) + 1.5) * MathHelper.sin(angle)); int y = (int)(this.posY - 0.5); - int z = this.posZ < 0 ? (int)(this.posZ + ((this.ticksExisted * speed) + 1.5) * Math.cos(angle) - 1) - : (int)(this.posZ + ((this.ticksExisted * speed) + 1.5) * Math.cos(angle)); + int z = this.posZ < 0 ? (int)(this.posZ + ((this.ticksExisted * speed) + 1.5) * MathHelper.cos(angle) - 1) + : (int)(this.posZ + ((this.ticksExisted * speed) + 1.5) * MathHelper.cos(angle)); BlockPos pos = new BlockPos(x, y, z); @@ -58,50 +60,53 @@ public class EntityEarthquake extends EntityMagicConstruct { } } - List targets = WizardryUtilities - .getEntitiesWithinRadius((this.ticksExisted * speed) + 1.5, this.posX, this.posY, this.posZ, world); + } - // In this particular instance, the caster is completely unaffected because they will always be in the - // centre. - targets.remove(this.getCaster()); + List targets = WizardryUtilities + .getEntitiesWithinRadius((this.ticksExisted * speed) + 1.5, this.posX, this.posY, this.posZ, world); - for(EntityLivingBase target : targets){ + // In this particular instance, the caster is completely unaffected because they will always be in the + // centre. + targets.remove(this.getCaster()); - // Searches in a 1 wide ring. - if(this.getDistance(target) > (this.ticksExisted * speed) + 0.5 && target.posY < this.posY + 1 - && target.posY > this.posY - 1){ + for(EntityLivingBase target : targets){ - // Knockback must be removed in this instance, or the target will fall into the floor. - double motionX = target.motionX; - double motionZ = target.motionZ; + // Searches in a 1 wide ring. + if(this.getDistance(target) > (this.ticksExisted * speed) + 0.5 && target.posY < this.posY + 1 + && target.posY > this.posY - 1){ - if(this.isValidTarget(target)){ - target.attackEntityFrom( - MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.BLAST), - 10 * this.damageMultiplier); - target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 400, 1)); - } + // Knockback must be removed in this instance, or the target will fall into the floor. + double motionX = target.motionX; + double motionZ = target.motionZ; - // All targets are thrown, even those immune to the damage, so they don't fall into the ground. - target.motionX = motionX; - target.motionY = 0.8; // Throws target into the air. - target.motionZ = motionZ; + if(this.isValidTarget(target)){ + target.attackEntityFrom( + MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.BLAST), + 10 * this.damageMultiplier); + target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 400, 1)); + } - // Player motion is handled on that player's client so needs packets - if(target instanceof EntityPlayerMP){ - ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); - } + // All targets are thrown, even those immune to the damage, so they don't fall into the ground. + target.motionX = motionX; + target.motionY = 0.8; // Throws target into the air. + target.motionZ = motionZ; + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); } } - }else{ - // Constant 15 blocks for now - List targets = WizardryUtilities.getEntitiesWithinRadius(15, posX, posY, posZ, world, EntityPlayer.class); + } - float magnitude = 6f * ((float)(this.lifetime - this.ticksExisted))/(float)this.lifetime; + if(!world.isRemote){ + // Constant 15 blocks for now + List targets2 = WizardryUtilities.getEntitiesWithinRadius(15, posX, posY, posZ, world, EntityPlayer.class); + + float magnitude = 10f * ((float)(this.lifetime - this.ticksExisted))/(float)this.lifetime; // Makes the screen shake - for(EntityPlayer target : targets){ - target.rotationPitch = this.ticksExisted % 2 == 0 ? magnitude : -magnitude; + for(EntityPlayer target : targets2){ + target.rotationPitch += this.ticksExisted % 2 == 0 ? magnitude : -magnitude; } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java index 5037b3bf..e6e20e96 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFireRing.java @@ -1,17 +1,21 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.util.DamageSource; import net.minecraft.world.World; +import java.util.List; + public class EntityFireRing extends EntityMagicConstruct { + // TODO: Implement blast modifiers + public EntityFireRing(World world){ super(world); this.height = 1.0f; @@ -21,7 +25,7 @@ public class EntityFireRing extends EntityMagicConstruct { public void onUpdate(){ if(this.ticksExisted % 40 == 1){ - this.playSound(SoundEvents.BLOCK_FIRE_AMBIENT, 4.0f, 0.7f); + this.playSound(WizardrySounds.ENTITY_FIRE_RING_AMBIENT, 4.0f, 0.7f); } super.onUpdate(); @@ -41,14 +45,15 @@ public class EntityFireRing extends EntityMagicConstruct { if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)){ - target.setFire(10); + target.setFire(Spells.ring_of_fire.getProperty(Spell.BURN_DURATION).intValue()); + + float damage = Spells.ring_of_fire.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; if(this.getCaster() != null){ - target.attackEntityFrom( - MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.FIRE), - 1 * damageMultiplier); + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), + DamageType.FIRE), damage); }else{ - target.attackEntityFrom(DamageSource.MAGIC, 1 * damageMultiplier); + target.attackEntityFrom(DamageSource.MAGIC, damage); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java index bb6b7e34..509511ff 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFireSigil.java @@ -1,16 +1,19 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class EntityFireSigil extends EntityMagicConstruct { public EntityFireSigil(World world){ @@ -38,16 +41,18 @@ public class EntityFireSigil extends EntityMagicConstruct { target.attackEntityFrom(this.getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.FIRE) - : DamageSource.MAGIC, 6); + : DamageSource.MAGIC, Spells.fire_sigil.getProperty(Spell.DAMAGE).floatValue() + * damageMultiplier); // Removes knockback target.motionX = velX; target.motionY = velY; target.motionZ = velZ; - if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)) target.setFire(10); + if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)) + target.setFire(Spells.fire_sigil.getProperty(Spell.BURN_DURATION).intValue()); - this.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + this.playSound(WizardrySounds.ENTITY_FIRE_SIGIL_TRIGGER, 1, 1); // The trap is destroyed once triggered. this.setDead(); @@ -55,9 +60,9 @@ public class EntityFireSigil extends EntityMagicConstruct { } }else if(this.rand.nextInt(15) == 0){ double radius = 0.5 + rand.nextDouble() * 0.3; - double angle = rand.nextDouble() * Math.PI * 2; - world.spawnParticle(EnumParticleTypes.FLAME, this.posX + radius * Math.cos(angle), this.posY + 0.1, - this.posZ + radius * Math.sin(angle), 0, 0, 0); + float angle = rand.nextFloat() * (float)Math.PI * 2;; + world.spawnParticle(EnumParticleTypes.FLAME, this.posX + radius * MathHelper.cos(angle), this.posY + 0.1, + this.posZ + radius * MathHelper.sin(angle), 0, 0, 0); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java index 2a1ab31d..759b7cb9 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java @@ -1,37 +1,89 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.ICustomHitbox; +import electroblob.wizardry.entity.projectile.EntityMagicArrow; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityXPOrb; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.entity.projectile.EntityThrowable; import net.minecraft.network.play.server.SPacketEntityVelocity; -import net.minecraft.util.DamageSource; import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.event.entity.living.LivingAttackEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.world.ExplosionEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -public class EntityForcefield extends EntityMagicConstruct { +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +@Mod.EventBusSubscriber +public class EntityForcefield extends EntityMagicConstruct implements ICustomHitbox { + + /** Extra radius to search around the forcefield for incoming entities. Any entities with a velocity greater than + * this could potentially penetrate the forcefield. */ + private static final double SEARCH_BORDER_SIZE = 4; + + private static final float BOUNCINESS = 0.2f; + + private float radius; public EntityForcefield(World world){ super(world); - this.height = 6; - this.width = 6; + setRadius(3); // Shouldn't be needed but it's a good failsafe + this.ignoreFrustumCheck = true; + this.noClip = true; + } + + public void setRadius(float radius){ + this.radius = radius; + this.height = 2 * radius; + this.width = 2 * radius; // y-3 because it needs to be centred on the given position - this.setEntityBoundingBox(new AxisAlignedBB(posX - 3, posY - 3, posZ - 3, posX + 3, posY + 3, posZ + 3)); + this.setEntityBoundingBox(new AxisAlignedBB(posX - radius, posY - radius, posZ - radius, + posX + radius, posY + radius, posZ + radius)); + } + + public float getRadius(){ + return radius; } @Override public boolean canBeCollidedWith(){ - return !this.isDead; + return false;//!this.isDead; } @Override public AxisAlignedBB getCollisionBox(Entity entity){ - return entity.getEntityBoundingBox(); + return null;//entity.getEntityBoundingBox(); + } + + @Nullable + @Override + public AxisAlignedBB getCollisionBoundingBox(){ + return super.getCollisionBoundingBox(); + } + + @Override + public boolean shouldRenderInPass(int pass){ + return pass == 1; } @Override @@ -39,48 +91,182 @@ public class EntityForcefield extends EntityMagicConstruct { super.onUpdate(); - if(!this.world.isRemote){ - // TESTME: This used to say posY+3, but I'm pretty sure that's wrong because of how the bounding box was set... - List targets = WizardryUtilities.getEntitiesWithinRadius(3.5, posX, posY, posZ, world); - - for(EntityLivingBase target : targets){ - if(this.isValidTarget(target)){ - double multiplier = (3.5 - target.getDistance(this.posX, this.posY, this.posZ)) * 0.1; - target.addVelocity((target.posX - this.posX) * multiplier, - (target.posY - this.posY) * multiplier, (target.posZ - this.posZ) * multiplier); - // Player motion is handled on that player's client so needs packets - if(target instanceof EntityPlayerMP){ - ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + // New forcefield repulsion system: + // Searches for all entities near the forcefield and determines where they will be next tick. + // If they will be inside the forcefield next tick, sets their position and velocity such that they appear to + // bounce off the forcefield and creates impact particle effects and sounds where they hit it + + List targets = WizardryUtilities.getEntitiesWithinRadius(radius + SEARCH_BORDER_SIZE, posX, posY, posZ, world, Entity.class); + + targets.remove(this); + targets.removeIf(t -> t instanceof EntityXPOrb); // Gets annoying since they're attracted to the player + + // Ring of the defender allows players to shoot through their own forcefields + if(getCaster() instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)getCaster(), + WizardryItems.ring_defender)){ + targets.removeIf(t -> t instanceof EntityMagicArrow && !this.isValidTarget(((EntityMagicArrow)t).getCaster()) + || t instanceof EntityThrowable && !this.isValidTarget(((EntityThrowable)t).getThrower()) + || t instanceof EntityArrow && !this.isValidTarget(((EntityArrow)t).shootingEntity)); + } + + for(Entity target : targets){ + + if(this.isValidTarget(target)){ + + Vec3d currentPos = Arrays.stream(WizardryUtilities.getVertices(target.getEntityBoundingBox())) + .min(Comparator.comparingDouble(v -> v.distanceTo(this.getPositionVector()))) + .orElse(target.getPositionVector()); // This will never happen, it's just here to make the compiler happy + + double currentDistance = target.getDistance(this); + + // Estimate the target's position next tick + // We have to assume the same vertex is closest or the velocity will be wrong + Vec3d nextTickPos = currentPos.add(target.motionX, target.motionY, target.motionZ); + double nextTickDistance = nextTickPos.distanceTo(this.getPositionVector()); + + boolean flag; + + if(WizardryUtilities.isLiving(target)){ + // Non-allied living entities shouldn't be inside at all + flag = nextTickDistance <= radius; + }else{ + // Non-living entities will bounce off if they hit the forcefield within the next tick... + flag = (currentDistance > radius && nextTickDistance <= radius) // ...from the outside... + || (currentDistance < radius && nextTickDistance >= radius); // ...or from the inside + } + + if(flag){ + + // Ring of interdiction + if(getCaster() instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)getCaster(), + WizardryItems.ring_interdiction) && WizardryUtilities.isLiving(target)){ + target.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), + MagicDamage.DamageType.MAGIC), 1); + } + + Vec3d targetRelativePos = currentPos.subtract(this.getPositionVector()); + + double nudgeVelocity = this.contains(target) ? -0.1 : 0.1; + if(WizardryUtilities.isLiving(target)) nudgeVelocity = 0.25; + Vec3d extraVelocity = targetRelativePos.normalize().scale(nudgeVelocity); + + // ...make it bounce off! + target.motionX = target.motionX * -BOUNCINESS + extraVelocity.x; + target.motionY = target.motionY * -BOUNCINESS + extraVelocity.y; + target.motionZ = target.motionZ * -BOUNCINESS + extraVelocity.z; + + // Prevents the forcefield bouncing things into the floor + if(target.onGround && target.motionY < 0) target.motionY = 0.1; + + // How far the target needs to move towards the centre (negative means away from the centre) + double distanceTowardsCentre = -(targetRelativePos.length() - radius) - (radius - nextTickDistance); + Vec3d targetNewPos = target.getPositionVector().add(targetRelativePos.normalize().scale(distanceTowardsCentre)); + target.setPosition(targetNewPos.x, targetNewPos.y, targetNewPos.z); + + world.playSound(target.posX, target.posY, target.posZ, WizardrySounds.ENTITY_FORCEFIELD_DEFLECT, + WizardrySounds.SPELLS, 0.3f, 1.3f, false); + + if(!world.isRemote){ + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + + }else{ + + Vec3d relativeImpactPos = targetRelativePos.normalize().scale(radius); + + float yaw = (float)Math.atan2(relativeImpactPos.x, -relativeImpactPos.z); + float pitch = (float)Math.asin(relativeImpactPos.y/ radius); + + ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector().add(relativeImpactPos)) + .time(6).face((float)(yaw * 180/Math.PI), (float)(pitch * 180/Math.PI)) + .clr(0.9f, 0.95f, 1).spawn(world); + + for(int i = 0; i < 12; i++){ + + float yaw1 = yaw + 0.3f * (rand.nextFloat() - 0.5f) - (float)Math.PI/2; + float pitch1 = pitch + 0.3f * (rand.nextFloat() - 0.5f); + + float brightness = rand.nextFloat(); + + double r = radius + 0.05; + double x = this.posX + r * MathHelper.cos(yaw1) * MathHelper.cos(pitch1); + double y = this.posY + r * MathHelper.sin(pitch1); + double z = this.posZ + r * MathHelper.sin(yaw1) * MathHelper.cos(pitch1); + + ParticleBuilder.create(Type.DUST).pos(x, y, z).time(6 + rand.nextInt(6)) + .face((float)(yaw1 * 180/Math.PI) + 90, (float)(pitch1 * 180/Math.PI)).scale(1.5f) + .clr(0.7f + 0.3f * brightness, 0.85f + 0.15f * brightness, 1).spawn(world); + } } } } - }else{ - for(int i = 1; i < 40; i++){ - - // Generates a spherical pattern of particles - float brightness = 0.5f + (rand.nextFloat() * 0.5f); - double radius = 3; - double yaw = rand.nextDouble() * Math.PI * 2; - double pitch = (rand.nextDouble() - 0.5) * Math.PI; - - ParticleBuilder.create(Type.DUST) - .pos(this.posX + radius * Math.cos(yaw) * Math.cos(pitch), this.posY + 3 + radius * Math.sin(pitch), - this.posZ + radius * Math.sin(yaw) * Math.cos(pitch)) - .time(48 + this.rand.nextInt(12)) - .clr(brightness, brightness, 1.0f).spawn(world); - } } } @Override - public boolean attackEntityFrom(DamageSource source, float damage){ + public boolean contains(Vec3d vec){ + return vec.distanceTo(this.getPositionVector()) < radius; // The surface counts as outside + } - if(source != null && source.getImmediateSource() != null){ - // Now works for any source of damage. - source.getImmediateSource().playSound(WizardrySounds.SPELL_DEFLECTION, 0.3f, 1.3f); + /** Returns true if the given bounding box is completely inside this forcefield (the surface counts as outside). */ + public boolean contains(AxisAlignedBB box){ + return Arrays.stream(WizardryUtilities.getVertices(box)).allMatch(this::contains); + } + + /** Returns true if the given entity is completely inside this forcefield (the surface counts as outside). */ + public boolean contains(Entity entity){ + return contains(entity.getEntityBoundingBox()); + } + + @Override + public Vec3d calculateIntercept(Vec3d origin, Vec3d endpoint, float fuzziness){ + + // We want the intercept between the line and a sphere + // First we need to find the point where the line is closest to the centre + // Then we can use a bit of geometry to find the intercept + + // Find the closest point to the centre + // http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html + Vec3d line = endpoint.subtract(origin); + double t = -origin.subtract(this.getPositionVector()).dotProduct(line) / line.lengthSquared(); + Vec3d closestPoint = origin.add(line.scale(t)); + // Now calculate the distance from that point to the centre (squared because that's all we need) + double dsquared = closestPoint.squareDistanceTo(this.getPositionVector()); + double rsquared = Math.pow(radius + fuzziness, 2); + // If the minimum distance is outside the radius (plus fuzziness) then there is no intercept + if(dsquared > rsquared) return null; + // Now do pythagoras to find the other side of the triangle, which is the distance along the line from + // the closest point to the edge of the sphere, and go that far back towards the origin - and that's it! + return closestPoint.subtract(line.normalize().scale(MathHelper.sqrt(rsquared - dsquared))); + } + + // Need to sync the caster because we're now dealing with client-side motion + + @Override + public void writeSpawnData(ByteBuf data){ + super.writeSpawnData(data); + data.writeFloat(getRadius()); + if(getCaster() != null) data.writeInt(getCaster().getEntityId()); + } + + @Override + public void readSpawnData(ByteBuf data){ + + super.readSpawnData(data); + + setRadius(data.readFloat()); + + if(!data.isReadable()) return; + + Entity entity = world.getEntityByID(data.readInt()); + + if(entity instanceof EntityLivingBase){ + setCaster((EntityLivingBase)entity); + }else{ + Wizardry.logger.warn("Forcefield caster with ID in spawn data not found"); } - super.attackEntityFrom(source, damage); - return false; } @Override @@ -88,4 +274,91 @@ public class EntityForcefield extends EntityMagicConstruct { return false; } + // Prevents any kind of interactions or attacks through the forcefield + // We may as well include projectile damage for this, then it will act as a failsafe + + @SubscribeEvent + public static void onLivingAttackEvent(LivingAttackEvent event){ + + if(event.getSource().getTrueSource() instanceof EntityPlayer && event.getSource().isProjectile() + && ItemArtefact.isArtefactActive((EntityPlayer)event.getSource().getTrueSource(), WizardryItems.ring_defender)){ + return; // Players wearing a ring of the defender can shoot stuff as normal, so don't cancel the event + } + + if(!event.getSource().isUnblockable() && event.getSource().getTrueSource() != null && event.getEntityLiving() != null + && !(event.getSource().getImmediateSource() instanceof EntityForcefield)){ // If the damage was from a forcefield that's ok + // This condition will be false if both entities are outside a forcefield or both are in the same one + if(getSurroundingForcefield(event.getEntityLiving()) != getSurroundingForcefield(event.getSource().getTrueSource())){ + event.setCanceled(true); + } + } + } + + @Nullable + private static EntityForcefield getSurroundingForcefield(World world, Vec3d vec){ + + double searchRadius = 20; + + List forcefields = WizardryUtilities.getEntitiesWithinRadius(searchRadius, vec.x, + vec.y, vec.z, world, EntityForcefield.class); + + forcefields.removeIf(f -> !f.contains(vec)); + // There should only be one left at this point since we now have anti-overlap, but commands might bypass that + return forcefields.stream().min(Comparator.comparingDouble(f -> vec.squareDistanceTo(f.getPositionVector()))) + .orElse(null); + } + + @Nullable + private static EntityForcefield getSurroundingForcefield(World world, AxisAlignedBB box, Vec3d vec){ + + double searchRadius = 20; + + List forcefields = WizardryUtilities.getEntitiesWithinRadius(searchRadius, vec.x, + vec.y, vec.z, world, EntityForcefield.class); + + forcefields.removeIf(f -> !f.contains(box)); + // There should only be one left at this point since we now have anti-overlap, but commands might bypass that + return forcefields.stream().min(Comparator.comparingDouble(f -> vec.squareDistanceTo(f.getPositionVector()))) + .orElse(null); + } + + @Nullable + private static EntityForcefield getSurroundingForcefield(Entity entity){ + return getSurroundingForcefield(entity.world, entity.getEntityBoundingBox(), entity.getPositionVector()); + } + + @SubscribeEvent + public static void onPlayerInteractEvent(PlayerInteractEvent event){ + + if(!event.isCancelable()) return; // We don't care about clicking empty space + + // For some reason block bounding boxes are relative whereas entity bounding boxes are absolute + AxisAlignedBB box = event.getWorld().getBlockState(event.getPos()).getBoundingBox(event.getWorld(), event.getPos()) + .offset(event.getPos().getX(), event.getPos().getY(), event.getPos().getZ()); + + if(event instanceof PlayerInteractEvent.EntityInteract){ + box = ((PlayerInteractEvent.EntityInteract)event).getTarget().getEntityBoundingBox(); + }else if(event instanceof PlayerInteractEvent.EntityInteractSpecific){ + box = ((PlayerInteractEvent.EntityInteractSpecific)event).getTarget().getEntityBoundingBox(); + } + + // If the player is trying to interact across a forcefield boundary, cancel the event + // The most pragmatic solution here is to use the centres - it's not perfect, but it's simple! + if(getSurroundingForcefield(event.getWorld(), WizardryUtilities.getCentre(box)) + != getSurroundingForcefield(event.getWorld(), event.getEntityPlayer().getPositionVector())){ + event.setCanceled(true); + } + } + + @SubscribeEvent + public static void onExplosionEvent(ExplosionEvent event){ + + EntityForcefield forcefield = getSurroundingForcefield(event.getWorld(), event.getExplosion().getPosition()); + // Not a particularly efficient way of doing it but explosions are laggy anyway, and the code is neat :P + event.getExplosion().getAffectedBlockPositions().removeIf(p -> getSurroundingForcefield(event.getWorld(), + new Vec3d(p).add(0.5, 0.5, 0.5)) != forcefield); + + event.getExplosion().getPlayerKnockbackMap().keySet().removeIf(p -> getSurroundingForcefield(p) != forcefield); + } + } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java index 1632335b..690e7ec8 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityFrostSigil.java @@ -1,9 +1,9 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -12,8 +12,11 @@ import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class EntityFrostSigil extends EntityMagicConstruct { public EntityFrostSigil(World world){ @@ -38,12 +41,15 @@ public class EntityFrostSigil extends EntityMagicConstruct { WizardryUtilities.attackEntityWithoutKnockback(target, this.getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), DamageType.FROST) - : DamageSource.MAGIC, 8); + : DamageSource.MAGIC, Spells.frost_sigil.getProperty(Spell.DAMAGE).floatValue() + * damageMultiplier); if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) - target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 200, 1)); + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, + Spells.frost_sigil.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.frost_sigil.getProperty(Spell.EFFECT_STRENGTH).intValue())); - this.playSound(WizardrySounds.SPELL_FREEZE, 1.0f, 1.0f); + this.playSound(WizardrySounds.ENTITY_FROST_SIGIL_TRIGGER, 1.0f, 1.0f); // The trap is destroyed once triggered. this.setDead(); @@ -51,9 +57,9 @@ public class EntityFrostSigil extends EntityMagicConstruct { } }else if(this.rand.nextInt(15) == 0){ double radius = 0.5 + rand.nextDouble() * 0.3; - double angle = rand.nextDouble() * Math.PI * 2; + float angle = rand.nextFloat() * (float)Math.PI * 2;; ParticleBuilder.create(Type.SNOW) - .pos(this.posX + radius * Math.cos(angle), this.posY + 0.1, this.posZ + radius * Math.sin(angle)) + .pos(this.posX + radius * MathHelper.cos(angle), this.posY + 0.1, this.posZ + radius * MathHelper.sin(angle)) .vel(0, 0, 0) // Required since default for snow is not stationary .spawn(world); } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java index 6a2baaab..f792d4ef 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHailstorm.java @@ -1,6 +1,7 @@ package electroblob.wizardry.entity.construct; import electroblob.wizardry.entity.projectile.EntityIceShard; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; public class EntityHailstorm extends EntityMagicConstruct { @@ -20,9 +21,9 @@ public class EntityHailstorm extends EntityMagicConstruct { EntityIceShard iceshard = new EntityIceShard(world); iceshard.setPosition(this.posX + rand.nextDouble() * 6 - 3, this.posY + rand.nextDouble() * 4 - 2, this.posZ + rand.nextDouble() * 6 - 3); - iceshard.motionX = Math.cos(Math.toRadians(this.rotationYaw + 90)); + iceshard.motionX = MathHelper.cos((float)Math.toRadians(this.rotationYaw + 90)); iceshard.motionY = -0.6; - iceshard.motionZ = Math.sin(Math.toRadians(this.rotationYaw + 90)); + iceshard.motionZ = MathHelper.sin((float)Math.toRadians(this.rotationYaw + 90)); iceshard.setCaster(this.getCaster()); iceshard.damageMultiplier = this.damageMultiplier; this.world.spawnEntity(iceshard); diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java index 80bec470..8a56a293 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java @@ -1,32 +1,44 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.item.ItemLightningHammer; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.LightningHammer; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; +import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.MoverType; import net.minecraft.entity.effect.EntityLightningBolt; -import net.minecraft.init.SoundEvents; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import java.util.List; + public class EntityHammer extends EntityMagicConstruct { /** How long the hammer has been falling for. */ public int fallTime; + public boolean spin = false; + public EntityHammer(World world){ super(world); this.setSize(1.0f, 1.9F); @@ -51,15 +63,20 @@ public class EntityHammer extends EntityMagicConstruct { return this.getEntityBoundingBox(); } + @Override + public void applyEntityCollision(Entity entity){ + super.applyEntityCollision(entity); + } + @Override public void onUpdate(){ super.onUpdate(); - if(this.ticksExisted % 20 == 1 && !this.onGround && world.isRemote){ - // Though this sound does repeat, it stops when it hits the ground. - Wizardry.proxy.playMovingSound(this, WizardrySounds.SPELL_LOOP_LIGHTNING, 3.0f, 1.0f, false); - } +// if(this.ticksExisted % 20 == 1 && !this.onGround && world.isRemote){ +// // Though this sound does repeat, it stops when it hits the ground. +// Wizardry.proxy.playMovingSound(this, WizardrySounds.ENTITY_HAMMER_FALLING, WizardrySounds.SPELLS, 3.0f, 1.0f, false); +// } if(this.world.isRemote && this.ticksExisted % 3 == 0){ ParticleBuilder.create(Type.SPARK) @@ -67,65 +84,81 @@ public class EntityHammer extends EntityMagicConstruct { .spawn(world); } - if(!this.world.isRemote){ + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + ++this.fallTime; + this.motionY -= 0.03999999910593033D; + this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ); + this.motionX *= 0.9800000190734863D; + this.motionY *= 0.9800000190734863D; + this.motionZ *= 0.9800000190734863D; - this.prevPosX = this.posX; - this.prevPosY = this.posY; - this.prevPosZ = this.posZ; - ++this.fallTime; - this.motionY -= 0.03999999910593033D; - this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ); - this.motionX *= 0.9800000190734863D; - this.motionY *= 0.9800000190734863D; - this.motionZ *= 0.9800000190734863D; + if(this.onGround){ - if(this.onGround){ + this.motionX *= 0.699999988079071D; + this.motionZ *= 0.699999988079071D; + this.motionY *= -0.5D; - this.motionX *= 0.699999988079071D; - this.motionZ *= 0.699999988079071D; - this.motionY *= -0.5D; + this.rotationPitch = 0; + this.spin = false; - if(this.ticksExisted % 40 == 0){ + if(this.ticksExisted % Spells.lightning_hammer.getProperty(LightningHammer.ATTACK_INTERVAL).floatValue() == 0){ - double seekerRange = 10.0d; + double seekerRange = Spells.lightning_hammer.getProperty(Spell.EFFECT_RADIUS).doubleValue(); - List targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX, - this.posY + 1, this.posZ, world); + List targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX, + this.posY + 1, this.posZ, world); - // For this spell there is no limit to the amount of secondary targets! - for(EntityLivingBase target : targets){ + int maxTargets = Spells.lightning_hammer.getProperty(LightningHammer.SECONDARY_MAX_TARGETS).intValue(); + while(targets.size() > maxTargets) targets.remove(targets.size() - 1); - if(this.isValidTarget(target)){ + for(EntityLivingBase target : targets){ - if(world.isRemote){ - - ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world); - - ParticleBuilder.spawnShockParticles(world, target.posX, - target.getEntityBoundingBox().minY + target.height, target.posZ); - } + if(WizardryUtilities.isLiving(target) && this.isValidTarget(target)){ - target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, rand.nextFloat() * 0.4F + 1.5F); + if(world.isRemote){ - if(this.getCaster() != null){ - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.SHOCK), - 6 * damageMultiplier); - WizardryUtilities.applyStandardKnockback(this, target); - }else{ - target.attackEntityFrom(DamageSource.MAGIC, 6 * damageMultiplier); - } + ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world); + + ParticleBuilder.spawnShockParticles(world, target.posX, + target.getEntityBoundingBox().minY + target.height, target.posZ); + } + + target.playSound(WizardrySounds.ENTITY_HAMMER_ATTACK, 1.0F, rand.nextFloat() * 0.4F + 1.5F); + + float damage = Spells.lightning_hammer.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier; + + if(this.getCaster() != null){ + WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage( + this, getCaster(), DamageType.SHOCK), damage); + WizardryUtilities.applyStandardKnockback(this, target); + }else{ + target.attackEntityFrom(DamageSource.MAGIC, damage); } } } } + + }else{ + + if(spin) this.setRotation(this.rotationYaw, this.rotationPitch + 15); + + List collided = world.getEntitiesInAABBexcluding(this, this.getCollisionBoundingBox(), e -> e instanceof EntityLivingBase); + + float damage = Spells.lightning_hammer.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier; + + for(Entity entity : collided){ + entity.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.SHOCK), damage); + //if(entity instanceof EntityLivingBase) ((EntityLivingBase)entity).knockBack(this, 2, -this.motionX, -this.motionZ); + } } } @Override public void despawn(){ - this.playSound(SoundEvents.ENTITY_GENERIC_EXPLODE, 1.0F, 1.0f); + this.playSound(WizardrySounds.ENTITY_HAMMER_EXPLODE, 1.0F, 1.0f); if(this.world.isRemote){ this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); @@ -156,6 +189,30 @@ public class EntityHammer extends EntityMagicConstruct { false); world.addWeatherEffect(entitylightning); } + + this.playSound(WizardrySounds.ENTITY_HAMMER_LAND, 1.0F, 0.6f); + } + } + + @Override + public boolean processInitialInteract(EntityPlayer player, EnumHand hand){ + + if(player == this.getCaster() && ItemArtefact.isArtefactActive(player, WizardryItems.ring_hammer) + && player.getHeldItemMainhand().isEmpty() && ticksExisted > 10){ + + this.setDead(); + + ItemStack hammer = new ItemStack(WizardryItems.lightning_hammer); + if(!hammer.hasTagCompound()) hammer.setTagCompound(new NBTTagCompound()); + hammer.getTagCompound().setInteger(ItemLightningHammer.DURATION_NBT_KEY, lifetime); + hammer.setItemDamage(ticksExisted); + hammer.getTagCompound().setFloat(ItemLightningHammer.DAMAGE_MULTIPLIER_NBT_KEY, damageMultiplier); + + player.setHeldItem(EnumHand.MAIN_HAND, hammer); + return true; + + }else{ + return super.processInitialInteract(player, hand); } } @@ -163,12 +220,39 @@ public class EntityHammer extends EntityMagicConstruct { public void writeEntityToNBT(NBTTagCompound nbttagcompound){ super.writeEntityToNBT(nbttagcompound); nbttagcompound.setByte("Time", (byte)this.fallTime); + nbttagcompound.setBoolean("Spin", spin); } @Override public void readEntityFromNBT(NBTTagCompound nbttagcompound){ super.readEntityFromNBT(nbttagcompound); this.fallTime = nbttagcompound.getByte("Time") & 255; + this.spin = nbttagcompound.getBoolean("Spin"); + } + + // Need to sync the caster so they don't have particles spawned at them + + @Override + public void writeSpawnData(ByteBuf data){ + super.writeSpawnData(data); + data.writeBoolean(spin); + if(getCaster() != null) data.writeInt(getCaster().getEntityId()); + } + + @Override + public void readSpawnData(ByteBuf data){ + super.readSpawnData(data); + spin = data.readBoolean(); + + if(!data.isReadable()) return; + + Entity entity = world.getEntityByID(data.readInt()); + + if(entity instanceof EntityLivingBase){ + setCaster((EntityLivingBase)entity); + }else{ + Wizardry.logger.warn("Lightning hammer caster with ID in spawn data not found"); + } } @Override diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java index 14406109..df3dd462 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java @@ -1,8 +1,8 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -10,10 +10,15 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.DamageSource; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class EntityHealAura extends EntityMagicConstruct { + // TODO: Implement blast modifiers + public EntityHealAura(World world){ super(world); this.height = 1.0f; @@ -24,7 +29,7 @@ public class EntityHealAura extends EntityMagicConstruct { public void onUpdate(){ if(this.ticksExisted % 25 == 1){ - this.playSound(WizardrySounds.SPELL_LOOP_SPARKLE, 0.1f, 1.0f); + this.playSound(WizardrySounds.ENTITY_HEAL_AURA_AMBIENT, 0.1f, 1.0f); } super.onUpdate(); @@ -46,9 +51,9 @@ public class EntityHealAura extends EntityMagicConstruct { if(this.getCaster() != null){ target.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.RADIANT), - 1 * damageMultiplier); + Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier); }else{ - target.attackEntityFrom(DamageSource.MAGIC, 1 * damageMultiplier); + target.attackEntityFrom(DamageSource.MAGIC, Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier); } // Removes knockback @@ -58,16 +63,16 @@ public class EntityHealAura extends EntityMagicConstruct { } }else if(target.getHealth() < target.getMaxHealth() && this.ticksExisted % 5 == 0){ - target.heal(1 * damageMultiplier); + target.heal(Spells.healing_aura.getProperty(Spell.HEALTH).floatValue() * damageMultiplier); } } }else{ for(int i=1; i<3; i++){ float brightness = 0.5f + (rand.nextFloat() * 0.5f); double radius = rand.nextDouble() * 2.0; - double angle = rand.nextDouble() * Math.PI * 2; + float angle = rand.nextFloat() * (float)Math.PI * 2;; ParticleBuilder.create(Type.SPARKLE) - .pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle)) + .pos(this.posX + radius * MathHelper.cos(angle), this.posY, this.posZ + radius * MathHelper.sin(angle)) .vel(0, 0.05, 0) .time(48 + this.rand.nextInt(12)) .clr(1.0f, 1.0f, brightness) diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java b/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java index 86817bb4..75a83bc4 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityIceSpike.java @@ -1,35 +1,62 @@ package electroblob.wizardry.entity.construct; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.MoverType; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class EntityIceSpike extends EntityMagicConstruct { + private EnumFacing facing; + public EntityIceSpike(World world){ super(world); this.setSize(0.5f, 1.0f); } + public void setFacing(EnumFacing facing){ + this.facing = facing; + this.setRotation(-facing.getHorizontalAngle(), WizardryUtilities.getPitch(facing)); + float yaw = (-facing.getHorizontalAngle()) * (float)Math.PI/180; + float pitch = (WizardryUtilities.getPitch(facing) - 90) * (float)Math.PI/180; + Vec3d min = new Vec3d(-width/2, 0, -width/2).rotatePitch(pitch).rotateYaw(yaw); + Vec3d max = new Vec3d(width/2, height, width/2).rotatePitch(pitch).rotateYaw(yaw); + this.setEntityBoundingBox(new AxisAlignedBB(this.getPositionVector().add(min), this.getPositionVector().add(max))); + } + + public EnumFacing getFacing(){ + return facing; + } + @Override public void onUpdate(){ + double extensionSpeed = 0; + if(lifetime - this.ticksExisted < 15){ - this.motionY = -0.01 * (this.ticksExisted - (lifetime - 15)); + extensionSpeed = -0.01 * (this.ticksExisted - (lifetime - 15)); }else if(lifetime - this.ticksExisted < 25){ - this.motionY = 0; + extensionSpeed = 0; }else if(lifetime - this.ticksExisted < 28){ - this.motionY = 0.25; + extensionSpeed = 0.25; } - this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ); + if(facing != null){ // Will probably be null on the client side, but should never be on the server side + this.move(MoverType.SELF, this.facing.getXOffset() * extensionSpeed, this.facing.getYOffset() * extensionSpeed, + this.facing.getZOffset() * extensionSpeed); + } - if(lifetime - this.ticksExisted == 30) this.playSound(WizardrySounds.SPELL_ICE, 1, 2); + if(lifetime - this.ticksExisted == 30) this.playSound(WizardrySounds.ENTITY_ICE_SPIKE_EXTEND, 1, 2); if(!this.world.isRemote){ for(Object entity : this.world.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox())){ @@ -37,8 +64,10 @@ public class EntityIceSpike extends EntityMagicConstruct { // Potion effect only gets added if the damage succeeded. if(((EntityLivingBase)entity).attackEntityFrom( MagicDamage.causeDirectMagicDamage(this.getCaster(), DamageType.FROST), - 5 * this.damageMultiplier)) - ((EntityLivingBase)entity).addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0)); + Spells.ice_spikes.getProperty(Spell.DAMAGE).floatValue() * this.damageMultiplier)) + ((EntityLivingBase)entity).addPotionEffect(new PotionEffect(WizardryPotions.frost, + Spells.ice_spikes.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.ice_spikes.getProperty(Spell.EFFECT_STRENGTH).intValue())); } } } @@ -46,4 +75,8 @@ public class EntityIceSpike extends EntityMagicConstruct { super.onUpdate(); } + @Override + public int getBrightnessForRender(){ + return 15728880; + } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java index 589cea82..412df121 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java @@ -1,8 +1,8 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -10,10 +10,15 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.DamageSource; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class EntityLightningSigil extends EntityMagicConstruct { + public static final String SECONDARY_MAX_TARGETS = "secondary_max_targets"; + public EntityLightningSigil(World world){ super(world); this.height = 0.2f; @@ -42,22 +47,24 @@ public class EntityLightningSigil extends EntityMagicConstruct { // Only works if target is actually damaged to account for hurtResistantTime if(target.attackEntityFrom(getCaster() != null ? MagicDamage.causeIndirectMagicDamage(this, getCaster(), - DamageType.SHOCK) : DamageSource.MAGIC, 6)){ + DamageType.SHOCK) : DamageSource.MAGIC, Spells.lightning_sigil.getProperty(Spell.DIRECT_DAMAGE) + .floatValue() * damageMultiplier)){ // Removes knockback target.motionX = velX; target.motionY = velY; target.motionZ = velZ; - this.playSound(WizardrySounds.SPELL_SPARK, 1.0f, 1.0f); + this.playSound(WizardrySounds.ENTITY_LIGHTNING_SIGIL_TRIGGER, 1.0f, 1.0f); // Secondary chaining effect - double seekerRange = 5.0d; + double seekerRange = Spells.lightning_sigil.getProperty(Spell.EFFECT_RADIUS).doubleValue(); List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, target.posX, target.posY + target.height / 2, target.posZ, world); - for(int j = 0; j < Math.min(secondaryTargets.size(), 3); j++){ + for(int j = 0; j < Math.min(secondaryTargets.size(), + Spells.lightning_sigil.getProperty(SECONDARY_MAX_TARGETS).floatValue()); j++){ EntityLivingBase secondaryTarget = secondaryTargets.get(j); @@ -73,11 +80,12 @@ public class EntityLightningSigil extends EntityMagicConstruct { secondaryTarget.posZ); } - secondaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, + secondaryTarget.playSound(WizardrySounds.ENTITY_LIGHTNING_SIGIL_TRIGGER, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); secondaryTarget.attackEntityFrom( - MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.SHOCK), 4); + MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.SHOCK), + Spells.lightning_sigil.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier); } } @@ -89,9 +97,9 @@ public class EntityLightningSigil extends EntityMagicConstruct { if(this.world.isRemote && this.rand.nextInt(15) == 0){ double radius = 0.5 + rand.nextDouble() * 0.3; - double angle = rand.nextDouble() * Math.PI * 2; + float angle = rand.nextFloat() * (float)Math.PI * 2;; ParticleBuilder.create(Type.SPARK) - .pos(this.posX + radius * Math.cos(angle), this.posY + 0.1, this.posZ + radius * Math.sin(angle)) + .pos(this.posX + radius * MathHelper.cos(angle), this.posY + 0.1, this.posZ + radius * MathHelper.sin(angle)) .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java b/src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java index 8951c743..14b514a9 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityMagicConstruct.java @@ -1,38 +1,38 @@ package electroblob.wizardry.entity.construct; -import java.lang.ref.WeakReference; -import java.util.UUID; - +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityOwnable; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.SoundCategory; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import javax.annotation.Nullable; +import java.util.UUID; + /** * This class is for all inanimate magical constructs which are not projectiles. It was made from scratch to provide a * unifying superclass for black hole, blizzard, tornado and a few others which all share some characteristics. The - * EntityPlayer instance of the caster, the lifetime and the damage multiplier are stored and synced here. - *

    + * caster UUID, lifetime and damage multiplier are stored here, and lifetime is also synced here. + *

    * When extending this class, override both constructors. Generally speaking, subclasses of this class are areas of * effect which deal damage or apply effects over time. * * @since Wizardry 1.0 */ -public abstract class EntityMagicConstruct extends Entity implements IEntityAdditionalSpawnData { +public abstract class EntityMagicConstruct extends Entity implements IEntityOwnable, IEntityAdditionalSpawnData { - /** The entity that created this construct */ - private WeakReference caster; - - /** - * The UUID of the caster. Note that this is only for loading purposes; during normal updates the actual entity - * instance is stored (so that getEntityByUUID is not called constantly), so this will not always be synced (this is - * why it is private). - */ + /** The UUID of the caster. As of Wizardry 4.2, this is synced, and rather than storing the caster + * instance via a weak reference, it is fetched from the UUID each time it is needed in + * {@link EntityMagicConstruct#getCaster()}. */ private UUID casterUUID; /** @@ -62,13 +62,6 @@ public abstract class EntityMagicConstruct extends Entity implements IEntityAddi public void onUpdate(){ - if(this.getCaster() == null && this.casterUUID != null){ - Entity entity = WizardryUtilities.getEntityByUUID(world, casterUUID); - if(entity instanceof EntityLivingBase){ - this.caster = new WeakReference((EntityLivingBase)entity); - } - } - if(this.ticksExisted > lifetime && lifetime != -1){ this.despawn(); } @@ -118,25 +111,51 @@ public abstract class EntityMagicConstruct extends Entity implements IEntityAddi lifetime = data.readInt(); } + @Nullable + @Override + public UUID getOwnerId(){ + return casterUUID; + } + + @Nullable + @Override + public Entity getOwner(){ + return getCaster(); // Delegate to getCaster + } + /** * Returns the EntityLivingBase that created this construct, or null if it no longer exists. Cases where the entity * may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported to * another dimension, or this construct simply had no caster in the first place. */ - public EntityLivingBase getCaster(){ - return caster == null ? null : caster.get(); + @Nullable + public EntityLivingBase getCaster(){ // Kept despite the above method because it returns an EntityLivingBase + + Entity entity = WizardryUtilities.getEntityByUUID(world, getOwnerId()); + + if(entity != null && !(entity instanceof EntityLivingBase)){ // Should never happen + Wizardry.logger.warn("{} has a non-living owner!", this); + entity = null; + } + + return (EntityLivingBase)entity; } - public void setCaster(EntityLivingBase caster){ - this.caster = new WeakReference(caster); + public void setCaster(@Nullable EntityLivingBase caster){ + this.casterUUID = caster == null ? null : caster.getUniqueID(); } /** - * Shorthand for {@link WizardryUtilities#isValidTarget(Entity, Entity)}, with the owner of this construct as the + * Shorthand for {@link AllyDesignationSystem#isValidTarget(Entity, Entity)}, with the owner of this construct as the * attacker. Also allows subclasses to override it if they wish to do so. */ public boolean isValidTarget(Entity target){ - return WizardryUtilities.isValidTarget(this.getCaster(), target); + return AllyDesignationSystem.isValidTarget(this.getCaster(), target); + } + + @Override + public SoundCategory getSoundCategory(){ + return WizardrySounds.SPELLS; } @Override diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java index 3571aaa4..18c8d51d 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java @@ -1,10 +1,12 @@ package electroblob.wizardry.entity.construct; -import java.util.List; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.spell.Tornado; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -15,15 +17,18 @@ import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.MoverType; -import net.minecraft.entity.passive.EntityPig; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.SPacketEntityVelocity; import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import java.util.List; + public class EntityTornado extends EntityMagicConstruct { private double velX, velZ; @@ -45,63 +50,69 @@ public class EntityTornado extends EntityMagicConstruct { super.onUpdate(); + double radius = Spells.tornado.getProperty(Spell.EFFECT_RADIUS).doubleValue(); + if(this.ticksExisted % 120 == 1 && world.isRemote){ // Repeat is false so that the sound fades out when the tornado does rather than stopping suddenly - Wizardry.proxy.playMovingSound(this, WizardrySounds.SPELL_LOOP_WIND, 1.0f, 1.0f, false); + Wizardry.proxy.playMovingSound(this, WizardrySounds.ENTITY_TORNADO_AMBIENT, WizardrySounds.SPELLS, 1.0f, 1.0f, false); } this.move(MoverType.SELF, velX, motionY, velZ); BlockPos pos = new BlockPos(this); - int y = WizardryUtilities.getNearestFloorLevelC(world, pos.up(3), 5); - pos = new BlockPos(pos.getX(), y, pos.getZ()); + Integer y = WizardryUtilities.getNearestSurface(world, pos.up(3), EnumFacing.UP, 5, true, WizardryUtilities.SurfaceCriteria.NOT_AIR_TO_AIR); - if(this.world.getBlockState(pos).getMaterial() == Material.LAVA){ - // Fire tornado! - this.setFire(5); + if(y != null){ + + pos = new BlockPos(pos.getX(), y, pos.getZ()); + + if(this.world.getBlockState(pos).getMaterial() == Material.LAVA){ + // Fire tornado! + this.setFire(5); + } } if(!this.world.isRemote){ - List targets = WizardryUtilities.getEntitiesWithinRadius(4.0d, this.posX, this.posY, + List targets = WizardryUtilities.getEntitiesWithinRadius(radius, this.posX, this.posY, this.posZ, this.world); for(EntityLivingBase target : targets){ + if(target instanceof EntityPlayer && ((getCaster() instanceof EntityPlayer && !Wizardry.settings.playersMoveEachOther) + || ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring))){ + continue; + } + if(this.isValidTarget(target)){ double velY = target.motionY; - double dx = this.posX - target.posX > 0 ? 0.5 - (this.posX - target.posX) / 8 - : -0.5 - (this.posX - target.posX) / 8; - double dz = this.posZ - target.posZ > 0 ? 0.5 - (this.posZ - target.posZ) / 8 - : -0.5 - (this.posZ - target.posZ) / 8; + // TODO: This doesn't seem right... + double dx = (this.posX - target.posX > 0 ? 0.5 : -0.5) - (this.posX - target.posX) * 0.125; + double dz = (this.posZ - target.posZ > 0 ? 0.5 : -0.5) - (this.posZ - target.posZ) * 0.125; if(this.isBurning()){ - target.setFire(4); + target.setFire(4); // Just a fun Easter egg so no properties here! } + float damage = Spells.tornado.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; + if(this.getCaster() != null){ - target.attackEntityFrom( - MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC), - 1 * damageMultiplier); + target.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, getCaster(), + DamageType.MAGIC), damage); }else{ - target.attackEntityFrom(DamageSource.MAGIC, 1 * damageMultiplier); + target.attackEntityFrom(DamageSource.MAGIC, damage); } target.motionX = dx; - target.motionY = velY + 0.2; + target.motionY = velY + Spells.tornado.getProperty(Tornado.UPWARD_ACCELERATION).floatValue(); target.motionZ = dz; // Player motion is handled on that player's client so needs packets if(target instanceof EntityPlayerMP){ ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); } - - // The 'Not Again...' achievement - if(target instanceof EntityPig && WizardryUtilities.getRider(target) instanceof EntityPlayer){ - WizardryAdvancementTriggers.pig_tornado.triggerFor((EntityPlayer)WizardryUtilities.getRider(target)); - } } } }else{ @@ -114,38 +125,43 @@ public class EntityTornado extends EntityMagicConstruct { BlockPos pos1 = new BlockPos(blockX, this.posY + 3, blockZ); - int blockY = WizardryUtilities.getNearestFloorLevelC(world, pos1, 5) - 1; + Integer blockY = WizardryUtilities.getNearestSurface(world, pos1, EnumFacing.UP, 5, true, WizardryUtilities.SurfaceCriteria.NOT_AIR_TO_AIR); - pos1 = new BlockPos(pos1.getX(), blockY, pos1.getZ()); + if(blockY != null){ - IBlockState block = this.world.getBlockState(pos1); + blockY--; - // If the block it found was air or something it can't pick up, it makes a best guess based on the - // biome. - if(!canTornadoPickUpBitsOf(block)){ - block = world.getBiome(pos1).topBlock; - } + pos1 = new BlockPos(pos1.getX(), blockY, pos1.getZ()); - Wizardry.proxy.spawnTornadoParticle(world, this.posX, this.posY + yPos, this.posZ, this.velX, this.velZ, - yPos / 3 + 0.5d, 100, block, pos1); - Wizardry.proxy.spawnTornadoParticle(world, this.posX, this.posY + yPos, this.posZ, this.velX, this.velZ, - yPos / 3 + 0.5d, 100, block, pos1); - - // Sometimes spawns leaf particles if the block is leaves, or snow particles if the block is snow - if(this.rand.nextInt(3) == 0){ + IBlockState block = this.world.getBlockState(pos1); - Type type = null; - - if(block.getMaterial() == Material.LEAVES) type = Type.LEAF; - if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW) type = Type.SNOW; - - if(type != null){ - double yPos1 = rand.nextDouble() * 8; - ParticleBuilder.create(type) - .pos(this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1, - this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d)) - .time(40 + rand.nextInt(10)) - .spawn(world); + // If the block it found was air or something it can't pick up, it makes a best guess based on the biome + if(!canTornadoPickUpBitsOf(block)){ + block = world.getBiome(pos1).topBlock; + } + + Wizardry.proxy.spawnTornadoParticle(world, this.posX, this.posY + yPos, this.posZ, this.velX, this.velZ, + yPos / 3 + 0.5d, 100, block, pos1); + Wizardry.proxy.spawnTornadoParticle(world, this.posX, this.posY + yPos, this.posZ, this.velX, this.velZ, + yPos / 3 + 0.5d, 100, block, pos1); + + // Sometimes spawns leaf particles if the block is leaves, or snow particles if the block is snow + if(this.rand.nextInt(3) == 0){ + + ResourceLocation type = null; + + if(block.getMaterial() == Material.LEAVES) type = Type.LEAF; + if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW) + type = Type.SNOW; + + if(type != null){ + double yPos1 = rand.nextDouble() * 8; + ParticleBuilder.create(type) + .pos(this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1, + this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d)) + .time(40 + rand.nextInt(10)) + .spawn(world); + } } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java index 85b9d65d..d0cd4c93 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityAIAttackSpell.java @@ -1,8 +1,5 @@ package electroblob.wizardry.entity.living; -import java.util.ArrayList; -import java.util.List; - import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent.Source; import electroblob.wizardry.packet.PacketNPCCastSpell; @@ -18,6 +15,9 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.network.NetworkRegistry.TargetPoint; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import java.util.ArrayList; +import java.util.List; + /** * Entity AI class for use by instances of {@link ISpellCaster}. This deals with pathing, the spell casting itself and * the attack cooldown. Also provides an automatic implementation of continuous spell casting using the methods @@ -106,7 +106,7 @@ public class EntityAIAttackSpell extends attacker.setContinuousSpell(spell); WizardryPacketHandler.net.sendToAllAround( new PacketNPCCastSpell.Message(attacker.getEntityId(), target == null ? -1 : target.getEntityId(), - EnumHand.MAIN_HAND, spell.id(), modifiers), + EnumHand.MAIN_HAND, spell, modifiers), // Particles are usually only visible from 16 blocks away, so 128 is more than far enough. // TODO: Why is this one a 128 block radius, whilst the other one is all in dimension? new TargetPoint(attacker.dimension, attacker.posX, attacker.posY, attacker.posZ, 128)); @@ -143,8 +143,8 @@ public class EntityAIAttackSpell extends if(distanceSq > (double)this.maxAttackDistance || !targetIsVisible // ...or the spell is cancelled via events... || MinecraftForge.EVENT_BUS - .post(new SpellCastEvent.Tick(attacker, attacker.getContinuousSpell(), attacker.getModifiers(), - Source.NPC, this.continuousSpellDuration - this.continuousSpellTimer)) + .post(new SpellCastEvent.Tick(Source.NPC, attacker.getContinuousSpell(), attacker, + attacker.getModifiers(), this.continuousSpellDuration - this.continuousSpellTimer)) // ...or the spell no longer succeeds... || !attacker.getContinuousSpell().cast(attacker.world, attacker, EnumHand.MAIN_HAND, this.continuousSpellDuration - this.continuousSpellTimer, target, attacker.getModifiers()) @@ -159,8 +159,8 @@ public class EntityAIAttackSpell extends }else if(this.continuousSpellDuration - this.continuousSpellTimer == 1){ // On the first tick, if the spell did succeed, fire SpellCastEvent.Post. - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(attacker, attacker.getContinuousSpell(), - attacker.getModifiers(), Source.NPC)); + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.NPC, attacker.getContinuousSpell(), + attacker, attacker.getModifiers())); } }else if(--this.cooldown == 0){ @@ -209,7 +209,7 @@ public class EntityAIAttackSpell extends private boolean attemptCastSpell(Spell spell, SpellModifiers modifiers){ // If anything stops the spell working at this point, nothing else happens. - if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(attacker, spell, modifiers, Source.NPC))){ + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(Source.NPC, spell, attacker, modifiers))){ return false; } @@ -222,16 +222,16 @@ public class EntityAIAttackSpell extends }else{ - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(attacker, spell, modifiers, Source.NPC)); + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.NPC, spell, attacker, modifiers)); // For now, the cooldown is just added to the constant base cooldown. I think this // is a reasonable way of doing things; it's certainly better than before. - this.cooldown = this.baseCooldown + spell.cooldown; + this.cooldown = this.baseCooldown + spell.getCooldown(); - if(spell.doesSpellRequirePacket()){ + if(spell.requiresPacket()){ // Sends a packet to all players in dimension to tell them to spawn particles. IMessage msg = new PacketNPCCastSpell.Message(attacker.getEntityId(), target.getEntityId(), - EnumHand.MAIN_HAND, spell.id(), modifiers); + EnumHand.MAIN_HAND, spell, modifiers); WizardryPacketHandler.net.sendToDimension(msg, attacker.world.provider.getDimension()); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java index 2bab8ebd..fc7873b2 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityBlazeMinion.java @@ -1,8 +1,5 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.UUID; - import electroblob.wizardry.Wizardry; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.EntityAIHurtByTarget; @@ -16,13 +13,15 @@ import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import java.util.UUID; + public class EntityBlazeMinion extends EntityBlaze implements ISummonedCreature { // Field implementations - private int lifetime = 600; - private WeakReference casterReference; + private int lifetime = -1; private UUID casterUUID; // Setter + getter implementations @@ -37,22 +36,12 @@ public class EntityBlazeMinion extends EntityBlaze implements ISummonedCreature } @Override - public WeakReference getCasterReference(){ - return casterReference; - } - - @Override - public void setCasterReference(WeakReference reference){ - casterReference = reference; - } - - @Override - public UUID getCasterUUID(){ + public UUID getOwnerId(){ return casterUUID; } @Override - public void setCasterUUID(UUID uuid){ + public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } @@ -65,13 +54,13 @@ public class EntityBlazeMinion extends EntityBlaze implements ISummonedCreature // EntityBlaze overrides // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its - // targeting system with one that targets hostile mobs and takes the ADS into account. + // targeting system with one that targets hostile mobs and takes the AllyDesignationSystem into account. @Override protected void initEntityAI(){ super.initEntityAI(); this.targetTasks.taskEntries.clear(); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, 0, false, true, this.getTargetSelector())); } @@ -142,8 +131,16 @@ public class EntityBlazeMinion extends EntityBlaze implements ISummonedCreature @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } @Override public boolean canAttackClass(Class entityType){ @@ -163,6 +160,6 @@ public class EntityBlazeMinion extends EntityBlaze implements ISummonedCreature @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + return Wizardry.settings.summonedCreatureNames && getCaster() != null; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java index 1444d6f9..8dc135d2 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java @@ -1,10 +1,7 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; - import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import io.netty.buffer.ByteBuf; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAILookIdle; @@ -99,18 +96,19 @@ public class EntityDecoy extends EntitySummonedCreature { return false; } - @Override - public void writeSpawnData(ByteBuf data){ - super.writeSpawnData(data); - if(this.getCaster() != null) data.writeInt(this.getCaster().getEntityId()); - } - - @Override - public void readSpawnData(ByteBuf data){ - super.readSpawnData(data); - if(!data.isReadable()) return; - this.setCasterReference( - new WeakReference((EntityLivingBase)this.world.getEntityByID(data.readInt()))); - } + // TESTME: Why was this here? It gets done in ISummonedCreature anyway +// @Override +// public void writeSpawnData(ByteBuf data){ +// super.writeSpawnData(data); +// if(this.getCaster() != null) data.writeInt(this.getCaster().getEntityId()); +// } +// +// @Override +// public void readSpawnData(ByteBuf data){ +// super.readSpawnData(data); +// if(!data.isReadable()) return; +// this.setCasterReference( +// new WeakReference((EntityLivingBase)this.world.getEntityByID(data.readInt()))); +// } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java index 356281ea..4a9c8755 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java @@ -1,11 +1,6 @@ package electroblob.wizardry.entity.living; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import com.google.common.base.Predicate; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; @@ -15,31 +10,18 @@ import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityList; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.IEntityLivingData; -import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.entity.ai.EntityAIHurtByTarget; -import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; -import net.minecraft.entity.ai.EntityAIOpenDoor; -import net.minecraft.entity.ai.EntityAIRestrictOpenDoor; -import net.minecraft.entity.ai.EntityAISwimming; -import net.minecraft.entity.ai.EntityAIWander; -import net.minecraft.entity.ai.EntityAIWatchClosest2; +import net.minecraft.entity.*; +import net.minecraft.entity.ai.*; import net.minecraft.entity.monster.EntityMob; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagInt; +import net.minecraft.nbt.NBTUtil; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; @@ -55,13 +37,21 @@ import net.minecraft.world.World; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import javax.annotation.Nullable; +import java.util.*; + public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData { - private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50); + private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50); public int textureIndex = 0; - public boolean hasTower = false; + /** True if this evil wizard was spawned as part of a structure (tower or shrine), false if it spawned naturally. */ + public boolean hasStructure = false; + + /** Stores the UUIDs of the other evil wizards spawned in the same group, if any. The wizard will not revenge-target + * entities whose UUIDs are in this set. This is currently used only for shrines. */ + public final Set groupUUIDs = new HashSet<>(); /** The entity selector passed into the new AI methods. */ protected Predicate targetSelector; @@ -95,11 +85,12 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity protected void entityInit(){ super.entityInit(); this.dataManager.register(HEAL_COOLDOWN, -1); - this.dataManager.register(ELEMENT, 0); + this.dataManager.register(ELEMENT, -1); } @Override protected void initEntityAI(){ + this.tasks.addTask(0, new EntityAISwimming(this)); this.tasks.addTask(4, new EntityAIRestrictOpenDoor(this)); this.tasks.addTask(5, new EntityAIOpenDoor(this, true)); @@ -107,34 +98,31 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity this.tasks.addTask(7, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F)); this.tasks.addTask(7, new EntityAIWander(this, 0.6D)); - this.targetSelector = new Predicate(){ + this.targetSelector = entity -> { - public boolean apply(Entity entity){ + // If the target is valid and not invisible... + if(entity != null && !entity.isInvisible() + && AllyDesignationSystem.isValidTarget(EntityEvilWizard.this, entity)){ - // If the target is valid and not invisible... - if(entity != null && !entity.isInvisible() - && WizardryUtilities.isValidTarget(EntityEvilWizard.this, entity)){ - - // ... and is a player, a summoned creature, another (non-evil) wizard ... - if(entity instanceof EntityPlayer - || (entity instanceof ISummonedCreature || entity instanceof EntityWizard - // ... or in the whitelist ... - || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist) - .contains(EntityList.getKey(entity.getClass()))) - // ... and isn't in the blacklist ... - && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist) - .contains(EntityList.getKey(entity.getClass()))){ - // ... it can be attacked. - return true; - } + // ... and is a player, a summoned creature, another (non-evil) wizard ... + if(entity instanceof EntityPlayer + || (entity instanceof ISummonedCreature || entity instanceof EntityWizard + // ... or in the whitelist ... + || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist) + .contains(EntityList.getKey(entity.getClass()))) + // ... and isn't in the blacklist ... + && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist) + .contains(EntityList.getKey(entity.getClass()))){ + // ... it can be attacked. + return true; } - - return false; } + + return false; }; this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); - this.targetTasks.addTask(0, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + this.targetTasks.addTask(0, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, 0, false, true, this.targetSelector)); } @@ -154,7 +142,8 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity } public Element getElement(){ - return Element.values()[this.dataManager.get(ELEMENT)]; + int n = this.dataManager.get(ELEMENT); + return n == -1 ? null : Element.values()[n]; } public void setElement(Element element){ @@ -192,6 +181,11 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity } } + @Override + public void setRevengeTarget(@Nullable EntityLivingBase target){ + if(target == null || !groupUUIDs.contains(target.getUniqueID())) super.setRevengeTarget(target); + } + @Override public void onLivingUpdate(){ @@ -225,13 +219,13 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity } }else{ if(this.getHealth() < 10){ - // Wizards heal themseselves more often if they have low health + // Wizards heal themselves more often if they have low health this.setHealCooldown(150); }else{ this.setHealCooldown(400); } - this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + this.playSound(Spells.heal.getSounds()[0], 0.7F, rand.nextFloat() * 0.4F + 1.0F); } } if(healCooldown > 0){ @@ -250,8 +244,8 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // Spell.get(spells[3]).getDisplayName())); // When right-clicked with a spell book in creative, sets one of the spells to that spell - if(player.capabilities.isCreativeMode && stack.getItem() instanceof ItemSpellBook){ - Spell spell = Spell.get(stack.getItemDamage()); + if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){ + Spell spell = Spell.byMetadata(stack.getItemDamage()); if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){ // The set(...) method returns the element that was replaced - neat! player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard", @@ -269,8 +263,9 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity super.writeEntityToNBT(nbt); nbt.setInteger("element", this.getElement().ordinal()); nbt.setInteger("skin", this.textureIndex); - nbt.setTag("spells", WizardryUtilities.listToNBT(spells, spell -> new NBTTagInt(spell.id()))); - nbt.setBoolean("hasTower", this.hasTower); + nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata()))); + nbt.setBoolean("hasStructure", this.hasStructure); + nbt.setTag("groupUUIDs", NBTExtras.listToNBT(groupUUIDs, NBTUtil::createUUIDTag)); } @Override @@ -278,9 +273,10 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity super.readEntityFromNBT(nbt); this.setElement(Element.values()[nbt.getInteger("element")]); this.textureIndex = nbt.getInteger("skin"); - this.spells = (List)WizardryUtilities.NBTToList(nbt.getTagList("spells", NBT.TAG_INT), - (NBTTagInt tag) -> Spell.get(tag.getInt())); - this.hasTower = nbt.getBoolean("hasTower"); + this.spells = (List)NBTExtras.NBTToList(nbt.getTagList("spells", NBT.TAG_INT), + (NBTTagInt tag) -> Spell.byMetadata(tag.getInt())); + this.hasStructure = nbt.getBoolean("hasStructure"); + this.groupUUIDs.addAll(NBTExtras.NBTToList(nbt.getTagList("groupUUIDs", NBT.TAG_COMPOUND), NBTUtil::getUUIDFromTag)); } @Override @@ -291,7 +287,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity @Override public boolean getCanSpawnHere(){ // Evil wizards can only spawn in the specified dimensions - for(int id : Wizardry.settings.evilWizardDimensions){ + for(int id : Wizardry.settings.mobSpawnDimensions){ if(this.dimension == id) return super.getCanSpawnHere(); } @@ -301,27 +297,27 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity @Override protected boolean canDespawn(){ // Evil wizards can only despawn if they don't have a tower (i.e. if they spawned naturally at night) - return !this.hasTower; + return !this.hasStructure; } - @Override - protected float getSoundPitch(){ - return (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 0.6F; - } +// @Override +// protected float getSoundPitch(){ +// return (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 0.6F; +// } @Override protected SoundEvent getAmbientSound(){ - return SoundEvents.ENTITY_WITCH_AMBIENT; + return WizardrySounds.ENTITY_EVIL_WIZARD_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource source){ - return SoundEvents.ENTITY_WITCH_HURT; + return WizardrySounds.ENTITY_EVIL_WIZARD_HURT; } @Override protected SoundEvent getDeathSound(){ - return SoundEvents.ENTITY_WITCH_DEATH; + return WizardrySounds.ENTITY_EVIL_WIZARD_DEATH; } // Although it *looks* like this is still called, in actual fact the only method that calls it is overridden in @@ -340,7 +336,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // the dropRareDrop method because that would be just as rare as normal mobs; instead this is half as rare. if(this.spells.size() > 0 && rand.nextInt(100) - lootingLevel < 5) this.entityDropItem(new ItemStack(WizardryItems.spell_book, 1, - this.spells.get(1 + rand.nextInt(this.spells.size() - 1)).id()), 0); + this.spells.get(1 + rand.nextInt(this.spells.size() - 1)).metadata()), 0); } @Override @@ -355,17 +351,19 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity textureIndex = this.rand.nextInt(6); - if(rand.nextBoolean()){ - this.setElement(Element.values()[rand.nextInt(Element.values().length - 1) + 1]); - }else{ - this.setElement(Element.MAGIC); + if(getElement() == null){ + if(rand.nextBoolean()){ + this.setElement(Element.values()[rand.nextInt(Element.values().length - 1) + 1]); + }else{ + this.setElement(Element.MAGIC); + } } Element element = this.getElement(); // Adds armour. for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ - this.setItemStackToSlot(slot, new ItemStack(WizardryUtilities.getArmour(element, slot))); + this.setItemStackToSlot(slot, new ItemStack(WizardryItems.getArmour(element, slot))); } // Default chance is 0.085f, for reference. @@ -375,12 +373,12 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // All wizards know magic missile, even if it is disabled. spells.add(Spells.magic_missile); - Tier maxTier = EntityWizard.populateSpells(spells, element, 3, rand); + Tier maxTier = EntityWizard.populateSpells(spells, element, hasStructure, 3, rand); // Now done after the spells so it can take the tier into account. For evil wizards this is slightly different; // it picks a random wand which is at least a high enough tier for the spells the wizard has. Tier tier = Tier.values()[maxTier.ordinal() + rand.nextInt(Tier.values().length - maxTier.ordinal())]; - this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(WizardryUtilities.getWand(tier, element))); + this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(WizardryItems.getWand(tier, element))); return data; } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityHuskMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityHuskMinion.java new file mode 100644 index 00000000..3a146734 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityHuskMinion.java @@ -0,0 +1,42 @@ +package electroblob.wizardry.entity.living; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class EntityHuskMinion extends EntityZombieMinion { + + /** Creates a new husk minion in the given world. */ + public EntityHuskMinion(World world){ + super(world); + } + + @Override + protected boolean shouldBurnInDay(){ + return false; + } + + @Override protected SoundEvent getAmbientSound(){ return SoundEvents.ENTITY_HUSK_AMBIENT; } + @Override protected SoundEvent getHurtSound(DamageSource damageSourceIn){ return SoundEvents.ENTITY_HUSK_HURT; } + @Override protected SoundEvent getDeathSound(){ return SoundEvents.ENTITY_HUSK_DEATH; } + @Override protected SoundEvent getStepSound(){ return SoundEvents.ENTITY_HUSK_STEP; } + + @Override + public boolean attackEntityAsMob(Entity target){ + + boolean flag = super.attackEntityAsMob(target); + + if(flag && this.getHeldItemMainhand().isEmpty() && target instanceof EntityLivingBase){ + float f = this.world.getDifficultyForLocation(new BlockPos(this)).getAdditionalDifficulty(); + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.HUNGER, 140 * (int)f)); + } + + return flag; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java index 8003f7f8..c3b118e7 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java @@ -1,8 +1,5 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.UUID; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; @@ -10,15 +7,9 @@ import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.ai.EntityAIAttackMelee; -import net.minecraft.entity.ai.EntityAIHurtByTarget; -import net.minecraft.entity.ai.EntityAILookIdle; -import net.minecraft.entity.ai.EntityAIMoveTowardsTarget; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; -import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.ai.*; import net.minecraft.entity.monster.EntityIronGolem; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; @@ -27,22 +18,22 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.village.Village; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import java.util.UUID; + public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature { // Field implementations - private int lifetime = 600; - private WeakReference casterReference; + private int lifetime = -1; private UUID casterUUID; // Setter + getter implementations @Override public int getLifetime(){ return lifetime; } @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } - @Override public WeakReference getCasterReference(){ return casterReference; } - @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } - @Override public UUID getCasterUUID(){ return casterUUID; } - @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } + @Override public UUID getOwnerId(){ return casterUUID; } + @Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } /** Creates a new ice giant in the given world. */ public EntityIceGiant(World world){ @@ -91,7 +82,7 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature @Override public void onDespawn(){ - this.playSound(WizardrySounds.SPELL_FREEZE, 1.0f, 1.0f); + this.playSound(WizardrySounds.ENTITY_ICE_GIANT_DESPAWN, 1.0f, 1.0f); this.spawnParticleEffect(); } @@ -126,7 +117,7 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature this.applyEnchantments(this, target); - this.playSound(SoundEvents.ENTITY_IRONGOLEM_ATTACK, 1.0F, 1.0F); + this.playSound(WizardrySounds.ENTITY_ICE_GIANT_ATTACK, 1.0F, 1.0F); } @Override @@ -160,8 +151,16 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } @Override public boolean canAttackClass(Class entityType){ @@ -182,7 +181,7 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + return Wizardry.settings.summonedCreatureNames && getCaster() != null; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java index 5d9fee8b..467fc3ad 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java @@ -1,16 +1,13 @@ package electroblob.wizardry.entity.living; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.ai.EntityAIBase; -import net.minecraft.entity.ai.EntityAILookIdle; -import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; -import net.minecraft.entity.ai.EntityAIWander; -import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.ai.*; import net.minecraft.entity.monster.EntityBlaze; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -66,7 +63,7 @@ public class EntityIceWraith extends EntityBlazeMinion { } if(this.rand.nextInt(24) == 0){ - this.playSound(WizardrySounds.SPELL_LOOP_WIND, 0.3F + this.rand.nextFloat() / 4, + this.playSound(WizardrySounds.ENTITY_ICE_WRAITH_AMBIENT, 0.3F + this.rand.nextFloat() / 4, this.rand.nextFloat() * 0.7F + 1.4F); } @@ -181,14 +178,24 @@ public class EntityIceWraith extends EntityBlazeMinion { @Override public boolean isBurning(){ // Uses the datawatcher on both sides because fire is private to Entity (and I'm not using reflection here). - // TESTME: This should work, but there may be some issues with updating, so if it doesn't work, copy the + // This should work, but there may be some issues with updating, so if it doesn't work, copy the // version from Entity and use reflection to access the fire field. return this.getFlag(0); } + @Override + public boolean getCanSpawnHere(){ + // Only spawns in the specified dimensions + for(int id : Wizardry.settings.mobSpawnDimensions){ + if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel(); + } + + return false; + } + /** * Copied straight from EntityBlaze.AIFireballAttack, with the only changes being replacement of fireball spawning - * with a one-liner call to WizardryRegistry.iceShard.cast(...) and the removal of redundant local variables. + * with a one-liner call to WizardryLoot.iceShard.cast(...) and the removal of redundant local variables. */ static class AIIceShardAttack extends EntityAIBase { @@ -222,6 +229,7 @@ public class EntityIceWraith extends EntityBlazeMinion { public void updateTask(){ --this.attackTime; EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); + if(entitylivingbase == null) return; // Dynamic stealth breaks things, let's un-break them double d0 = this.blaze.getDistanceSq(entitylivingbase); if(d0 < 4.0D){ @@ -251,7 +259,6 @@ public class EntityIceWraith extends EntityBlazeMinion { // Proof, if it were at all needed, of the elegance and versatility of the spell system. Spells.ice_shard.cast(this.blaze.world, this.blaze, EnumHand.MAIN_HAND, 0, entitylivingbase, new SpellModifiers()); - // TODO: Decide if an event should be fired here. I'm guessing no. } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java index a97c52af..d396735f 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java @@ -1,15 +1,12 @@ package electroblob.wizardry.entity.living; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.ai.EntityAIBase; -import net.minecraft.entity.ai.EntityAILookIdle; -import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; -import net.minecraft.entity.ai.EntityAIWander; -import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.ai.*; import net.minecraft.entity.monster.EntityBlaze; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; @@ -75,9 +72,21 @@ public class EntityLightningWraith extends EntityBlazeMinion { return this.getFlag(0); } + @Override + public boolean getCanSpawnHere(){ + // Only spawns in the specified dimensions, during thunderstorms + if(!world.isThundering()) return false; + + for(int id : Wizardry.settings.mobSpawnDimensions){ + if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel(); + } + + return false; + } + /** * Copied straight from EntityBlaze.AIFireballAttack, with the only changes being replacement of fireball spawning - * with a one-liner call to WizardryRegistry.arc.cast(...) and the removal of redundant local variables. + * with a one-liner call to WizardryLoot.arc.cast(...) and the removal of redundant local variables. */ static class AILightningAttack extends EntityAIBase { @@ -111,6 +120,7 @@ public class EntityLightningWraith extends EntityBlazeMinion { public void updateTask(){ --this.attackTime; EntityLivingBase entitylivingbase = this.blaze.getAttackTarget(); + if(entitylivingbase == null) return; // Dynamic stealth breaks things, let's un-break them double d0 = this.blaze.getDistanceSq(entitylivingbase); if(d0 < 4.0D){ @@ -139,7 +149,6 @@ public class EntityLightningWraith extends EntityBlazeMinion { if(this.attackStep > 1){ // Proof, if it were at all needed, of the elegance and versatility of the spell system. Spells.arc.cast(this.blaze.world, this.blaze, EnumHand.MAIN_HAND, 0, entitylivingbase, new SpellModifiers()); - // TODO: Decide if an event should be fired here. I'm guessing no. } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java b/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java index 1c9da3ce..183fb155 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityMagicSlime.java @@ -1,16 +1,11 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.UUID; - -import javax.annotation.Nullable; - +import electroblob.wizardry.registry.WizardrySounds; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; import net.minecraft.entity.monster.EntitySlime; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; @@ -22,21 +17,21 @@ import net.minecraft.world.DifficultyInstance; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import javax.annotation.Nullable; +import java.util.UUID; + /** As of Wizardry 1.2, this is now an ISummonedCreature like the rest of them, and it extends EntitySlime. */ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { // Field implementations private int lifetime = 200; - private WeakReference casterReference; private UUID casterUUID; // Setter + getter implementations @Override public int getLifetime(){ return lifetime; } @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } - @Override public WeakReference getCasterReference(){ return casterReference; } - @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } - @Override public UUID getCasterUUID(){ return casterUUID; } - @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } + @Override public UUID getOwnerId(){ return casterUUID; } + @Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } public EntityMagicSlime(World world){ super(world); @@ -57,7 +52,7 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { super(world); this.setPosition(target.posX, target.posY, target.posZ); this.startRiding(target); - this.casterReference = new WeakReference(caster); + this.setOwnerId(caster.getUniqueID()); this.setSlimeSize(2, false); // Needs to be called before setting the experience value to 0 this.experienceValue = 0; this.lifetime = lifetime; @@ -83,8 +78,8 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { this.world.spawnParticle(EnumParticleTypes.SLIME, x, y, z, (x - this.posX) * 2, (y - this.posY) * 2, (z - this.posZ) * 2); } - this.playSound(SoundEvents.ENTITY_SLIME_ATTACK, 2.5f, 0.6f); - this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST_FAR, 1.0f, 0.5f); + this.playSound(WizardrySounds.ENTITY_MAGIC_SLIME_SPLAT, 2.5f, 0.6f); + this.playSound(WizardrySounds.ENTITY_MAGIC_SLIME_EXPLODE, 1.0f, 0.5f); } @Override @@ -127,7 +122,7 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { this.getRidingEntity().attackEntityFrom(DamageSource.MAGIC, 1); ((EntityLivingBase)this.getRidingEntity()) .addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 20, 2)); - this.playSound(SoundEvents.ENTITY_SLIME_ATTACK, 1.0f, 1.0f); + this.playSound(WizardrySounds.ENTITY_MAGIC_SLIME_ATTACK, 1.0f, 1.0f); this.squishAmount = 0.5F; } }else{ @@ -174,7 +169,10 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature { @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java index 73170416..e04428b0 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityPhoenix.java @@ -1,9 +1,7 @@ package electroblob.wizardry.entity.living; -import java.util.Collections; -import java.util.List; - import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; @@ -13,7 +11,6 @@ import net.minecraft.entity.ai.EntityAIHurtByTarget; import net.minecraft.entity.ai.EntityAILookIdle; import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAIWatchClosest; -import net.minecraft.init.SoundEvents; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.SoundEvent; @@ -22,6 +19,9 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.Collections; +import java.util.List; + public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaster { private double AISpeed = 0.5; @@ -97,17 +97,17 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste @Override protected SoundEvent getAmbientSound(){ - return SoundEvents.ENTITY_BLAZE_AMBIENT; + return WizardrySounds.ENTITY_PHOENIX_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource source){ - return SoundEvents.ENTITY_BLAZE_HURT; + return WizardrySounds.ENTITY_PHOENIX_HURT; } @Override protected SoundEvent getDeathSound(){ - return SoundEvents.ENTITY_BLAZE_DEATH; + return WizardrySounds.ENTITY_PHOENIX_DEATH; } @Override @@ -144,9 +144,9 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste public void onLivingUpdate(){ // Makes the phoenix hover. - int floorLevel = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(this), 4); + Integer floorLevel = WizardryUtilities.getNearestFloor(world, new BlockPos(this), 4); - if(this.posY - floorLevel > 3){ + if(floorLevel == null || this.posY - floorLevel > 3){ this.motionY = -0.1; }else if(this.posY - floorLevel < 2){ this.motionY = 0.1; @@ -156,13 +156,13 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste // Living sound if(this.rand.nextInt(24) == 0){ - this.playSound(SoundEvents.BLOCK_FIRE_AMBIENT, 1.0F + this.rand.nextFloat(), + this.playSound(WizardrySounds.ENTITY_PHOENIX_BURN, 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F); } // Flapping sound effect if(this.ticksExisted % 22 == 0){ - this.playSound(SoundEvents.ENTITY_ENDERDRAGON_FLAP, 1.0F, 1.0f); + this.playSound(WizardrySounds.ENTITY_PHOENIX_FLAP, 1.0F, 1.0f); } for(int i = 0; i < 2; i++){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java index d09a3326..55963b90 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java @@ -1,22 +1,15 @@ package electroblob.wizardry.entity.living; -import java.util.Collections; -import java.util.List; - import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.entity.ai.EntityAIAttackMelee; -import net.minecraft.entity.ai.EntityAIHurtByTarget; -import net.minecraft.entity.ai.EntityAILookIdle; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; -import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.ai.*; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; @@ -25,6 +18,9 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.Collections; +import java.util.List; + public class EntityShadowWraith extends EntitySummonedCreature implements ISpellCaster { // TODO: This currently doesn't fly like it used to. Should it, or does it not matter? @@ -96,17 +92,17 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell @Override protected SoundEvent getAmbientSound(){ - return SoundEvents.ENTITY_BLAZE_AMBIENT; + return WizardrySounds.ENTITY_SHADOW_WRAITH_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource source){ - return SoundEvents.ENTITY_BLAZE_HURT; + return WizardrySounds.ENTITY_SHADOW_WRAITH_HURT; } @Override protected SoundEvent getDeathSound(){ - return SoundEvents.ENTITY_BLAZE_DEATH; + return WizardrySounds.ENTITY_SHADOW_WRAITH_DEATH; } @Override @@ -135,7 +131,7 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell public void onLivingUpdate(){ if(this.rand.nextInt(24) == 0){ - this.playSound(SoundEvents.BLOCK_PORTAL_AMBIENT, 1.0F + this.rand.nextFloat(), + this.playSound(WizardrySounds.ENTITY_SHADOW_WRAITH_NOISE, 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F); } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java index e0275389..d7d92d76 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java @@ -1,8 +1,5 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.UUID; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; @@ -20,22 +17,26 @@ import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import java.util.UUID; + public class EntitySilverfishMinion extends EntitySilverfish implements ISummonedCreature { + public static final int MAX_GENERATIONS = 5; + // Field implementations - private int lifetime = 600; - private WeakReference casterReference; + private int lifetime = -1; private UUID casterUUID; + private int generation = 1; + // Setter + getter implementations @Override public int getLifetime(){ return lifetime; } @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } - @Override public WeakReference getCasterReference(){ return casterReference; } - @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } - @Override public UUID getCasterUUID(){ return casterUUID; } - @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } + @Override public UUID getOwnerId(){ return casterUUID; } + @Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } /** Creates a new silverfish minion in the given world. */ public EntitySilverfishMinion(World world){ @@ -50,7 +51,7 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone this.tasks.addTask(1, new EntityAISwimming(this)); this.tasks.addTask(4, new EntityAIAttackMelee(this, 1.0D, false)); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, 0, false, true, this.getTargetSelector())); } @@ -99,7 +100,7 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone public void onKillEntity(EntityLivingBase victim){ // If the silverfish has a summoner, this is actually called from Wizardry's event handler rather than by // Minecraft itself, because the damagesource being changed causes it not to get called. - if(!this.world.isRemote){ + if(!this.world.isRemote && generation < MAX_GENERATIONS){ // Summons 1-4 more silverfish int alliesToSummon = rand.nextInt(4) + 1; @@ -108,6 +109,7 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone silverfish.setPosition(victim.posX, victim.posY, victim.posZ); silverfish.setCaster(this.getCaster()); silverfish.setLifetime(this.getLifetime()); + silverfish.generation = this.generation + 1; this.world.spawnEntity(silverfish); } } @@ -129,12 +131,14 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone public void writeEntityToNBT(NBTTagCompound nbttagcompound){ super.writeEntityToNBT(nbttagcompound); this.writeNBTDelegate(nbttagcompound); + nbttagcompound.setInteger("generation", this.generation); } @Override public void readEntityFromNBT(NBTTagCompound nbttagcompound){ super.readEntityFromNBT(nbttagcompound); this.readNBTDelegate(nbttagcompound); + this.generation = nbttagcompound.getInteger("generation"); } // Recommended overrides @@ -144,8 +148,16 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } @Override public boolean canAttackClass(Class entityType){ @@ -166,6 +178,6 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + return Wizardry.settings.summonedCreatureNames && getCaster() != null; } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java index c1801d76..2d10fd34 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySkeletonMinion.java @@ -1,12 +1,7 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.Calendar; -import java.util.UUID; - -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryUtilities.Operations; import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; @@ -14,37 +9,39 @@ import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIHurtByTarget; import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.attributes.AttributeModifier; -import net.minecraft.entity.monster.EntitySkeleton; +import net.minecraft.entity.monster.AbstractSkeleton; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.Items; +import net.minecraft.init.SoundEvents; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.Item; import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumHand; -import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.ResourceLocation; +import net.minecraft.util.*; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; -public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCreature { +import javax.annotation.Nullable; +import java.util.Calendar; +import java.util.UUID; + +// Extends AbstractSkeleton because EntitySkeleton drops skulls, which we don't want +public class EntitySkeletonMinion extends AbstractSkeleton implements ISummonedCreature { // Field implementations - private int lifetime = 600; - private WeakReference casterReference; + private int lifetime = -1; private UUID casterUUID; // Setter + getter implementations @Override public int getLifetime(){ return lifetime; } @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } - @Override public WeakReference getCasterReference(){ return casterReference; } - @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } - @Override public UUID getCasterUUID(){ return casterUUID; } - @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } + @Override public UUID getOwnerId(){ return casterUUID; } + @Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } /** Creates a new skeleton minion in the given world. */ public EntitySkeletonMinion(World world){ @@ -55,13 +52,13 @@ public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCre // EntitySkeleton overrides // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its - // targeting system with one that targets hostile mobs and takes the ADS into account. + // targeting system with one that targets hostile mobs and takes the AllyDesignationSystem into account. @Override protected void initEntityAI(){ super.initEntityAI(); this.targetTasks.taskEntries.clear(); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, 0, false, true, this.getTargetSelector())); } @@ -76,7 +73,7 @@ public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCre public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata){ // Can't call super, so the code from the next level up (EntityLiving) had to be copied as well. this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE) - .applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, 1)); + .applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, Operations.MULTIPLY_FLAT)); if(this.rand.nextFloat() < 0.05F){ this.setLeftHanded(true); @@ -98,6 +95,12 @@ public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCre return livingdata; } + // Since we're extending AbstractSkeleton these aren't set by the superclass like normal + @Override protected SoundEvent getAmbientSound(){ return SoundEvents.ENTITY_SKELETON_AMBIENT; } + @Override protected SoundEvent getHurtSound(DamageSource source){ return SoundEvents.ENTITY_SKELETON_HURT; } + @Override protected SoundEvent getDeathSound(){ return SoundEvents.ENTITY_SKELETON_DEATH; } + @Override protected SoundEvent getStepSound(){ return SoundEvents.ENTITY_SKELETON_STEP; } + // Implementations @Override @@ -161,8 +164,16 @@ public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCre @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } @Override public boolean canAttackClass(Class entityType){ @@ -183,6 +194,6 @@ public class EntitySkeletonMinion extends EntitySkeleton implements ISummonedCre @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + return Wizardry.settings.summonedCreatureNames && getCaster() != null; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java index 328e988c..b4efebc2 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java @@ -1,11 +1,9 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.UUID; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.WizardryUtilities.Operations; import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; @@ -27,20 +25,19 @@ import net.minecraft.world.DifficultyInstance; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import java.util.UUID; + public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCreature { // Field implementations - private int lifetime = 600; - private WeakReference casterReference; + private int lifetime = -1; private UUID casterUUID; // Setter + getter implementations @Override public int getLifetime(){ return lifetime; } @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } - @Override public WeakReference getCasterReference(){ return casterReference; } - @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } - @Override public UUID getCasterUUID(){ return casterUUID; } - @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } + @Override public UUID getOwnerId(){ return casterUUID; } + @Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } /** Creates a new spider minion in the given world. */ public EntitySpiderMinion(World world){ @@ -51,7 +48,7 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre // EntitySpider overrides // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its - // targeting system with one that targets hostile mobs and takes the ADS into account. + // targeting system with one that targets hostile mobs and takes the AllyDesignationSystem into account. @Override protected void initEntityAI(){ super.initEntityAI(); @@ -70,7 +67,7 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre // Can't call super, so the code from the next level up (EntityLiving) had to be copied as well. this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE) - .applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, 1)); + .applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, Operations.MULTIPLY_FLAT)); if(this.rand.nextFloat() < 0.05F){ this.setLeftHanded(true); @@ -163,8 +160,16 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } @Override public boolean canAttackClass(Class entityType){ @@ -185,6 +190,6 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + return Wizardry.settings.summonedCreatureNames && getCaster() != null; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java index 67284bde..98deb764 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java @@ -1,8 +1,7 @@ package electroblob.wizardry.entity.living; -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; @@ -16,7 +15,6 @@ import net.minecraft.entity.passive.EntityHorse; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; @@ -34,6 +32,10 @@ public class EntitySpiritHorse extends EntityHorse { private int idleTimer = 0; + private int dispelTimer = 0; + + private static final int DISPEL_TIME = 10; + public EntitySpiritHorse(World par1World){ super(par1World); } @@ -93,19 +95,13 @@ public class EntitySpiritHorse extends EntityHorse { // Allows the owner (but not other players) to dispel the spirit horse using a wand (shift-clicking, because // clicking mounts the horse in this case). - if(itemstack.getItem() instanceof ItemWand && this.getOwner() == player && player.isSneaking()){ + if(itemstack.getItem() instanceof ISpellCastingItem && this.getOwner() == player && player.isSneaking()){ // Prevents accidental double clicking. if(this.ticksExisted > 20){ + + this.dispelTimer++; - this.spawnAppearParticles(); - - this.setDead(); - - if(WizardData.get(player) != null){ - WizardData.get(player).hasSpiritHorse = false; - } - - this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + this.playSound(WizardrySounds.ENTITY_SPIRIT_HORSE_VANISH, 0.7F, rand.nextFloat() * 0.4F + 1.0F); // This is necessary to prevent the wand's spell being cast when performing this action. return true; } @@ -124,17 +120,6 @@ public class EntitySpiritHorse extends EntityHorse { } } - @Override - public void onDeath(DamageSource par1DamageSource){ - - super.onDeath(par1DamageSource); - - // Allows player to summon another spirit horse once this one has died. - if(this.getOwner() instanceof EntityPlayer && WizardData.get((EntityPlayer)this.getOwner()) != null){ - WizardData.get((EntityPlayer)this.getOwner()).hasSpiritHorse = false; - } - } - // I wrote this one! private EntityLivingBase getOwner(){ @@ -148,11 +133,21 @@ public class EntitySpiritHorse extends EntityHorse { } } + public float getOpacity(){ + return 1 - (float)dispelTimer/DISPEL_TIME; + } + @Override public void onUpdate(){ super.onUpdate(); + if(dispelTimer > 0){ + if(dispelTimer++ > DISPEL_TIME){ + this.setDead(); + } + } + // Adds a dust particle effect if(this.world.isRemote){ double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; @@ -170,17 +165,9 @@ public class EntitySpiritHorse extends EntityHorse { if(this.idleTimer > 200){ - if(this.world.isRemote){ - this.spawnAppearParticles(); - } + this.playSound(WizardrySounds.ENTITY_SPIRIT_HORSE_VANISH, 0.7F, rand.nextFloat() * 0.4F + 1.0F); - this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); - // Allows player to summon another spirit horse once this one has disappeared. - if(this.getOwner() instanceof EntityPlayer && WizardData.get((EntityPlayer)this.getOwner()) != null){ - WizardData.get((EntityPlayer)this.getOwner()).hasSpiritHorse = false; - } - - this.setDead(); + this.dispelTimer++; } } @@ -213,7 +200,7 @@ public class EntitySpiritHorse extends EntityHorse { @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getOwner() != null; + return Wizardry.settings.summonedCreatureNames && getOwner() != null; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java index f18601f9..3c8929b5 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java @@ -1,29 +1,17 @@ package electroblob.wizardry.entity.living; -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.IEntityLivingData; -import net.minecraft.entity.ai.EntityAIAttackMelee; -import net.minecraft.entity.ai.EntityAIFollowOwner; -import net.minecraft.entity.ai.EntityAIHurtByTarget; -import net.minecraft.entity.ai.EntityAILeapAtTarget; -import net.minecraft.entity.ai.EntityAILookIdle; -import net.minecraft.entity.ai.EntityAIOwnerHurtByTarget; -import net.minecraft.entity.ai.EntityAIOwnerHurtTarget; -import net.minecraft.entity.ai.EntityAISit; -import net.minecraft.entity.ai.EntityAISwimming; -import net.minecraft.entity.ai.EntityAIWander; -import net.minecraft.entity.ai.EntityAIWatchClosest; +import net.minecraft.entity.ai.*; import net.minecraft.entity.passive.EntityWolf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; @@ -37,9 +25,12 @@ import net.minecraft.world.World; */ public class EntitySpiritWolf extends EntityWolf { - public EntitySpiritWolf(World par1World){ + private int dispelTimer = 0; - super(par1World); + private static final int DISPEL_TIME = 10; + + public EntitySpiritWolf(World world){ + super(world); this.experienceValue = 0; } @@ -60,18 +51,6 @@ public class EntitySpiritWolf extends EntityWolf { this.targetTasks.addTask(3, new EntityAIHurtByTarget(this, true, new Class[0])); } - @Override - public void onDeath(DamageSource source){ - - // Allows player to summon another spirit wolf once this one has died. - // NOTE: This has been known to work incorrectly. - if(this.getOwner() instanceof EntityPlayer && WizardData.get((EntityPlayer)this.getOwner()) != null){ - WizardData.get((EntityPlayer)this.getOwner()).hasSpiritWolf = false; - } - - super.onDeath(source); - } - @Override public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData livingdata){ @@ -92,12 +71,22 @@ public class EntitySpiritWolf extends EntityWolf { ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).clr(0.8f, 0.8f, 1.0f).spawn(world); } } + + public float getOpacity(){ + return 1 - (float)dispelTimer/DISPEL_TIME; + } @Override public void onUpdate(){ super.onUpdate(); + if(dispelTimer > 0){ + if(dispelTimer++ > DISPEL_TIME){ + this.setDead(); + } + } + // Adds a dust particle effect if(this.world.isRemote){ double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; @@ -116,21 +105,13 @@ public class EntitySpiritWolf extends EntityWolf { // Allows the owner (but not other players) to dispel the spirit wolf using a // wand. - if(stack.getItem() instanceof ItemWand && this.getOwner() == player && player.isSneaking()){ + if(stack.getItem() instanceof ISpellCastingItem && this.getOwner() == player && player.isSneaking()){ // Prevents accidental double clicking. if(this.ticksExisted > 20){ - if(this.world.isRemote){ - this.spawnAppearParticles(); - } + this.dispelTimer++; - this.setDead(); - - if(WizardData.get(player) != null){ - WizardData.get(player).hasSpiritWolf = false; - } - - this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + this.playSound(WizardrySounds.ENTITY_SPIRIT_WOLF_VANISH, 0.7F, rand.nextFloat() * 0.4F + 1.0F); // This is necessary to prevent the wand's spell being cast when performing this // action. return true; @@ -181,7 +162,7 @@ public class EntitySpiritWolf extends EntityWolf { public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking // directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getOwner() != null; + return Wizardry.settings.summonedCreatureNames && getOwner() != null; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java index 29776335..ce87a216 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java @@ -1,23 +1,15 @@ package electroblob.wizardry.entity.living; -import java.util.Collections; -import java.util.List; - import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.entity.ai.EntityAIAttackMelee; -import net.minecraft.entity.ai.EntityAIHurtByTarget; -import net.minecraft.entity.ai.EntityAILookIdle; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; -import net.minecraft.entity.ai.EntityAIWander; +import net.minecraft.entity.ai.*; import net.minecraft.entity.effect.EntityLightningBolt; -import net.minecraft.init.SoundEvents; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.SoundEvent; @@ -25,6 +17,9 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.Collections; +import java.util.List; + public class EntityStormElemental extends EntitySummonedCreature implements ISpellCaster { private double AISpeed = 1.0; @@ -90,17 +85,17 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe @Override protected SoundEvent getAmbientSound(){ - return SoundEvents.ENTITY_BLAZE_AMBIENT; + return WizardrySounds.ENTITY_STORM_ELEMENTAL_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource source){ - return SoundEvents.ENTITY_BLAZE_HURT; + return WizardrySounds.ENTITY_STORM_ELEMENTAL_HURT; } @Override protected SoundEvent getDeathSound(){ - return SoundEvents.ENTITY_BLAZE_DEATH; + return WizardrySounds.ENTITY_STORM_ELEMENTAL_DEATH; } @Override @@ -118,11 +113,11 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe public void onLivingUpdate(){ if(this.ticksExisted % 120 == 1){ - this.playSound(WizardrySounds.SPELL_LOOP_WIND, 1.0f, 1.0f); + this.playSound(WizardrySounds.ENTITY_STORM_ELEMENTAL_WIND, 1.0f, 1.0f); } if(this.rand.nextInt(24) == 0){ - this.playSound(SoundEvents.ENTITY_BLAZE_BURN, 1.0F + this.rand.nextFloat(), + this.playSound(WizardrySounds.ENTITY_STORM_ELEMENTAL_BURN, 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F); } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityStrayMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityStrayMinion.java new file mode 100644 index 00000000..6edcc700 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityStrayMinion.java @@ -0,0 +1,35 @@ +package electroblob.wizardry.entity.living; + +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.entity.projectile.EntityTippedArrow; +import net.minecraft.init.MobEffects; +import net.minecraft.init.SoundEvents; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.util.SoundEvent; +import net.minecraft.world.World; + +public class EntityStrayMinion extends EntitySkeletonMinion { + + /** Creates a new stray minion in the given world. */ + public EntityStrayMinion(World world){ + super(world); + } + + @Override protected SoundEvent getAmbientSound(){ return SoundEvents.ENTITY_STRAY_AMBIENT; } + @Override protected SoundEvent getHurtSound(DamageSource source){ return SoundEvents.ENTITY_STRAY_HURT; } + @Override protected SoundEvent getDeathSound(){ return SoundEvents.ENTITY_STRAY_DEATH; } + @Override protected SoundEvent getStepSound(){ return SoundEvents.ENTITY_STRAY_STEP; } + + @Override + protected EntityArrow getArrow(float distanceFactor){ + + EntityArrow entityarrow = super.getArrow(distanceFactor); + + if(entityarrow instanceof EntityTippedArrow){ + ((EntityTippedArrow)entityarrow).addEffect(new PotionEffect(MobEffects.SLOWNESS, 600)); + } + + return entityarrow; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java index 2ef50929..12d623e7 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySummonedCreature.java @@ -1,8 +1,5 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.UUID; - import electroblob.wizardry.Wizardry; import net.minecraft.entity.EntityCreature; import net.minecraft.entity.EntityFlying; @@ -14,8 +11,11 @@ import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import java.util.UUID; + /** * Abstract base implementation of {@link ISummonedCreature} which is the superclass to all custom summoned entities * (i.e. entities that don't extend vanilla/mod creatures). Also serves as an example of how to correctly implement the @@ -29,8 +29,7 @@ import net.minecraft.world.World; public abstract class EntitySummonedCreature extends EntityCreature implements ISummonedCreature { // Field implementations - private int lifetime = 600; - private WeakReference casterReference; + private int lifetime = -1; private UUID casterUUID; // Setter + getter implementations @@ -45,22 +44,12 @@ public abstract class EntitySummonedCreature extends EntityCreature implements I } @Override - public WeakReference getCasterReference(){ - return casterReference; - } - - @Override - public void setCasterReference(WeakReference reference){ - casterReference = reference; - } - - @Override - public UUID getCasterUUID(){ + public UUID getOwnerId(){ return casterUUID; } @Override - public void setCasterUUID(UUID uuid){ + public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } @@ -122,8 +111,16 @@ public abstract class EntitySummonedCreature extends EntityCreature implements I @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } @Override public boolean canAttackClass(Class entityType){ @@ -144,7 +141,7 @@ public abstract class EntitySummonedCreature extends EntityCreature implements I @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + return Wizardry.settings.summonedCreatureNames && getCaster() != null; } // Specific to EntitySummonedCreature, remove if copying diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityVexMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityVexMinion.java new file mode 100644 index 00000000..73ed60ba --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/living/EntityVexMinion.java @@ -0,0 +1,151 @@ +package electroblob.wizardry.entity.living; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIHurtByTarget; +import net.minecraft.entity.ai.EntityAINearestAttackableTarget; +import net.minecraft.entity.monster.EntityVex; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.EnumDifficulty; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.UUID; + +public class EntityVexMinion extends EntityVex implements ISummonedCreature { + + // Field implementations + private int lifetime = -1; + private UUID casterUUID; + + // Setter + getter implementations + @Override public int getLifetime(){ return lifetime; } + @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } + @Override public UUID getOwnerId(){ return casterUUID; } + @Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } + + /** Creates a new vex minion in the given world. */ + public EntityVexMinion(World world){ + super(world); + this.experienceValue = 0; + } + + // ISummonedCreature overrides + @Override + public void setCaster(@Nullable EntityLivingBase caster){ + // Integrates the summoned creature caster system with the (subtly different) vex owner system for NPC casters + ISummonedCreature.super.setCaster(caster); + if(caster instanceof EntityLiving) this.setOwner((EntityLiving)caster); + } + + // EntityVex overrides + @Override + protected void initEntityAI(){ + super.initEntityAI(); + this.targetTasks.taskEntries.clear(); + this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, + 0, false, false, this.getTargetSelector())); + } + + // Implementations + + @Override + public void setRevengeTarget(EntityLivingBase entity){ + if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity); + } + + @Override + public void onUpdate(){ + super.onUpdate(); + this.updateDelegate(); + } + + @Override + public void onSpawn(){ + this.spawnParticleEffect(); + } + + @Override + public void onDespawn(){ + this.spawnParticleEffect(); + } + + private void spawnParticleEffect(){ + if(this.world.isRemote){ + for(int i = 0; i < 15; i++){ + ParticleBuilder.create(Type.DARK_MAGIC) + .pos(this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat()) + .clr(0.3f, 0.3f, 0.3f) + .spawn(world); + } + } + } + + @Override + public boolean hasParticleEffect(){ + return true; + } + + @Override + protected boolean processInteract(EntityPlayer player, EnumHand hand){ + // In this case, the delegate method determines whether super is called. + // Rather handily, we can make use of Java's short-circuiting method of evaluating OR statements. + return this.interactDelegate(player, hand) || super.processInteract(player, hand); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + this.writeNBTDelegate(nbttagcompound); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + this.readNBTDelegate(nbttagcompound); + } + + // Recommended overrides + + @Override protected int getExperiencePoints(EntityPlayer player){ return 0; } + @Override protected boolean canDropLoot(){ return false; } + @Override protected Item getDropItem(){ return null; } + @Override protected ResourceLocation getLootTable(){ return null; } + @Override public boolean canPickUpLoot(){ return false; } + + // This vanilla method has nothing to do with the custom despawn() method. + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } + + @Override + public ITextComponent getDisplayName(){ + if(getCaster() != null){ + return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(), + new TextComponentTranslation("entity." + this.getEntityString() + ".name")); + }else{ + return super.getDisplayName(); + } + } + + @Override + public boolean hasCustomName(){ + // If this returns true, the renderer will show the nameplate when looking directly at the entity + return Wizardry.settings.summonedCreatureNames && getCaster() != null; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWitherSkeletonMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityWitherSkeletonMinion.java index 8606978b..4ec2238a 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWitherSkeletonMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWitherSkeletonMinion.java @@ -1,12 +1,7 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.Calendar; -import java.util.UUID; - -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.WizardryUtilities.Operations; import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; @@ -31,22 +26,24 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import javax.annotation.Nullable; +import java.util.Calendar; +import java.util.UUID; + public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements ISummonedCreature { // Field implementations - private int lifetime = 600; - private WeakReference casterReference; + private int lifetime = -1; private UUID casterUUID; // Setter + getter implementations @Override public int getLifetime(){ return lifetime; } @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } - @Override public WeakReference getCasterReference(){ return casterReference; } - @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } - @Override public UUID getCasterUUID(){ return casterUUID; } - @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } + @Override public UUID getOwnerId(){ return casterUUID; } + @Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } /** Creates a new wither skeleton minion in the given world. */ public EntityWitherSkeletonMinion(World world){ @@ -57,7 +54,7 @@ public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements // EntitySkeleton overrides // This particular override is pretty standard: let the superclass handle basic AI like swimming, but replace its - // targeting system with one that targets hostile mobs and takes the ADS into account. + // targeting system with one that targets hostile mobs and takes the AllyDesignationSystem into account. @Override protected void initEntityAI(){ super.initEntityAI(); @@ -78,7 +75,7 @@ public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata){ // Can't call super, so the code from the next level up (EntityLiving) had to be copied as well. this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE) - .applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, 1)); + .applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, Operations.MULTIPLY_FLAT)); if(this.rand.nextFloat() < 0.05F){ this.setLeftHanded(true); @@ -171,8 +168,16 @@ public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } @Override public boolean canAttackClass(Class entityType){ @@ -193,6 +198,6 @@ public class EntityWitherSkeletonMinion extends EntityWitherSkeleton implements @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + return Wizardry.settings.summonedCreatureNames && getCaster() != null; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 7115fcd9..2d5ac7b0 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -1,70 +1,37 @@ package electroblob.wizardry.entity.living; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; - -import javax.annotation.Nullable; - import com.google.common.base.Predicate; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.event.DiscoverSpellEvent; +import electroblob.wizardry.item.ItemArtefact; import electroblob.wizardry.item.ItemSpellBook; -import electroblob.wizardry.registry.Spells; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.misc.WildcardTradeList; +import electroblob.wizardry.registry.*; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WildcardTradeList; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.*; import io.netty.buffer.ByteBuf; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityCreature; -import net.minecraft.entity.EntityList; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.IEntityLivingData; -import net.minecraft.entity.IMerchant; -import net.minecraft.entity.INpc; -import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.entity.ai.EntityAIBase; -import net.minecraft.entity.ai.EntityAIHurtByTarget; -import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction; -import net.minecraft.entity.ai.EntityAINearestAttackableTarget; -import net.minecraft.entity.ai.EntityAIOpenDoor; -import net.minecraft.entity.ai.EntityAIRestrictOpenDoor; -import net.minecraft.entity.ai.EntityAISwimming; -import net.minecraft.entity.ai.EntityAIWander; -import net.minecraft.entity.ai.EntityAIWatchClosest; -import net.minecraft.entity.ai.EntityAIWatchClosest2; +import net.minecraft.entity.*; +import net.minecraft.entity.ai.*; import net.minecraft.entity.monster.IMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagInt; -import net.minecraft.nbt.NBTTagLong; +import net.minecraft.nbt.*; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; @@ -73,6 +40,7 @@ import net.minecraft.village.MerchantRecipeList; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.event.world.BlockEvent; @@ -83,6 +51,9 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.oredict.OreDictionary; +import javax.annotation.Nullable; +import java.util.*; + @Mod.EventBusSubscriber public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISpellCaster, IEntityAdditionalSpawnData { @@ -150,7 +121,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // If the target is valid and not invisible... if(entity != null && !entity.isInvisible() - && WizardryUtilities.isValidTarget(EntityWizard.this, entity)){ + && AllyDesignationSystem.isValidTarget(EntityWizard.this, entity)){ // ... and is a mob, a summoned creature ... if((entity instanceof IMob || entity instanceof ISummonedCreature @@ -247,7 +218,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Copied from EntityVillager if(!this.world.isRemote && this.livingSoundTime > -this.getTalkInterval() + 20){ this.livingSoundTime = -this.getTalkInterval(); - this.playSound(stack.isEmpty() ? SoundEvents.ENTITY_VILLAGER_NO : SoundEvents.ENTITY_VILLAGER_YES, this.getSoundVolume(), this.getSoundPitch()); + this.playSound(stack.isEmpty() ? WizardrySounds.ENTITY_WIZARD_NO : WizardrySounds.ENTITY_WIZARD_YES, this.getSoundVolume(), this.getSoundPitch()); } } @@ -267,8 +238,14 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Apparently nothing goes here, and nothing's here in EntityVillager either... } + // TESTME: Should this be getName instead? @Override public ITextComponent getDisplayName(){ + + if(this.hasCustomName()){ + return super.getDisplayName(); + } + return this.getElement().getWizardName(); } @@ -276,6 +253,21 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp protected boolean canDespawn(){ return false; } + + @Override + protected SoundEvent getAmbientSound(){ + return this.isTrading() ? WizardrySounds.ENTITY_WIZARD_TRADING : WizardrySounds.ENTITY_WIZARD_AMBIENT; + } + + @Override + protected SoundEvent getHurtSound(DamageSource source){ + return WizardrySounds.ENTITY_WIZARD_HURT; + } + + @Override + protected SoundEvent getDeathSound(){ + return WizardrySounds.ENTITY_WIZARD_DEATH; + } @Override public void onLivingUpdate(){ @@ -301,14 +293,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Heal particles TODO: Change this so it uses the heal spell directly if(world.isRemote){ - for(int i=0; i<10; i++){ - double x = (double)((float)this.posX + rand.nextFloat() * 2 - 1.0F); - // Apparently the client side spawns the particles 1 block higher than it should... hence the - - // 0.5F. - double y = (double)((float)this.posY - 0.5F + rand.nextFloat()); - double z = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1F, 0).clr(1, 1, 0.3f).spawn(world); - } + ParticleBuilder.spawnHealParticles(world, this); }else{ if(this.getHealth() < 10){ // Wizards heal themseselves more often if they have low health @@ -317,7 +302,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp this.setHealCooldown(400); } - this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F); + this.playSound(Spells.heal.getSounds()[0], 0.7F, rand.nextFloat() * 0.4F + 1.0F); } } @@ -370,8 +355,8 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Spell.get(spells[3]).getDisplayName())); // When right-clicked with a spell book in creative, sets one of the spells to that spell - if(player.capabilities.isCreativeMode && stack.getItem() instanceof ItemSpellBook){ - Spell spell = Spell.get(stack.getItemDamage()); + if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){ + Spell spell = Spell.byMetadata(stack.getItemDamage()); if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){ // The set(...) method returns the element that was replaced - neat! player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard", @@ -407,11 +392,10 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp nbt.setInteger("element", this.getElement().ordinal()); nbt.setInteger("skin", this.textureIndex); - nbt.setTag("spells", WizardryUtilities.listToNBT(spells, spell -> new NBTTagInt(spell.id()))); + nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata()))); if(this.towerBlocks != null && this.towerBlocks.size() > 0){ - nbt.setTag("towerBlocks", - WizardryUtilities.listToNBT(this.towerBlocks, pos -> new NBTTagLong(pos.toLong()))); + nbt.setTag("towerBlocks", NBTExtras.listToNBT(this.towerBlocks, NBTUtil::createPosTag)); } } @@ -427,11 +411,17 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp this.setElement(Element.values()[nbt.getInteger("element")]); this.textureIndex = nbt.getInteger("skin"); - this.spells = (List)WizardryUtilities.NBTToList(nbt.getTagList("spells", NBT.TAG_INT), - (NBTTagInt tag) -> Spell.get(tag.getInt())); + this.spells = (List)NBTExtras.NBTToList(nbt.getTagList("spells", NBT.TAG_INT), + (NBTTagInt tag) -> Spell.byMetadata(tag.getInt())); - this.towerBlocks = new HashSet(WizardryUtilities.NBTToList( - nbt.getTagList("towerBlocks", NBT.TAG_LONG), (NBTTagLong tag) -> BlockPos.fromLong(tag.getLong()))); + NBTTagList tagList = nbt.getTagList("towerBlocks", NBT.TAG_LONG); + if(!tagList.isEmpty()){ + this.towerBlocks = new HashSet<>(NBTExtras.NBTToList(tagList, NBTUtil::getPosFromTag)); + }else{ + // Fallback to old packed long format + this.towerBlocks = new HashSet<>(NBTExtras.NBTToList(nbt.getTagList("towerBlocks", NBT.TAG_LONG), + (NBTTagLong tag) -> BlockPos.fromLong(tag.getLong()))); + } } @Override @@ -439,20 +429,42 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp merchantrecipe.incrementToolUses(); this.livingSoundTime = -this.getTalkInterval(); - this.playSound(SoundEvents.ENTITY_VILLAGER_YES, this.getSoundVolume(), this.getSoundPitch()); + this.playSound(WizardrySounds.ENTITY_WIZARD_YES, this.getSoundVolume(), this.getSoundPitch()); - // Achievements if(this.getCustomer() != null){ + + // Achievements WizardryAdvancementTriggers.wizard_trade.triggerFor(this.getCustomer()); - if(merchantrecipe.getItemToSell().getItem() instanceof ItemSpellBook - && Spell.get(merchantrecipe.getItemToSell().getItemDamage()).tier == Tier.MASTER){ - WizardryAdvancementTriggers.buy_master_spell.triggerFor(this.getCustomer()); + if(merchantrecipe.getItemToSell().getItem() instanceof ItemSpellBook){ + + Spell spell = Spell.byMetadata(merchantrecipe.getItemToSell().getItemDamage()); + + if(spell.getTier() == Tier.MASTER) WizardryAdvancementTriggers.buy_master_spell.triggerFor(this.getCustomer()); + + // Spell discovery (a lot of this is the same as in the event handler) + WizardData data = WizardData.get(this.getCustomer()); + + if(data != null){ + + if(!MinecraftForge.EVENT_BUS.post(new DiscoverSpellEvent(this.getCustomer(), spell, + DiscoverSpellEvent.Source.PURCHASE)) && data.discoverSpell(spell)){ + + data.sync(); + + if(!world.isRemote && !this.getCustomer().isCreative() && Wizardry.settings.discoveryMode){ + // Sound and text only happen server-side, in survival, with discovery mode on + WizardryUtilities.playSoundAtPlayer(this.getCustomer(), WizardrySounds.MISC_DISCOVER_SPELL, 1.25f, 1); + this.getCustomer().sendMessage(new TextComponentTranslation("spell.discover", + spell.getNameForTranslationFormatted())); + } + } + } } } // Changed to a 4 in 5 chance of unlocking a new recipe. - if(this.rand.nextInt(5) > 0){ + if(this.rand.nextInt(5) > 0 || ItemArtefact.isArtefactActive(customer, WizardryItems.charm_haggler)){ this.timeUntilReset = 40; this.updateRecipes = true; @@ -500,7 +512,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp boolean itemAlreadySold = true; - Tier tier = Tier.BASIC; + Tier tier = Tier.NOVICE; while(itemAlreadySold){ @@ -515,7 +527,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp double tierIncreaseChance = 0.5 + 0.04 * (Math.max(this.trades.size() - 4, 0)); - tier = Tier.BASIC; + tier = Tier.NOVICE; if(rand.nextDouble() < tierIncreaseChance){ tier = Tier.APPRENTICE; @@ -545,8 +557,10 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Don't know how it can ever be empty here, but it's a failsafe. if(itemToSell.isEmpty()) return; - merchantrecipelist.add(new MerchantRecipe(this.getRandomPrice(tier), - new ItemStack(WizardryItems.magic_crystal, tier.ordinal() * 3 + 1 + rand.nextInt(4)), itemToSell)); + ItemStack secondItemToBuy = tier == Tier.MASTER ? new ItemStack(WizardryItems.astral_diamond) + : new ItemStack(WizardryItems.magic_crystal, tier.ordinal() * 3 + 1 + rand.nextInt(4)); + + merchantrecipelist.add(new MerchantRecipe(this.getRandomPrice(tier), secondItemToBuy, itemToSell)); } Collections.shuffle(merchantrecipelist); @@ -555,27 +569,31 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp this.trades = new WildcardTradeList(); } - for(int j1 = 0; j1 < merchantrecipelist.size(); ++j1){ - this.trades.add(merchantrecipelist.get(j1)); - } + this.trades.addAll(merchantrecipelist); } // TODO: Switch all of this over to some kind of loot pool system? private ItemStack getRandomPrice(Tier tier){ - ItemStack itemstack = ItemStack.EMPTY; - switch(this.rand.nextInt(3)){ - case 0: - itemstack = new ItemStack(Items.GOLD_INGOT, (tier.ordinal() + 1) * 8 - 1 + rand.nextInt(6)); - break; - case 1: - itemstack = new ItemStack(Items.DIAMOND, (tier.ordinal() + 1) * 4 - 2 + rand.nextInt(3)); - break; - case 2: - itemstack = new ItemStack(Items.EMERALD, (tier.ordinal() + 1) * 6 - 1 + rand.nextInt(3)); - break; + + Map map = Wizardry.settings.currencyItems; + // This isn't that efficient but it's not called very often really so it doesn't matter + ResourceLocation itemName = map.keySet().toArray(new ResourceLocation[0])[rand.nextInt(map.size())]; + Item item = Item.REGISTRY.getObject(itemName); + int value; + + if(item == null){ + Wizardry.logger.warn("Invalid item in currency items: {}", itemName); + item = Items.EMERALD; // Fallback item + value = 6; + }else{ + value = map.get(itemName); } - return itemstack; + + // ((tier.ordinal() + 1) * 16 + rand.nextInt(6)) gives a 'value' for the item being bought + // This is then divided by the value of the currency item to give a price + // The absolute maximum stack size that can result from this calculation (with value = 1) is 64. + return new ItemStack(item, (8 + tier.ordinal() * 16 + rand.nextInt(9)) / value); } private ItemStack getRandomItemOfTier(Tier tier){ @@ -583,32 +601,36 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp int randomiser; // All enabled spells of the given tier - List spells = Spell.getSpells(new Spell.TierElementFilter(tier, null)); + List spells = Spell.getSpells(new Spell.TierElementFilter(tier, null, SpellProperties.Context.TRADES)); // All enabled spells of the given tier that match this wizard's element - List specialismSpells = Spell.getSpells(new Spell.TierElementFilter(tier, this.getElement())); + List specialismSpells = Spell.getSpells(new Spell.TierElementFilter(tier, this.getElement(), SpellProperties.Context.TRADES)); + + // Wizards don't sell scrolls + spells.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK)); + specialismSpells.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK)); // This code is sooooooo much neater with the new filter system! switch(tier){ - case BASIC: + case NOVICE: randomiser = rand.nextInt(5); if(randomiser < 4 && !spells.isEmpty()){ if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){ // This means it is more likely for spell books sold to be of the same element as the wizard if the // wizard has an element. return new ItemStack(WizardryItems.spell_book, 1, - specialismSpells.get(rand.nextInt(specialismSpells.size())).id()); + specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata()); }else{ - return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).id()); + return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata()); } }else{ if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ // This means it is more likely for wands sold to be of the same element as the wizard if the wizard // has an element. - return new ItemStack(WizardryUtilities.getWand(tier, this.getElement())); + return new ItemStack(WizardryItems.getWand(tier, this.getElement())); }else{ return new ItemStack( - WizardryUtilities.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); + WizardryItems.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); } } @@ -619,18 +641,18 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // This means it is more likely for spell books sold to be of the same element as the wizard if the // wizard has an element. return new ItemStack(WizardryItems.spell_book, 1, - specialismSpells.get(rand.nextInt(specialismSpells.size())).id()); + specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata()); }else{ - return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).id()); + return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata()); } }else if(randomiser < 6){ if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ // This means it is more likely for wands sold to be of the same element as the wizard if the wizard // has an element. - return new ItemStack(WizardryUtilities.getWand(tier, this.getElement())); + return new ItemStack(WizardryItems.getWand(tier, this.getElement())); }else{ return new ItemStack( - WizardryUtilities.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); + WizardryItems.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); } }else if(randomiser < 8){ return new ItemStack(WizardryItems.arcane_tome, 1, 1); @@ -639,10 +661,10 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ // This means it is more likely for armour sold to be of the same element as the wizard if the // wizard has an element. - return new ItemStack(WizardryUtilities.getArmour(this.getElement(), slot)); + return new ItemStack(WizardryItems.getArmour(this.getElement(), slot)); }else{ return new ItemStack( - WizardryUtilities.getArmour(Element.values()[rand.nextInt(Element.values().length)], slot)); + WizardryItems.getArmour(Element.values()[rand.nextInt(Element.values().length)], slot)); } }else{ // Don't need to check for discovery mode here since it is done above @@ -656,18 +678,18 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // This means it is more likely for spell books sold to be of the same element as the wizard if the // wizard has an element. return new ItemStack(WizardryItems.spell_book, 1, - specialismSpells.get(rand.nextInt(specialismSpells.size())).id()); + specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata()); }else{ - return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).id()); + return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata()); } }else if(randomiser < 6){ if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ // This means it is more likely for wands sold to be of the same element as the wizard if the wizard // has an element. - return new ItemStack(WizardryUtilities.getWand(tier, this.getElement())); + return new ItemStack(WizardryItems.getWand(tier, this.getElement())); }else{ return new ItemStack( - WizardryUtilities.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); + WizardryItems.getWand(tier, Element.values()[rand.nextInt(Element.values().length)])); } }else if(randomiser < 8){ return new ItemStack(WizardryItems.arcane_tome, 1, 2); @@ -684,12 +706,12 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp if(randomiser < 5 && this.getElement() != Element.MAGIC && !specialismSpells.isEmpty()){ // Master spells can only be sold by a specialist in that element. return new ItemStack(WizardryItems.spell_book, 1, - specialismSpells.get(rand.nextInt(specialismSpells.size())).id()); + specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata()); }else if(randomiser < 6){ if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){ // Master elemental wands can only be sold by a specialist in that element. - return new ItemStack(WizardryUtilities.getWand(tier, this.getElement())); + return new ItemStack(WizardryItems.getWand(tier, this.getElement())); }else{ return new ItemStack(WizardryItems.master_wand); } @@ -718,7 +740,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Adds armour. for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ - this.setItemStackToSlot(slot, new ItemStack(WizardryUtilities.getArmour(element, slot))); + this.setItemStackToSlot(slot, new ItemStack(WizardryItems.getArmour(element, slot))); } // Default chance is 0.085f, for reference. @@ -728,11 +750,16 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // All wizards know magic missile, even if it is disabled. spells.add(Spells.magic_missile); - Tier maxTier = populateSpells(spells, element, 3, rand); + Tier maxTier = populateSpells(spells, element, false, 3, rand); // Now done after the spells so it can take the tier into account. - this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, - new ItemStack(WizardryUtilities.getWand(maxTier, element))); + ItemStack wand = new ItemStack(WizardryItems.getWand(maxTier, element)); + ArrayList list = new ArrayList<>(spells); + list.add(Spells.heal); + WandHelper.setSpells(wand, list.toArray(new Spell[5])); + this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, wand); + + this.setHealCooldown(50); return livingdata; } @@ -747,14 +774,14 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp * @param random A random number generator to use. * @return The tier of the highest-tier spell that was added to the list. */ - static Tier populateSpells(List spells, Element e, int n, Random random){ + static Tier populateSpells(List spells, Element e, boolean master, int n, Random random){ // This is the tier of the highest tier spell added. - Tier maxTier = Tier.BASIC; + Tier maxTier = Tier.NOVICE; List npcSpells = Spell.getSpells(Spell.npcSpells); - for(int i = 0; i < 3; i++){ + for(int i = 0; i < n; i++){ Tier tier; // If the wizard has no element, it picks a random one each time. @@ -764,17 +791,19 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // Uses its own special weighting if(randomiser < 10){ - tier = Tier.BASIC; + tier = Tier.NOVICE; }else if(randomiser < 16){ tier = Tier.APPRENTICE; - }else{ + }else if(randomiser < 19 || !master){ tier = Tier.ADVANCED; + }else{ + tier = Tier.MASTER; } if(tier.ordinal() > maxTier.ordinal()) maxTier = tier; // Finds all the spells of the chosen tier and element - List list = Spell.getSpells(new Spell.TierElementFilter(tier, element)); + List list = Spell.getSpells(new Spell.TierElementFilter(tier, element, SpellProperties.Context.NPCS)); // Keeps only spells which can be cast by NPCs list.retainAll(npcSpells); // Removes spells that the wizard already has @@ -828,12 +857,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp this.towerBlocks = blocks; } - /** - * Tests whether the block at the given coordinates is part of this wizard's tower. - * - * @param pos - * @return - */ + /** Tests whether the block at the given coordinates is part of this wizard's tower. */ public boolean isBlockPartOfTower(BlockPos pos){ if(this.towerBlocks == null) return false; // Uses .equals() rather than == so this will work fine. diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java index 3613d614..f61e33a3 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityZombieMinion.java @@ -1,8 +1,5 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.UUID; - import electroblob.wizardry.Wizardry; import net.minecraft.entity.EntityFlying; import net.minecraft.entity.EntityLivingBase; @@ -12,6 +9,7 @@ import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; @@ -19,22 +17,22 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; +import java.util.UUID; + public class EntityZombieMinion extends EntityZombie implements ISummonedCreature { // Field implementations - private int lifetime = 600; - private WeakReference casterReference; + private int lifetime = -1; private UUID casterUUID; // Setter + getter implementations @Override public int getLifetime(){ return lifetime; } @Override public void setLifetime(int lifetime){ this.lifetime = lifetime; } - @Override public WeakReference getCasterReference(){ return casterReference; } - @Override public void setCasterReference(WeakReference reference){ casterReference = reference; } - @Override public UUID getCasterUUID(){ return casterUUID; } - @Override public void setCasterUUID(UUID uuid){ this.casterUUID = uuid; } + @Override public UUID getOwnerId(){ return casterUUID; } + @Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; } /** Creates a new zombie minion in the given world. */ public EntityZombieMinion(World world){ @@ -42,13 +40,13 @@ public class EntityZombieMinion extends EntityZombie implements ISummonedCreatur this.experienceValue = 0; } - // EntityZombie overrides (EntityZombie is a long class so there are lots of these) + // EntityZombie overrides (EntityZombie is a complex class so there are lots of these) @Override protected void applyEntityAI(){ this.tasks.addTask(6, new EntityAIMoveThroughVillage(this, 1.0D, false)); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLivingBase.class, + this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class, 0, false, true, this.getTargetSelector())); } @@ -57,6 +55,7 @@ public class EntityZombieMinion extends EntityZombie implements ISummonedCreatur @Override protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty){} // They don't have equipment! @Override public void onKillEntity(EntityLivingBase entityLivingIn){} // Turns villagers to zombies in EntityZombie @Override public void setChildSize(boolean isChild){} + @Override protected ItemStack getSkullDrop(){ return ItemStack.EMPTY; } // Implementations @@ -121,8 +120,16 @@ public class EntityZombieMinion extends EntityZombie implements ISummonedCreatur @Override protected Item getDropItem(){ return null; } @Override protected ResourceLocation getLootTable(){ return null; } @Override public boolean canPickUpLoot(){ return false; } + // This vanilla method has nothing to do with the custom despawn() method. - @Override protected boolean canDespawn(){ return false; } + @Override protected boolean canDespawn(){ + return getCaster() == null && getOwnerId() == null; + } + + @Override + public boolean getCanSpawnHere(){ + return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; + } @Override public boolean canAttackClass(Class entityType){ @@ -143,7 +150,7 @@ public class EntityZombieMinion extends EntityZombie implements ISummonedCreatur @Override public boolean hasCustomName(){ // If this returns true, the renderer will show the nameplate when looking directly at the entity - return Wizardry.settings.showSummonedCreatureNames && getCaster() != null; + return Wizardry.settings.summonedCreatureNames && getCaster() != null; } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/living/IIntelligentSpellCaster.java b/src/main/java/electroblob/wizardry/entity/living/IIntelligentSpellCaster.java index 978f5457..939414d5 100644 --- a/src/main/java/electroblob/wizardry/entity/living/IIntelligentSpellCaster.java +++ b/src/main/java/electroblob/wizardry/entity/living/IIntelligentSpellCaster.java @@ -1,9 +1,9 @@ package electroblob.wizardry.entity.living; -import java.util.List; - import electroblob.wizardry.spell.Spell; +import java.util.List; + /** * [NYI] Interface for entities that can select between spells based on their current circumstances, to be used in * conjunction with {@link EntityAISelectSpell}. diff --git a/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java b/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java index 86eda769..6b336783 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISpellCaster.java @@ -1,24 +1,23 @@ package electroblob.wizardry.entity.living; -import java.util.List; - -import javax.annotation.Nonnull; - import electroblob.wizardry.registry.Spells; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.world.EnumDifficulty; +import javax.annotation.Nonnull; +import java.util.List; + /** * Interface for entities that can cast spells. Mainly intended for use by wizard-type entities, but can be implemented * by any subclass of EntityLiving. Designed to be as flexible as possible - ranging from the simplest use of giving an * entity a specific spell as an attack, to a complex AI which selects different spell types depending on the situation. * The only restriction is that the spells must be castable by NPCs. - *

    + *

    * This is intended for entities that use {@link EntityAIAttackSpell}. If so, all the spell casting code (including * packets) is handled by that class, and all the implementor needs to do is decide which spell(s) to select. - *

    + *

    * This class also allows Wizardry to do all the syncing necessary for continuous spell casting. All the implementor * needs to do is store the actual fields involved. */ diff --git a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java index 5e27cb57..5b9e06da 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java @@ -1,28 +1,15 @@ package electroblob.wizardry.entity.living; -import java.lang.ref.WeakReference; -import java.util.Arrays; -import java.util.UUID; - -import javax.annotation.Nullable; - import com.google.common.base.Predicate; - -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.integration.DamageSafetyChecker; -import electroblob.wizardry.item.ItemWand; -import electroblob.wizardry.util.IElementalDamage; -import electroblob.wizardry.util.IndirectMinionDamage; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.MinionDamage; -import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityList; -import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.*; import net.minecraft.entity.monster.IMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -36,28 +23,33 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.UUID; + /** * Interface for all summoned creatures. The code for summoned creatures has been overhauled in Wizardry 2.1, and this * interface allows summoned creatures to extend vanilla (or indeed modded) entity classes, so * EntitySummonedZombie now extends EntityZombie, for example. This change has two major * benefits: - *

    + *

    * - There is no longer any need for separate render classes, because summoned creatures are now instances of vanilla * types. You don't even need to assign a render class because the supertype should already be assigned the * correct one.
    * - Summoned creature classes are now much more robust when it comes to changes between Minecraft versions, since none * of the vanilla code needs to be copied. - *

    + *

    * Summoned creatures that do not emulate vanilla entities do not directly implement this interface. Instead, * they should extend the abstract base implementation, {@link EntitySummonedCreature}. - *

    + *

    * All damage dealt by ISummonedCreature instances is redirected via - * {@link ISummonedCreature#onLivingAttackEvent(net.minecraftforge.event.entity.living.LivingAttackEvent) + * {@link ISummonedCreature#onLivingAttackEvent(LivingAttackEvent) * ISummonedCreature.onLivingAttackEvent(LivingAttackEvent)} and replaced by an instance of - * {@link electroblob.wizardry.util.IElementalDamage IElementalDamage} with the summoner of that creature as the source + * {@link IElementalDamage IElementalDamage} with the summoner of that creature as the source * rather than the creature itself. This means that kills by summoned creatures register as kills for their owner, * dropping xp and rare loot if that owner is a player. - *

    + *

    * Though this system is a lot better than the previous system, it is not a perfect solution. The old * EntitySummonedCreature class overrode some methods from Entity in order to add shared functionality, but this cannot * be done with an interface. To get around this problem, this interface contains 5 delegate methods that do the same @@ -67,12 +59,12 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; * work properly unless it is adhered to. The position of the delegate method call is unimportant, but by convention * it is usually at the start of the calling method, which avoids it being unintentionally skipped by a return * statement (except for methods where the result of the delegate method should itself be returned). - *

    + *

    * It is recommended that when implementing this interface, you begin by copying {@link EntitySummonedCreature} to * ensure all the relevant methods are duplicated. You can then change the superclass, override any additional methods * and add functionality to any that are already overridden. You will always want to override the AI methods at the very * least. - *

    + *

    * Due to the limitations of interfaces, some methods that really ought to be protected are public. These are clearly * marked as 'Internal, DO NOT CALL'. Don't call them, only implement them. * @@ -83,7 +75,7 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; * sacrifices have to be made when it comes to Java style - because adding on to a pre-existing program is not a good * way of doing this sort of thing anyway, but we have no choice about that! */ @Mod.EventBusSubscriber -public interface ISummonedCreature extends IEntityAdditionalSpawnData { +public interface ISummonedCreature extends IEntityAdditionalSpawnData, IEntityOwnable { // Remember that ALL fields are static and final in interfaces, even if they don't explicitly state that. String NAMEPLATE_TRANSLATION_KEY = "entity." + Wizardry.MODID + ":summonedcreature.nameplate"; @@ -101,43 +93,51 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { */ int getLifetime(); - /** - * Sets the WeakReference object which refers to the owner of this summoned creature. Internal, don't call unless - * you know what you are doing. - */ - void setCasterReference(WeakReference reference); + /** Internal, do not use. Implementing classes should implement this to set their owner UUID field. */ + void setOwnerId(UUID uuid); - /** - * Returns a WeakReference object which refers to the owner of this summoned creature. Subclasses should store this - * as a private field. This may be null; as such it is preferable to use {@link ISummonedCreature#getCaster()} to - * get the caster object itself. - */ + /** Returns the UUID of the owner of this summoned creature, or null if it does not have an owner. + * Implementing classes should implement this to return their owner UUID field. */ @Nullable - WeakReference getCasterReference(); + @Override + UUID getOwnerId(); // Only overridden because I wanted to add javadoc! - /** Internal, DO NOT CALL. */ - void setCasterUUID(UUID uuid); - - /** Internal, DO NOT CALL. This is for loading purposes only and is not usually synchronised. */ - UUID getCasterUUID(); + @Nullable + @Override + default Entity getOwner(){ + return getCaster(); // Delegate to getCaster + } /** * Returns the EntityLivingBase that summoned this creature, or null if it no longer exists. Cases where the entity * may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported to - * another dimension, or this creature simply had no caster in the first place. This is the correct method to use - * to get the owner of this summoned creature. + * another dimension, or this creature simply had no caster in the first place. */ @Nullable - default EntityLivingBase getCaster(){ - return getCasterReference() == null ? null : getCasterReference().get(); + default EntityLivingBase getCaster(){ // Kept despite the above method because it returns an EntityLivingBase + + if(this instanceof Entity){ // Bit of a cheat but it saves having yet another method just to get the world + + Entity entity = WizardryUtilities.getEntityByUUID(((Entity)this).world, getOwnerId()); + + if(entity != null && !(entity instanceof EntityLivingBase)){ // Should never happen + Wizardry.logger.warn("{} has a non-living owner!", this); + return null; + } + + return (EntityLivingBase)entity; + + }else{ + Wizardry.logger.warn("{} implements ISummonedCreature but is not an SoundLoopSpellEntity!", this.getClass()); + return null; + } } /** - * Sets the EntityLivingBase that summoned this creature. This is the correct method to use to set the owner of - * this summoned creature. + * Sets the EntityLivingBase that summoned this creature. */ default void setCaster(@Nullable EntityLivingBase caster){ - setCasterReference(new WeakReference(caster)); + setOwnerId(caster == null ? null : caster.getUniqueID()); } // Miscellaneous @@ -164,17 +164,56 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { default void readSpawnData(ByteBuf buffer){ int id = buffer.readInt(); // We're on the client side here, so we can safely use Minecraft.getMinecraft().world via proxies. - if(id > -1) setCasterReference( - new WeakReference((EntityLivingBase)Wizardry.proxy.getTheWorld().getEntityByID(id))); + if(id > -1){ + Entity entity = Wizardry.proxy.getTheWorld().getEntityByID(id); + if(entity instanceof EntityLivingBase) setCaster((EntityLivingBase)entity); + else Wizardry.logger.warn("Received a spawn packet for entity {}, but no living entity matched the supplied ID", this); + } setLifetime(buffer.readInt()); } /** - * Shorthand for {@link WizardryUtilities#isValidTarget(Entity, Entity)}, with the owner of this creature as the - * attacker. Also allows implementors to override it if they wish to do so. + * Determines whether the given target is valid. Used by the default target selector (see + * {@link ISummonedCreature#getTargetSelector()}) and revenge targeting checks. This method is responsible for the + * ally designation system, default classes that may be targeted and the config whitelist/blacklist. + * Implementors may override this if they want to do something different or add their own checks. + * @see AllyDesignationSystem#isValidTarget(Entity, Entity) */ default boolean isValidTarget(Entity target){ - return WizardryUtilities.isValidTarget(this.getCaster(), target); + // If the target is valid based on the ADS... + if(AllyDesignationSystem.isValidTarget(this.getCaster(), target)){ + + // ...and is a player, they can be attacked, since players can't be in the whitelist or the + // blacklist... + if(target instanceof EntityPlayer){ + // ...unless the creature was summoned by a good wizard who the player has not angered. + if(getCaster() instanceof EntityWizard){ + if(getCaster().getRevengeTarget() != target + && ((EntityWizard)getCaster()).getAttackTarget() != target) { + return false; + } + } + + return true; + } + + // ...and is a mob, a summoned creature, a wizard... + if((target instanceof IMob || target instanceof ISummonedCreature + || (target instanceof EntityWizard && !(getCaster() instanceof EntityWizard)) + // ...or something that's attacking the owner... + || (target instanceof EntityLiving && ((EntityLiving)target).getAttackTarget() == getCaster()) + // ...or in the whitelist... + || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist) + .contains(EntityList.getKey(target.getClass()))) + // ...and isn't in the blacklist... + && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist) + .contains(EntityList.getKey(target.getClass()))){ + // ...it can be attacked. + return true; + } + } + + return false; } /** @@ -182,45 +221,7 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { * possible for implementors to override this in order to do something special when selecting a target. */ default Predicate getTargetSelector(){ - - return new Predicate(){ - - public boolean apply(Entity entity){ - // TODO: Backport invisibility check (also in wizards) - // If the target is valid and not invisible... - if(!entity.isInvisible() && isValidTarget(entity)){ - - // ... and is a player, they can be attacked, since players can't be in the whitelist or the - // blacklist ... - if(entity instanceof EntityPlayer){ - // ... unless the creature was summoned by a good wizard who the player has not angered. - if(getCaster() instanceof EntityWizard){ - if(((EntityWizard)getCaster()).getRevengeTarget() != entity - && ((EntityWizard)getCaster()).getAttackTarget() != entity) { - return false; - } - } - - return true; - } - - // ... and is a mob, a summoned creature, a wizard ... - if((entity instanceof IMob || entity instanceof ISummonedCreature - || (entity instanceof EntityWizard && !(getCaster() instanceof EntityWizard)) - // ... or in the whitelist ... - || Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist) - .contains(EntityList.getKey(entity.getClass()))) - // ... and isn't in the blacklist ... - && !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist) - .contains(EntityList.getKey(entity.getClass()))){ - // ... it can be attacked. - return true; - } - } - - return false; - } - }; + return entity -> getCaster() == null ? entity instanceof EntityPlayer : !entity.isInvisible() && isValidTarget(entity); } /** @@ -241,7 +242,7 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { * Called from the event handler after the damage change is applied. Does nothing by default, but can be overridden * to do something when a successful attack is made. This was added because the event-based damage source system can * cause parts of attackEntityAsMob not to fire, since attackEntityFrom is intercepted and canceled. - *

    + *

    * Usage examples: {@link EntitySilverfishMinion} uses this to summon more silverfish if the target is killed, * {@link EntitySkeletonMinion} and {@link EntitySpiderMinion} use this to add potion effects to the target. */ @@ -266,7 +267,7 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { * very little point in doing that since anything extra could just be added to readEntityFromNBT anyway. */ default void readNBTDelegate(NBTTagCompound tagcompound){ - this.setCasterUUID(tagcompound.getUniqueId("casterUUID")); + this.setOwnerId(tagcompound.getUniqueId("casterUUID")); this.setLifetime(tagcompound.getInteger("lifetime")); } @@ -275,8 +276,8 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { * returns true. */ default boolean shouldRevengeTarget(EntityLivingBase entity){ - // Allows the config to prevent minions from revenge-targeting their owners. - return entity != this.getCaster() || Wizardry.settings.minionRevengeTargeting; + // Allows the config to prevent minions from revenge-targeting their owners (or anything else, for that matter) + return Wizardry.settings.minionRevengeTargeting || isValidTarget(entity); } /** @@ -286,22 +287,17 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { default void updateDelegate(){ if(!(this instanceof Entity)) - throw new ClassCastException("Implementations of ISummonedCreature must extend Entity!"); + throw new ClassCastException("Implementations of ISummonedCreature must extend SoundLoopSpellEntity!"); Entity thisEntity = ((Entity)this); - if(this.getCaster() == null && this.getCasterUUID() != null){ - Entity entity = WizardryUtilities.getEntityByUUID(thisEntity.world, getCasterUUID()); - if(entity instanceof EntityLivingBase){ - this.setCasterReference(new WeakReference((EntityLivingBase)entity)); - } - } - if(thisEntity.ticksExisted == 1){ this.onSpawn(); } - if(thisEntity.ticksExisted > this.getLifetime() && this.getLifetime() != -1){ + // For some reason Minecraft reads the entity from NBT just after the entity is created, so setting -1 as a + // default lifetime doesn't work. The easiest way around this is to use 0 - nobody's going to need it! + if(thisEntity.ticksExisted > this.getLifetime() && this.getLifetime() > 0){ this.onDespawn(); thisEntity.setDead(); } @@ -322,20 +318,20 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { ItemStack stack = player.getHeldItem(hand); - WizardData properties = WizardData.get(player); + WizardData data = WizardData.get(player); // Selects one of the player's minions. - if(player.isSneaking() && stack.getItem() instanceof ItemWand){ + if(player.isSneaking() && stack.getItem() instanceof ISpellCastingItem){ - if(!player.world.isRemote && properties != null && this.getCaster() == player){ + if(!player.world.isRemote && data != null && this.getCaster() == player){ - if(properties.selectedMinion != null && properties.selectedMinion.get() == this){ + if(data.selectedMinion != null && data.selectedMinion.get() == this){ // Deselects the selected minion if right-clicked again - properties.selectedMinion = null; + data.selectedMinion = null; }else{ // Selects this minion - properties.selectedMinion = new WeakReference(this); + data.selectedMinion = new WeakReference<>(this); } - properties.sync(); + data.sync(); } return true; } @@ -346,7 +342,7 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { // Damage system @SubscribeEvent - public static void onLivingAttackEvent(LivingAttackEvent event){ + static void onLivingAttackEvent(LivingAttackEvent event){ // Rather than bother overriding entire attack methods in ISummonedCreature implementations, it's easier (and // more robust) to use LivingAttackEvent to modify the damage source. diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java index d9aee1e5..484457ba 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java @@ -1,5 +1,8 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -7,7 +10,6 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; @@ -24,16 +26,19 @@ public class EntityDarknessOrb extends EntityMagicProjectile { Entity target = rayTrace.entityHit; if(target != null && !MagicDamage.isEntityImmune(DamageType.WITHER, target)){ - float damage = 8 * damageMultiplier; + + float damage = Spells.darkness_orb.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; target.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.WITHER).setProjectile(), damage); if(target instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.WITHER, target)) - ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.WITHER, 150, 1)); + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.WITHER, + Spells.darkness_orb.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.darkness_orb.getProperty(Spell.EFFECT_STRENGTH).intValue())); - this.playSound(SoundEvents.ENTITY_WITHER_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + this.playSound(WizardrySounds.ENTITY_DARKNESS_ORB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); } this.setDead(); @@ -53,10 +58,6 @@ public class EntityDarknessOrb extends EntityMagicProjectile { ParticleBuilder.create(Type.DARK_MAGIC, this).clr(0.1f, 0.0f, 0.0f).spawn(world); } - if(this.ticksExisted > 150){ - this.setDead(); - } - // Cancels out the slowdown effect in EntityThrowable this.motionX /= 0.99; this.motionY /= 0.99; @@ -67,4 +68,9 @@ public class EntityDarknessOrb extends EntityMagicProjectile { public boolean hasNoGravity(){ return true; } + + @Override + public int getLifetime(){ + return 60; + } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java index 146b0c4e..6fd4cb3c 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java @@ -1,11 +1,14 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; public class EntityDart extends EntityMagicArrow { @@ -15,7 +18,7 @@ public class EntityDart extends EntityMagicArrow { super(world); } - @Override public double getDamage(){ return 4; } + @Override public double getDamage(){ return Spells.dart.getProperty(Spell.DAMAGE).doubleValue(); } @Override public boolean doGravity(){ return true; } @@ -24,13 +27,14 @@ public class EntityDart extends EntityMagicArrow { @Override public void onEntityHit(EntityLivingBase entityHit){ // Adds a weakness effect to the target. - entityHit.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 200, 1, false, false)); - this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + entityHit.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, Spells.dart.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.dart.getProperty(Spell.EFFECT_STRENGTH).intValue(), false, false)); + this.playSound(WizardrySounds.ENTITY_DART_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); } @Override - public void onBlockHit(){ - this.playSound(SoundEvents.ENTITY_ARROW_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + public void onBlockHit(RayTraceResult hit){ + this.playSound(WizardrySounds.ENTITY_DART_HIT_BLOCK, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); } @Override @@ -51,4 +55,8 @@ public class EntityDart extends EntityMagicArrow { @Override protected void entityInit(){} + @Override + public int getLifetime(){ + return -1; + } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityEmber.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityEmber.java new file mode 100644 index 00000000..13325283 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityEmber.java @@ -0,0 +1,87 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Disintegration; +import electroblob.wizardry.spell.Spell; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityEmber extends EntityMagicProjectile { + + private int extraLifetime; + + public EntityEmber(World world){ + super(world); + } + + public EntityEmber(World world, EntityLivingBase caster){ + super(world); + this.thrower = caster; + extraLifetime = rand.nextInt(30); + this.setSize(0.1f, 0.1f); + } + + @Override + public AxisAlignedBB getCollisionBoundingBox(){ + return null;//this.getEntityBoundingBox(); + } + + @Override + public int getLifetime(){ + return Spells.disintegration.getProperty(Disintegration.EMBER_LIFETIME).intValue() + extraLifetime; + } + + @Override + protected void onImpact(RayTraceResult result){ + + if(result.entityHit != null){ + result.entityHit.setFire(Spells.disintegration.getProperty(Spell.BURN_DURATION).intValue()); + } + + if(result.typeOfHit == RayTraceResult.Type.BLOCK){ + this.inGround = true; + this.collided = true; + if(result.sideHit.getAxis() == EnumFacing.Axis.X) motionX = 0; + if(result.sideHit.getAxis() == EnumFacing.Axis.Y){ + motionY = 0; + this.collidedVertically = true; + } + if(result.sideHit.getAxis() == EnumFacing.Axis.Z) motionZ = 0; + } + } + + @Override + public void applyEntityCollision(Entity entity){ + + super.applyEntityCollision(entity); + + if(entity instanceof EntityLivingBase){ + entity.setFire(Spells.disintegration.getProperty(Spell.BURN_DURATION).intValue()); + } + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(this.collidedVertically){ + this.motionY += this.getGravityVelocity(); + this.motionX *= 0.5; + this.motionZ *= 0.5; + } + + world.getEntitiesInAABBexcluding(thrower, this.getEntityBoundingBox(), e -> e instanceof EntityLivingBase) + .forEach(e -> e.setFire(Spells.disintegration.getProperty(Spell.BURN_DURATION).intValue())); + + // Copied from ParticleLava + if(this.rand.nextFloat() > (float)this.ticksExisted / this.getLifetime()){ + this.world.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, this.posX, this.posY, this.posZ, this.motionX, this.motionY, this.motionZ); + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java index 50c5e648..454aad3e 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebolt.java @@ -1,9 +1,12 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; import net.minecraft.entity.Entity; -import net.minecraft.init.SoundEvents; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; @@ -16,19 +19,22 @@ public class EntityFirebolt extends EntityMagicProjectile { @Override protected void onImpact(RayTraceResult rayTrace){ + Entity entityHit = rayTrace.entityHit; if(entityHit != null){ - float damage = 5 * damageMultiplier; + + float damage = Spells.firebolt.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; entityHit.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(), damage); - if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit)) entityHit.setFire(5); + if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit)) + entityHit.setFire(Spells.firebolt.getProperty(Spell.BURN_DURATION).intValue()); } - this.playSound(SoundEvents.BLOCK_LAVA_POP, 2, 0.8f + rand.nextFloat() * 0.3f); + this.playSound(WizardrySounds.ENTITY_FIREBOLT_HIT, 2, 0.8f + rand.nextFloat() * 0.3f); // Particle effect if(world.isRemote){ @@ -47,16 +53,20 @@ public class EntityFirebolt extends EntityMagicProjectile { super.onUpdate(); if(world.isRemote){ - for(int i = 0; i < 4; i++){ - world.spawnParticle(EnumParticleTypes.FLAME, this.posX + rand.nextFloat() * 0.2 - 0.1, - this.posY + this.height / 2 + rand.nextFloat() * 0.2 - 0.1, - this.posZ + rand.nextFloat() * 0.2 - 0.1, 0, 0, 0); + ParticleBuilder.create(ParticleBuilder.Type.MAGIC_FIRE, this).time(14).spawn(world); + + if(this.ticksExisted > 1){ // Don't spawn particles behind where it started! + double x = posX - motionX/2 + rand.nextFloat() * 0.2 - 0.1; + double y = posY + this.height/2 - motionY/2 + rand.nextFloat() * 0.2 - 0.1; + double z = posZ - motionZ/2 + rand.nextFloat() * 0.2 - 0.1; + ParticleBuilder.create(ParticleBuilder.Type.MAGIC_FIRE).pos(x, y, z).time(14).spawn(world); } } + } - if(this.ticksExisted > 8){ - this.setDead(); - } + @Override + public int getLifetime(){ + return 6; } @Override diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java index 32c42bf3..0c4693ce 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java @@ -1,7 +1,8 @@ package electroblob.wizardry.entity.projectile; -import java.util.List; - +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -9,17 +10,23 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import java.util.List; + public class EntityFirebomb extends EntityBomb { public EntityFirebomb(World world){ super(world); } + @Override + public int getLifetime(){ + return -1; + } + @Override protected void onImpact(RayTraceResult rayTrace){ @@ -27,13 +34,14 @@ public class EntityFirebomb extends EntityBomb { if(entityHit != null){ // This is if the firebomb gets a direct hit - float damage = 5 * damageMultiplier; + float damage = Spells.firebomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier; entityHit.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(), damage); - if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit)) entityHit.setFire(10); + if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit)) + entityHit.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue()); } // Particle effect @@ -45,7 +53,7 @@ public class EntityFirebomb extends EntityBomb { for(int i = 0; i < 60 * blastMultiplier; i++){ ParticleBuilder.create(Type.MAGIC_FIRE, rand, posX, posY, posZ, 2*blastMultiplier, false) - .time(15 + rand.nextInt(5)).scale(2 + rand.nextFloat()).spawn(world); + .time(10 + rand.nextInt(4)).scale(2 + rand.nextFloat()).spawn(world); ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) .clr(1.0f, 0.2f + rand.nextFloat() * 0.4f, 0.0f).spawn(world); @@ -56,10 +64,10 @@ public class EntityFirebomb extends EntityBomb { if(!this.world.isRemote){ - this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.5F, rand.nextFloat() * 0.4F + 0.6F); - this.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); + this.playSound(WizardrySounds.ENTITY_FIREBOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F); + this.playSound(WizardrySounds.ENTITY_FIREBOMB_FIRE, 1, 1); - double range = 3.0d * blastMultiplier; + double range = Spells.firebomb.getProperty(Spell.BLAST_RADIUS).floatValue() * blastMultiplier; List targets = WizardryUtilities.getEntitiesWithinRadius(range, this.posX, this.posY, this.posZ, this.world); @@ -70,8 +78,8 @@ public class EntityFirebomb extends EntityBomb { // Splash damage does not count as projectile damage target.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE), - 4.0f * damageMultiplier); - target.setFire(7); + Spells.firebomb.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier); + target.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue()); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java index 8fcf251d..0b5bb9cb 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java @@ -1,53 +1,100 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.item.IManaStoringItem; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import java.util.Arrays; + public class EntityForceArrow extends EntityMagicArrow { + /** The mana used to cast this force arrow, used for artefacts. */ + private int mana = 0; + /** Creates a new force arrow in the given world. */ public EntityForceArrow(World world){ super(world); } + public void setMana(int mana){ + this.mana = mana; + } + @Override public void onEntityHit(EntityLivingBase entityHit){ - this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); + this.playSound(WizardrySounds.ENTITY_FORCE_ARROW_HIT, 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 public void tickInGround(){ + returnManaToCaster(); this.setDead(); } @Override - public void onBlockHit(){ - this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); + public void onUpdate(){ + + if(getLifetime() >=0 && this.ticksExisted > getLifetime()){ // The last tick before it disappears + returnManaToCaster(); + } + + super.onUpdate(); + } + + private void returnManaToCaster(){ + + if(mana > 0 && getCaster() instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)getCaster(); + + if(!player.capabilities.isCreativeMode && ItemArtefact.isArtefactActive(player, WizardryItems.ring_mana_return)){ + + for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){ + if(stack.getItem() instanceof ISpellCastingItem && stack.getItem() instanceof IManaStoringItem + && Arrays.asList(((ISpellCastingItem)stack.getItem()).getSpells(stack)).contains(Spells.force_arrow)){ + ((IManaStoringItem)stack.getItem()).rechargeMana(stack, mana); + } + } + } + } + } + + @Override + public void onBlockHit(RayTraceResult hit){ + this.playSound(WizardrySounds.ENTITY_FORCE_ARROW_HIT, 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); + //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 - public void tickInAir(){ - if(this.ticksExisted > 20){ - this.setDead(); - } + public int getLifetime(){ + return 20; } @Override public double getDamage(){ - return 7.0d; + return Spells.force_arrow.getProperty(Spell.DAMAGE).floatValue(); } @Override diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java index 73373a40..3967b0ba 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java @@ -1,30 +1,37 @@ package electroblob.wizardry.entity.projectile; -import java.util.List; - +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import java.util.List; + public class EntityForceOrb extends EntityBomb { public EntityForceOrb(World world){ super(world); } + @Override + public int getLifetime(){ + return -1; + } + @Override protected void onImpact(RayTraceResult par1RayTraceResult){ if(par1RayTraceResult.entityHit != null){ // This is if the force orb gets a direct hit - this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + this.playSound(WizardrySounds.ENTITY_FORCE_ORB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); } // Particle effect @@ -41,10 +48,10 @@ public class EntityForceOrb extends EntityBomb { // 2 gives a cool flanging effect! float pitch = this.rand.nextFloat() * 0.2F + 0.3F; - this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.5F, pitch); - this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.5F, pitch - 0.01f); + this.playSound(WizardrySounds.ENTITY_FORCE_ORB_HIT_BLOCK, 1.5F, pitch); + this.playSound(WizardrySounds.ENTITY_FORCE_ORB_HIT_BLOCK, 1.5F, pitch - 0.01f); - double blastRadius = 4.0d * blastMultiplier; + double blastRadius = Spells.force_orb.getProperty(Spell.BLAST_RADIUS).floatValue() * blastMultiplier; List targets = WizardryUtilities.getEntitiesWithinRadius(blastRadius, this.posX, this.posY, this.posZ, this.world); @@ -59,7 +66,7 @@ public class EntityForceOrb extends EntityBomb { double dz = this.posZ - target.posZ > 0 ? -0.5 - (this.posZ - target.posZ) / 8 : 0.5 - (this.posZ - target.posZ) / 8; - float damage = 4 * damageMultiplier; + float damage = Spells.force_orb.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; target.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.BLAST), damage); diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java index 1f35f8d6..048d47c9 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java @@ -1,9 +1,9 @@ package electroblob.wizardry.entity.projectile; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -12,43 +12,55 @@ import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; -import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import java.util.List; + public class EntityIceCharge extends EntityBomb { + public static final String ICE_SHARDS = "ice_shards"; + public EntityIceCharge(World world){ super(world); } @Override - protected void onImpact(RayTraceResult par1RayTraceResult){ - Entity entityHit = par1RayTraceResult.entityHit; + public int getLifetime(){ + return -1; + } + + @Override + protected void onImpact(RayTraceResult rayTrace){ + + Entity entityHit = rayTrace.entityHit; if(entityHit != null){ // This is if the ice charge gets a direct hit - float damage = 4 * damageMultiplier; + float damage = Spells.ice_charge.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; entityHit.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FROST).setProjectile(), damage); if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.FROST, entityHit)) - ((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(WizardryPotions.frost, 120, 1)); + ((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(WizardryPotions.frost, + Spells.ice_charge.getProperty(Spell.DIRECT_EFFECT_DURATION).intValue(), + Spells.ice_charge.getProperty(Spell.DIRECT_EFFECT_STRENGTH).intValue())); } // Particle effect if(world.isRemote){ this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); for(int i = 0; i < 30 * blastMultiplier; i++){ - + ParticleBuilder.create(Type.ICE, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) .time(35).gravity(true).spawn(world); - + float brightness = 0.4f + rand.nextFloat() * 0.5f; ParticleBuilder.create(Type.DARK_MAGIC, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) .clr(brightness, brightness + 0.1f, 1.0f).spawn(world); @@ -57,10 +69,10 @@ public class EntityIceCharge extends EntityBomb { if(!this.world.isRemote){ - this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.5f, rand.nextFloat() * 0.4f + 0.6f); - this.playSound(WizardrySounds.SPELL_ICE, 1.2f, rand.nextFloat() * 0.4f + 1.2f); + this.playSound(WizardrySounds.ENTITY_ICE_CHARGE_SMASH, 1.5f, rand.nextFloat() * 0.4f + 0.6f); + this.playSound(WizardrySounds.ENTITY_ICE_CHARGE_ICE, 1.2f, rand.nextFloat() * 0.4f + 1.2f); - double radius = 3.0d * blastMultiplier; + double radius = Spells.ice_charge.getProperty(Spell.EFFECT_RADIUS).floatValue() * blastMultiplier; List targets = WizardryUtilities.getEntitiesWithinRadius(radius, this.posX, this.posY, this.posZ, this.world); @@ -69,7 +81,9 @@ public class EntityIceCharge extends EntityBomb { for(EntityLivingBase target : targets){ if(target != entityHit && target != this.getThrower()){ if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) - target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 100, 0)); + target.addPotionEffect(new PotionEffect(WizardryPotions.frost, + Spells.ice_charge.getProperty(Spell.SPLASH_EFFECT_DURATION).intValue(), + Spells.ice_charge.getProperty(Spell.SPLASH_EFFECT_STRENGTH).intValue())); } } @@ -79,35 +93,39 @@ public class EntityIceCharge extends EntityBomb { BlockPos pos = new BlockPos(this.posX + i, this.posY, this.posZ + j); - int y = WizardryUtilities.getNearestFloorLevelB(world, pos, 7); + Integer y = WizardryUtilities.getNearestSurface(world, pos, EnumFacing.UP, 7, true, + WizardryUtilities.SurfaceCriteria.SOLID_LIQUID_TO_AIR); - pos = new BlockPos(pos.getX(), y, pos.getZ()); + if(y != null){ - double dist = this.getDistance(pos.getX(), pos.getY(), pos.getZ()); + pos = new BlockPos(pos.getX(), y, pos.getZ()); - // Randomised with weighting so that the nearer the block the more likely it is to be snowed. - if(y != -1 && rand.nextInt((int)dist * 2 + 1) < 1 && dist < 2){ - if(world.getBlockState(pos.down()).getBlock() == Blocks.WATER){ - world.setBlockState(pos.down(), Blocks.ICE.getDefaultState()); - }else{ - // Don't need to check whether the block at pos can be replaced since getNearestFloorLevelB - // only ever returns floors with air above them. - world.setBlockState(pos, Blocks.SNOW_LAYER.getDefaultState()); + double dist = this.getDistance(pos.getX(), pos.getY(), pos.getZ()); + + // Randomised with weighting so that the nearer the block the more likely it is to be snowed. + if(rand.nextInt((int)dist * 2 + 1) < 1 && dist < 2){ + if(world.getBlockState(pos.down()).getBlock() == Blocks.WATER){ + world.setBlockState(pos.down(), Blocks.ICE.getDefaultState()); + }else{ + // Don't need to check whether the block at pos can be replaced since getNearestFloorLevelB + // only ever returns floors with air above them. + world.setBlockState(pos, Blocks.SNOW_LAYER.getDefaultState()); + } } } } } // Releases shards - for(int i = 0; i < 10; i++){ + for(int i = 0; i < Spells.ice_charge.getProperty(ICE_SHARDS).intValue(); i++){ double dx = rand.nextDouble() - 0.5; double dy = rand.nextDouble() - 0.5; double dz = rand.nextDouble() - 0.5; EntityIceShard iceshard = new EntityIceShard(world); iceshard.setPosition(this.posX + dx, this.posY + dy, this.posZ + dz); - iceshard.motionX = dx; - iceshard.motionY = dy; - iceshard.motionZ = dz; + iceshard.motionX = dx * 1.5; + iceshard.motionY = dy * 1.5; + iceshard.motionZ = dz * 1.5; iceshard.setCaster(this.getThrower()); iceshard.damageMultiplier = this.damageMultiplier; world.spawnEntity(iceshard); diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java index 1863f343..a9c2032e 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java @@ -1,13 +1,16 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; public class EntityIceLance extends EntityMagicArrow { @@ -18,7 +21,9 @@ public class EntityIceLance extends EntityMagicArrow { this.setKnockbackStrength(1); } - @Override public double getDamage(){ return 10.0d; } + @Override public double getDamage(){ return Spells.ice_lance.getProperty(Spell.DAMAGE).floatValue(); } + + @Override public int getLifetime(){ return -1; } @Override public DamageType getDamageType(){ return DamageType.FROST; } @@ -35,13 +40,15 @@ public class EntityIceLance extends EntityMagicArrow { // Adds a freeze effect to the target. if(!MagicDamage.isEntityImmune(DamageType.FROST, entityHit)) - entityHit.addPotionEffect(new PotionEffect(WizardryPotions.frost, 300, 0)); + entityHit.addPotionEffect(new PotionEffect(WizardryPotions.frost, + Spells.ice_lance.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.ice_lance.getProperty(Spell.EFFECT_STRENGTH).intValue())); - this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + this.playSound(WizardrySounds.ENTITY_ICE_LANCE_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); } @Override - public void onBlockHit(){ + public void onBlockHit(RayTraceResult hit){ // Adds a particle effect when the ice lance hits a block. if(this.world.isRemote){ for(int j = 0; j < 10; j++){ @@ -49,8 +56,8 @@ public class EntityIceLance extends EntityMagicArrow { .time(20 + rand.nextInt(10)).gravity(true).spawn(world); } } - // Parameters for sound: sound event name, volume, pitch. - this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.0F, rand.nextFloat() * 0.4F + 1.2F); + + this.playSound(WizardrySounds.ENTITY_ICE_LANCE_SMASH, 1.0F, rand.nextFloat() * 0.4F + 1.2F); } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java index c4d42bfa..72a2cfdf 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java @@ -1,13 +1,17 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class EntityIceShard extends EntityMagicArrow { @@ -17,7 +21,9 @@ public class EntityIceShard extends EntityMagicArrow { super(world); } - @Override public double getDamage(){ return 6; } + @Override public double getDamage(){ return Spells.ice_shard.getProperty(Spell.DAMAGE).floatValue(); } + + @Override public int getLifetime(){ return -1; } @Override public DamageType getDamageType(){ return DamageType.FROST; } @@ -32,13 +38,16 @@ public class EntityIceShard extends EntityMagicArrow { // Adds a freeze effect to the target. if(!MagicDamage.isEntityImmune(DamageType.FROST, entityHit)) - entityHit.addPotionEffect(new PotionEffect(WizardryPotions.frost, 200, 0)); + entityHit.addPotionEffect(new PotionEffect(WizardryPotions.frost, + Spells.ice_shard.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.ice_shard.getProperty(Spell.EFFECT_STRENGTH).intValue())); - this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + this.playSound(WizardrySounds.ENTITY_ICE_SHARD_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); } @Override - public void onBlockHit(){ + public void onBlockHit(RayTraceResult hit){ + // Adds a particle effect when the ice shard hits a block. if(this.world.isRemote){ // Gets a position slightly away from the block hit so the particle doesn't get cut in half by the block face @@ -51,7 +60,7 @@ public class EntityIceShard extends EntityMagicArrow { } } // Parameters for sound: sound event name, volume, pitch. - this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.0F, rand.nextFloat() * 0.4F + 1.2F); + this.playSound(WizardrySounds.ENTITY_ICE_SHARD_SMASH, 1.0F, rand.nextFloat() * 0.4F + 1.2F); } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceball.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceball.java new file mode 100644 index 00000000..7a34b09d --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceball.java @@ -0,0 +1,117 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Blocks; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityIceball extends EntityMagicProjectile { + + public EntityIceball(World world){ + super(world); + this.setSize(0.5f, 0.5f); + } + + @Override + protected void onImpact(RayTraceResult rayTrace){ + + if(!world.isRemote){ + + Entity entityHit = rayTrace.entityHit; + + if(entityHit != null){ + + float damage = Spells.iceball.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; + + entityHit.attackEntityFrom( + MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FROST).setProjectile(), + damage); + + if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.FROST, entityHit)){ + ((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(WizardryPotions.frost, + Spells.iceball.getProperty(Spell.EFFECT_DURATION).intValue(), + Spells.iceball.getProperty(Spell.EFFECT_STRENGTH).intValue())); + } + + }else{ + + boolean flag = true; + + if(this.getThrower() != null && this.getThrower() instanceof EntityLiving){ + flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.getThrower()); + } + + if(flag){ + + BlockPos pos = rayTrace.getBlockPos(); + + if(rayTrace.sideHit == EnumFacing.UP && !world.isRemote && world.isSideSolid(pos, EnumFacing.UP) + && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + world.setBlockState(pos.up(), Blocks.SNOW_LAYER.getDefaultState()); + } + } + } + + this.playSound(WizardrySounds.ENTITY_ICEBALL_HIT, 2, 0.8f + rand.nextFloat() * 0.3f); + + this.setDead(); + } + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(world.isRemote){ + + for(int i=0; i<5; i++){ + + double dx = (rand.nextDouble() - 0.5) * width; + double dy = (rand.nextDouble() - 0.5) * height + this.height/2; + double dz = (rand.nextDouble() - 0.5) * width; + double v = 0.06; + ParticleBuilder.create(ParticleBuilder.Type.SNOW) + .pos(this.getPositionVector().add(dx - this.motionX/2, dy, dz - this.motionZ/2)) + .vel(-v * dx, -v * dy, -v * dz).scale(width*2).time(8 + rand.nextInt(4)).spawn(world); + + if(ticksExisted > 1){ + dx = (rand.nextDouble() - 0.5) * width; + dy = (rand.nextDouble() - 0.5) * height + this.height / 2; + dz = (rand.nextDouble() - 0.5) * width; + ParticleBuilder.create(ParticleBuilder.Type.SNOW) + .pos(this.getPositionVector().add(dx - this.motionX, dy, dz - this.motionZ)) + .vel(-v * dx, -v * dy, -v * dz).scale(width*2).time(8 + rand.nextInt(4)).spawn(world); + } + } + } + } + + @Override + public int getLifetime(){ + return 16; + } + + @Override + public boolean hasNoGravity(){ + return true; + } + + @Override + public boolean canRenderOnFire(){ + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLargeMagicFireball.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLargeMagicFireball.java new file mode 100644 index 00000000..e78574a4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLargeMagicFireball.java @@ -0,0 +1,106 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.projectile.EntityLargeFireball; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +/** + * It's like {@link EntityMagicFireball}, but bigger... the wizardry version of vanilla's + * {@link net.minecraft.entity.projectile.EntityLargeFireball} + */ +@Mod.EventBusSubscriber +public class EntityLargeMagicFireball extends EntityMagicFireball { + + public static final String EXPLOSION_POWER = "explosion_power"; + + /** The entity blast multiplier. This is now synced and saved centrally from {@link EntityBomb}. */ + public float blastMultiplier = 1.0f; + + /** The explosion power of this fireball. If this is -1, the damage for the fireball + * spell will be used instead; this is for when the fireball is not from a spell (i.e. a vanilla fireball replacement). */ + protected float explosionPower = -1; + + public EntityLargeMagicFireball(World world){ + super(world); + this.setSize(1, 1); + } + + public void setExplosionPower(float explosionPower){ + this.explosionPower = explosionPower; + } + + public float getExplosionPower(){ + return explosionPower == -1 ? Spells.greater_fireball.getProperty(EXPLOSION_POWER).floatValue() : explosionPower; + } + + @Override + public float getDamage(){ + return damage == -1 ? Spells.greater_fireball.getProperty(Spell.DAMAGE).floatValue() : damage; + } + + @Override + protected void onImpact(RayTraceResult rayTrace){ + + if(!world.isRemote){ + boolean flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.thrower); + this.world.newExplosion(null, this.posX, this.posY, this.posZ, getExplosionPower() * blastMultiplier, flag, flag); + } + + super.onImpact(rayTrace); + } + + @Override + public void writeSpawnData(ByteBuf buffer){ + buffer.writeFloat(blastMultiplier); + super.writeSpawnData(buffer); + } + + @Override + public void readSpawnData(ByteBuf buffer){ + blastMultiplier = buffer.readFloat(); + super.readSpawnData(buffer); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + blastMultiplier = nbttagcompound.getFloat("blastMultiplier"); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setFloat("blastMultiplier", blastMultiplier); + } + + @SubscribeEvent + public static void onEntityJoinWorldEvent(EntityJoinWorldEvent event){ + // Replaces all vanilla large fireballs with wizardry ones + if(Wizardry.settings.replaceVanillaFireballs && event.getEntity() instanceof EntityLargeFireball){ + + event.setCanceled(true); + + EntityLargeMagicFireball fireball = new EntityLargeMagicFireball(event.getWorld()); + fireball.thrower = ((EntityLargeFireball)event.getEntity()).shootingEntity; + fireball.setPosition(event.getEntity().posX, event.getEntity().posY, event.getEntity().posZ); + fireball.setDamage(6); + // Don't set the burn duration because vanilla large fireballs don't set mobs on fire directly + fireball.setExplosionPower(((EntityLargeFireball)event.getEntity()).explosionPower); + fireball.setLifetime(75); + + fireball.motionX = ((EntityLargeFireball)event.getEntity()).accelerationX * ACCELERATION_CONVERSION_FACTOR; + fireball.motionY = ((EntityLargeFireball)event.getEntity()).accelerationY * ACCELERATION_CONVERSION_FACTOR; + fireball.motionZ = ((EntityLargeFireball)event.getEntity()).accelerationZ * ACCELERATION_CONVERSION_FACTOR; + + event.getWorld().spawnEntity(fireball); + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java index 63857276..2f166bfd 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java @@ -1,6 +1,8 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; @@ -14,7 +16,9 @@ public class EntityLightningArrow extends EntityMagicArrow { super(world); } - @Override public double getDamage(){ return 7.0d; } + @Override public double getDamage(){ return Spells.lightning_arrow.getProperty(Spell.DAMAGE).doubleValue(); } + + @Override public int getLifetime(){ return 20; } @Override public DamageType getDamageType(){ return DamageType.SHOCK; } @@ -31,26 +35,22 @@ public class EntityLightningArrow extends EntityMagicArrow { } } - this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.0F); - @Override - public void onBlockHit(RayTraceResult hit){ - if(this.world.isRemote){ - Vec3d vec = hit.hitVec.add(new Vec3d(hit.sideHit.getDirectionVec()).scale(WizardryUtilities.ANTI_Z_FIGHTING_OFFSET)); - ParticleBuilder.create(Type.SCORCH).pos(vec).face(hit.sideHit).clr(0.4f, 0.8f, 1).scale(0.6f).spawn(world); - } + this.playSound(WizardrySounds.ENTITY_LIGHTNING_ARROW_HIT, 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 public void tickInAir(){ - - if(this.ticksExisted > 20){ - this.setDead(); - } - if(world.isRemote){ ParticleBuilder.create(Type.SPARK).pos(posX, posY, posZ).spawn(world); } - } @Override diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java index afa24ff8..7f745f87 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningDisc.java @@ -1,15 +1,13 @@ package electroblob.wizardry.entity.projectile; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; @@ -27,13 +25,12 @@ public class EntityLightningDisc extends EntityMagicProjectile { Entity entityHit = result.entityHit; if(entityHit != null){ - float damage = 12 * damageMultiplier; - - entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK), - damage); + float damage = Spells.lightning_disc.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), + DamageType.SHOCK), damage); } - this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + this.playSound(WizardrySounds.ENTITY_LIGHTNING_DISC_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); if(result.typeOfHit == RayTraceResult.Type.BLOCK) this.setDead(); } @@ -46,47 +43,27 @@ public class EntityLightningDisc extends EntityMagicProjectile { // Particle effect if(world.isRemote){ for(int i = 0; i < 8; i++){ - // TODO: Why are the x and z parameters different? ParticleBuilder.create(Type.SPARK).pos(this.posX + rand.nextFloat() * 2 - 1, this.posY, this.posZ + rand.nextFloat() * 2 - 1).spawn(world); } } - if(!this.collided && !world.isRemote){ - - double seekingRange = 5.0d; - - List entities = WizardryUtilities.getEntitiesWithinRadius(seekingRange, this.posX, - this.posY, this.posZ, this.world); - Entity target = null; - - for(Entity possibleTarget : entities){ - // Decides if current entity should be replaced. - if(target == null || this.getDistance(target) > this.getDistance(possibleTarget)){ - // Decides if new entity is a valid target. - if(WizardryUtilities.isValidTarget(this.getThrower(), possibleTarget)){ - target = possibleTarget; - } - } - } - - if(target != null && Math.abs(this.motionX) < 1 && Math.abs(this.motionY) < 1 - && Math.abs(this.motionZ) < 1){ - this.addVelocity((target.posX - this.posX) / 30, (target.posY + target.height / 2 - this.posY) / 30, - (target.posZ - this.posZ) / 30); - } - } - - if(this.ticksExisted > 50){ - this.setDead(); - } - // Cancels out the slowdown effect in EntityThrowable this.motionX /= 0.99; this.motionY /= 0.99; this.motionZ /= 0.99; } + @Override + public float getSeekingStrength(){ + return Spells.lightning_disc.getProperty(Spell.SEEKING_STRENGTH).floatValue(); + } + + @Override + public int getLifetime(){ + return 30; + } + @Override public boolean hasNoGravity(){ return true; diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java index 9b84d8f7..2dd166e6 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java @@ -1,11 +1,12 @@ package electroblob.wizardry.entity.projectile; -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.UUID; - +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; @@ -23,22 +24,23 @@ import net.minecraft.network.play.server.SPacketChangeGameState; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.*; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.UUID; + /** * This class was copied from EntityArrow in the 1.7.10 update as part of the overhaul and major cleanup of the code for * the projectiles. It provides a unifying superclass for all directed projectiles (i.e. not spherical stuff like * snowballs), namely magic missile, ice shard, force arrow, lightning arrow and dart. All spherical projectiles should * extend {@link EntityMagicProjectile}. - *

    + *

    * This class handles saving of the damage multiplier and all shared logic. Methods are provided which are triggered at * useful points during the entity update cycle as well as a few getters for various properties. Override any of these * to change the behaviour (no need to call super for any of them). @@ -46,8 +48,12 @@ import net.minecraftforge.fml.relauncher.SideOnly; * @since Wizardry 1.0 * @author Electroblob */ +// TODO: Might be a good idea to have this implement IEntityOwnable as well public abstract class EntityMagicArrow extends Entity implements IProjectile, IEntityAdditionalSpawnData { + public static final double LAUNCH_Y_OFFSET = 0.1; + public static final int SEEKING_TIME = 15; + private int blockX = -1; private int blockY = -1; private int blockZ = -1; @@ -81,14 +87,14 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE // Initialiser methods - /** Sets the shooter of the projectile to the given caster, positions the projctile at the given caster's eyes and + /** Sets the shooter of the projectile to the given caster, positions the projectile at the given caster's eyes and * aims it in the direction they are looking with the given speed. */ public void aim(EntityLivingBase caster, float speed){ this.setCaster(caster); - this.setLocationAndAngles(caster.posX, caster.posY + (double)caster.getEyeHeight(), caster.posZ, - caster.rotationYaw, caster.rotationPitch); + this.setLocationAndAngles(caster.posX, caster.getEntityBoundingBox().minY + (double)caster.getEyeHeight() - LAUNCH_Y_OFFSET, + caster.posZ, caster.rotationYaw, caster.rotationPitch); this.posX -= (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F); this.posY -= 0.10000000149011612D; @@ -106,7 +112,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE this.shoot(this.motionX, this.motionY, this.motionZ, speed * 1.5F, 1.0F); } - /** Sets the shooter of the projectile to the given caster, positions the projctile at the given caster's eyes and + /** Sets the shooter of the projectile to the given caster, positions the projectile at the given caster's eyes and * aims it at the given target with the given speed. The trajectory will be altered slightly by a random amount * determined by the aimingError parameter. For reference, skeletons set this to 10 on easy, 6 on normal and 2 on hard * difficulty. */ @@ -114,7 +120,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE this.setCaster(caster); - this.posY = caster.posY + (double)caster.getEyeHeight() - 0.1d; + this.posY = caster.getEntityBoundingBox().minY + (double)caster.getEyeHeight() - LAUNCH_Y_OFFSET; double dx = target.posX - caster.posX; double dy = this.doGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0f) - this.posY : target.getEntityBoundingBox().minY + (double)(target.height / 2.0f) - this.posY; @@ -141,6 +147,10 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE /** Subclasses must override this to set their own base damage. */ public abstract double getDamage(); + /** Returns the maximum flight time in ticks before this projectile disappears, or -1 if it can continue + * indefinitely until it hits something. This should be constant. */ + public abstract int getLifetime(); + /** Override this to specify the damage type dealt. Defaults to {@link DamageType#MAGIC}. */ public DamageType getDamageType(){ return DamageType.MAGIC; @@ -167,6 +177,16 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE return false; } + /** + * Returns the seeking strength of this projectile, or the maximum distance from a target the projectile can be + * heading for that will make it curve towards that target. By default, this is 2 if the caster is wearing a ring + * of attraction, otherwise it is 0. + */ + public float getSeekingStrength(){ + return getCaster() instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)getCaster(), + WizardryItems.ring_seeking) ? 2 : 0; + } + // Setters and getters /** Sets the amount of knockback the projectile applies when it hits a mob. */ @@ -184,7 +204,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE } public void setCaster(EntityLivingBase entity){ - caster = new WeakReference(entity); + caster = new WeakReference<>(entity); } // Methods triggered during the update cycle @@ -211,10 +231,15 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE super.onUpdate(); + // Projectile disappears after its lifetime (if it has one) has elapsed + if(getLifetime() >=0 && this.ticksExisted > getLifetime()){ + this.setDead(); + } + if(this.getCaster() == null && this.casterUUID != null){ Entity entity = WizardryUtilities.getEntityByUUID(world, casterUUID); if(entity instanceof EntityLivingBase){ - this.caster = new WeakReference((EntityLivingBase)entity); + this.caster = new WeakReference<>((EntityLivingBase)entity); } } @@ -323,8 +348,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE if(this.getCaster() == null){ damagesource = DamageSource.causeThrownDamage(this, this); }else{ - damagesource = MagicDamage.causeIndirectMagicDamage(this, - (EntityLivingBase)this.getCaster(), this.getDamageType()).setProjectile(); + damagesource = MagicDamage.causeIndirectMagicDamage(this, this.getCaster(), this.getDamageType()).setProjectile(); } if(raytraceresult.entityHit.attackEntityFrom(damagesource, @@ -347,11 +371,9 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE } // Thorns enchantment - if(this.getCaster() != null - && this.getCaster() instanceof EntityLivingBase){ + if(this.getCaster() != null){ EnchantmentHelper.applyThornEnchantments(entityHit, this.getCaster()); - EnchantmentHelper.applyArthropodEnchantments((EntityLivingBase)this.getCaster(), - entityHit); + EnchantmentHelper.applyArthropodEnchantments(this.getCaster(), entityHit); } if(this.getCaster() != null && raytraceresult.entityHit != this.getCaster() @@ -401,6 +423,29 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE } } + // Seeking + if(getSeekingStrength() > 0){ + + Vec3d velocity = new Vec3d(motionX, motionY, motionZ); + + RayTraceResult hit = RayTracer.rayTrace(world, this.getPositionVector(), + this.getPositionVector().add(velocity.scale(SEEKING_TIME)), getSeekingStrength(), false, + true, false, EntityLivingBase.class, RayTracer.ignoreEntityFilter(null)); + + if(hit != null && hit.entityHit != null){ + + if(AllyDesignationSystem.isValidTarget(getCaster(), hit.entityHit)){ + + Vec3d direction = new Vec3d(hit.entityHit.posX, hit.entityHit.posY + hit.entityHit.height/2, + hit.entityHit.posZ).subtract(this.getPositionVector()).normalize().scale(velocity.length()); + + motionX = motionX + 2 * (direction.x - motionX) / SEEKING_TIME; + motionY = motionY + 2 * (direction.y - motionY) / SEEKING_TIME; + motionZ = motionZ + 2 * (direction.z - motionZ) / SEEKING_TIME; + } + } + } + this.posX += this.motionX; this.posY += this.motionY; this.posZ += this.motionZ; @@ -510,8 +555,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE tag.setShort("zTile", (short)this.blockZ); tag.setShort("life", (short)this.ticksInGround); if(this.stuckInBlock != null){ - ResourceLocation resourcelocation = (ResourceLocation)Block.REGISTRY - .getNameForObject(this.stuckInBlock.getBlock()); + ResourceLocation resourcelocation = Block.REGISTRY.getNameForObject(this.stuckInBlock.getBlock()); tag.setString("inTile", resourcelocation == null ? "" : resourcelocation.toString()); } tag.setByte("inData", (byte)this.inData); @@ -529,7 +573,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE this.blockY = tag.getShort("yTile"); this.blockZ = tag.getShort("zTile"); this.ticksInGround = tag.getShort("life"); - // Commented out for now because there's some funny stuff going on with blockstates and metadata. + // Commented out for now because there's some funny stuff going on with blockstates and id. // this.stuckInBlock = Block.getBlockById(tag.getByte("inTile") & 255); this.inData = tag.getByte("inData") & 255; this.arrowShake = tag.getByte("shake") & 255; @@ -545,7 +589,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE @Override public void readSpawnData(ByteBuf buffer){ - if(buffer.isReadable()) this.caster = new WeakReference( + if(buffer.isReadable()) this.caster = new WeakReference<>( (EntityLivingBase)this.world.getEntityByID(buffer.readInt())); } @@ -565,6 +609,11 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE public float getShadowSize(){ return 0.0F; } + + @Override + public SoundCategory getSoundCategory(){ + return WizardrySounds.SPELLS; + } @Override protected void entityInit(){} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicFireball.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicFireball.java new file mode 100644 index 00000000..0089966a --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicFireball.java @@ -0,0 +1,198 @@ +package electroblob.wizardry.entity.projectile; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.projectile.EntitySmallFireball; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +/** + * It's a fireball - but unlike vanilla fireballs, it actually looks like a fireball, and isn't completely useless for + * attacking things (acceleration from stationary? Really, Mojang? No wonder I had so many blaze rods back in the day...) + */ +@Mod.EventBusSubscriber +public class EntityMagicFireball extends EntityMagicProjectile { + + protected static final int ACCELERATION_CONVERSION_FACTOR = 10; + + /** The damage dealt by this fireball. If this is -1, the damage for the fireball spell will be used instead; + * this is for when the fireball is not from a spell (i.e. a vanilla fireball replacement). */ + protected float damage = -1; + /** The number of seconds entities are set on fire by this fireball. If this is -1, the damage for the fireball + * spell will be used instead; this is for when the fireball is not from a spell (i.e. a vanilla fireball replacement). */ + protected int burnDuration = -1; + /** The lifetime of this fireball in ticks. This needs to be stored so that it can be changed for vanilla replacements, + * or mobs that shoot fireballs would have severely reduced range! */ + protected int lifetime = 16; + + public EntityMagicFireball(World world){ + super(world); + this.setSize(0.5f, 0.5f); + } + + public void setDamage(float damage){ + this.damage = damage; + } + + public void setBurnDuration(int burnDuration){ + this.burnDuration = burnDuration; + } + + public float getDamage(){ + // I'm lazy, I'd rather not have an entire fireball spell class just to set two fields on the entity + return damage == -1 ? Spells.fireball.getProperty(Spell.DAMAGE).floatValue() : damage; + } + + public int getBurnDuration(){ + return burnDuration == -1 ? Spells.fireball.getProperty(Spell.BURN_DURATION).intValue() : burnDuration; + } + + @Override + protected void onImpact(RayTraceResult rayTrace){ + + if(!world.isRemote){ + + Entity entityHit = rayTrace.entityHit; + + if(entityHit != null){ + + float damage = getDamage() * damageMultiplier; + + entityHit.attackEntityFrom( + MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(), + damage); + + if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit) && getBurnDuration() > 0) + entityHit.setFire(getBurnDuration()); + + }else{ + + boolean flag = true; + + if(this.getThrower() != null && this.getThrower() instanceof EntityLiving){ + flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.getThrower()); + } + + if(flag){ + + BlockPos blockpos = rayTrace.getBlockPos().offset(rayTrace.sideHit); + + if(this.world.isAirBlock(blockpos)){ + this.world.setBlockState(blockpos, Blocks.FIRE.getDefaultState()); + } + } + } + + //this.playSound(WizardrySounds.ENTITY_MAGIC_FIREBALL_HIT, 2, 0.8f + rand.nextFloat() * 0.3f); + + this.setDead(); + } + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(world.isRemote){ + + for(int i=0; i<5; i++){ + + double dx = (rand.nextDouble() - 0.5) * width; + double dy = (rand.nextDouble() - 0.5) * height + this.height/2 - 0.1; // -0.1 because flames aren't centred + double dz = (rand.nextDouble() - 0.5) * width; + double v = 0.06; + ParticleBuilder.create(ParticleBuilder.Type.MAGIC_FIRE) + .pos(this.getPositionVector().add(dx - this.motionX/2, dy, dz - this.motionZ/2)) + .vel(-v * dx, -v * dy, -v * dz).scale(width*2).time(10).spawn(world); + + if(ticksExisted > 1){ + dx = (rand.nextDouble() - 0.5) * width; + dy = (rand.nextDouble() - 0.5) * height + this.height / 2 - 0.1; + dz = (rand.nextDouble() - 0.5) * width; + ParticleBuilder.create(ParticleBuilder.Type.MAGIC_FIRE) + .pos(this.getPositionVector().add(dx - this.motionX, dy, dz - this.motionZ)) + .vel(-v * dx, -v * dy, -v * dz).scale(width*2).time(10).spawn(world); + } + } + } + } + + public void setLifetime(int lifetime){ + this.lifetime = lifetime; + } + + @Override + public int getLifetime(){ + return lifetime; + } + + @Override + public boolean hasNoGravity(){ + return true; + } + + @Override + public boolean canRenderOnFire(){ + return false; + } + + @Override + public void writeSpawnData(ByteBuf buffer){ + buffer.writeInt(lifetime); + super.writeSpawnData(buffer); + } + + @Override + public void readSpawnData(ByteBuf buffer){ + lifetime = buffer.readInt(); + super.readSpawnData(buffer); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound){ + super.readEntityFromNBT(nbttagcompound); + lifetime = nbttagcompound.getInteger("lifetime"); + } + + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound){ + super.writeEntityToNBT(nbttagcompound); + nbttagcompound.setInteger("lifetime", lifetime); + } + + @SubscribeEvent + public static void onEntityJoinWorldEvent(EntityJoinWorldEvent event){ + // Replaces all vanilla fireballs with wizardry ones + if(Wizardry.settings.replaceVanillaFireballs && event.getEntity() instanceof EntitySmallFireball){ + + event.setCanceled(true); + + EntityMagicFireball fireball = new EntityMagicFireball(event.getWorld()); + fireball.thrower = ((EntitySmallFireball)event.getEntity()).shootingEntity; + fireball.setPosition(event.getEntity().posX, event.getEntity().posY, event.getEntity().posZ); + fireball.setDamage(5); + fireball.setBurnDuration(5); + fireball.setLifetime(40); + + fireball.motionX = ((EntitySmallFireball)event.getEntity()).accelerationX * ACCELERATION_CONVERSION_FACTOR; + fireball.motionY = ((EntitySmallFireball)event.getEntity()).accelerationY * ACCELERATION_CONVERSION_FACTOR; + fireball.motionZ = ((EntitySmallFireball)event.getEntity()).accelerationZ * ACCELERATION_CONVERSION_FACTOR; + + event.getWorld().spawnEntity(fireball); + } + } +} diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java index 676ba719..9649b84a 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java @@ -1,24 +1,25 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class EntityMagicMissile extends EntityMagicArrow { - - /** The number of ticks the magic missile flies for before vanishing; effectively determines its range. */ - private static final int LIFETIME = 12; /** Creates a new magic missile in the given world. */ public EntityMagicMissile(World world){ super(world); } - @Override public double getDamage(){ return 4; } + @Override public double getDamage(){ return Spells.magic_missile.getProperty(Spell.DAMAGE).floatValue(); } + + @Override public int getLifetime(){ return 12; } @Override public boolean doGravity(){ return false; } @@ -26,8 +27,8 @@ public class EntityMagicMissile extends EntityMagicArrow { @Override public void onEntityHit(EntityLivingBase entityHit){ - this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); - if(this.world.isRemote) spawnImpactParticles(); + this.playSound(WizardrySounds.ENTITY_MAGIC_MISSILE_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + if(this.world.isRemote) ParticleBuilder.create(Type.FLASH).pos(posX, posY, posZ).clr(1, 1, 0.65f).spawn(world); } @Override @@ -42,10 +43,6 @@ public class EntityMagicMissile extends EntityMagicArrow { @Override public void tickInAir(){ - if(this.ticksExisted > LIFETIME){ - this.setDead(); - } - if(this.world.isRemote){ ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1) .time(20 + rand.nextInt(10)).spawn(world); diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java index 93e5b9ef..3246d818 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicProjectile.java @@ -1,11 +1,20 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.AllyDesignationSystem; +import electroblob.wizardry.util.RayTracer; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntityThrowable; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.SoundCategory; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; @@ -13,7 +22,7 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; * This class is a generic superclass for all non-directed projectiles, namely: darkness orb, firebolt, firebomb, * force orb, ice charge, lightning disc, poison bomb, spark, spark bomb and thunderbolt. Directed (arrow-like) * projectiles should instead extend {@link EntityMagicArrow}. - *

    + *

    * This class purely handles saving of the damage multiplier; EntityThrowable is pretty well suited to my purposes as it * is. Range is done via the velocity when the constructor is called. Caster is already handled by * EntityThrowable.getThrower(), though due to a bug in vanilla it has to be synced by this class. @@ -24,6 +33,9 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; */ public abstract class EntityMagicProjectile extends EntityThrowable implements IEntityAdditionalSpawnData { + public static final double LAUNCH_Y_OFFSET = 0.1; + public static final int SEEKING_TIME = 15; + public float damageMultiplier = 1.0f; /** Creates a new projectile in the given world. */ @@ -33,10 +45,10 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I // Initialiser methods - /** Sets the shooter of the projectile to the given caster, positions the projctile at the given caster's eyes and + /** Sets the shooter of the projectile to the given caster, positions the projectile at the given caster's eyes and * aims it in the direction they are looking with the given speed. */ public void aim(EntityLivingBase caster, float speed){ - this.setPosition(caster.posX, caster.posY + (double)caster.getEyeHeight() - 0.1d, caster.posZ); + this.setPosition(caster.posX, caster.getEntityBoundingBox().minY + (double)caster.getEyeHeight() - LAUNCH_Y_OFFSET, caster.posZ); // This is the standard set of parameters for this method, used by snowballs and ender pearls amongst others. this.shoot(caster, caster.rotationPitch, caster.rotationYaw, 0.0f, speed, 1.0f); this.thrower = caster; @@ -44,7 +56,7 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I this.ignoreEntity = caster; } - /** Sets the shooter of the projectile to the given caster, positions the projctile at the given caster's eyes and + /** Sets the shooter of the projectile to the given caster, positions the projectile at the given caster's eyes and * aims it at the given target with the given speed. The trajectory will be altered slightly by a random amount * determined by the aimingError parameter. For reference, skeletons set this to 10 on easy, 6 on normal and 2 on hard * difficulty. */ @@ -54,7 +66,7 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I // Mojang's 'fix' for the projectile-hitting-thrower bug actually made the problem worse, hence the following line. this.ignoreEntity = thrower; - this.posY = caster.posY + (double)caster.getEyeHeight() - 0.1d; + this.posY = caster.getEntityBoundingBox().minY + (double)caster.getEyeHeight() - LAUNCH_Y_OFFSET; double dx = target.posX - caster.posX; double dy = !this.hasNoGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0f) - this.posY : target.getEntityBoundingBox().minY + (double)(target.height / 2.0f) - this.posY; @@ -75,6 +87,54 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I } } + public void setCaster(EntityLivingBase caster){ + this.thrower = caster; + this.ignoreEntity = caster; + } + + /** + * Returns the seeking strength of this projectile, or the maximum distance from a target the projectile can be + * heading for that will make it curve towards that target. By default, this is 2 if the caster is wearing a ring + * of attraction, otherwise it is 0. + */ + public float getSeekingStrength(){ + return getThrower() instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)getThrower(), + WizardryItems.ring_seeking) ? 2 : 0; + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + if(getLifetime() >=0 && this.ticksExisted > getLifetime()){ + this.setDead(); + } + + // Seeking + if(getSeekingStrength() > 0){ + + Vec3d velocity = new Vec3d(motionX, motionY, motionZ); + + RayTraceResult hit = RayTracer.rayTrace(world, this.getPositionVector(), + this.getPositionVector().add(velocity.scale(SEEKING_TIME)), getSeekingStrength(), false, + true, false, EntityLivingBase.class, RayTracer.ignoreEntityFilter(null)); + + if(hit != null && hit.entityHit != null){ + + if(AllyDesignationSystem.isValidTarget(getThrower(), hit.entityHit)){ + + Vec3d direction = new Vec3d(hit.entityHit.posX, hit.entityHit.posY + hit.entityHit.height/2, + hit.entityHit.posZ).subtract(this.getPositionVector()).normalize().scale(velocity.length()); + + motionX = motionX + 2 * (direction.x - motionX) / SEEKING_TIME; + motionY = motionY + 2 * (direction.y - motionY) / SEEKING_TIME; + motionZ = motionZ + 2 * (direction.z - motionZ) / SEEKING_TIME; + } + } + } + } + @Override public void readEntityFromNBT(NBTTagCompound nbttagcompound){ super.readEntityFromNBT(nbttagcompound); @@ -88,20 +148,26 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I } @Override - // For now, we're only writing when the thrower exists, so subclasses MUST CALL SUPER LAST. - // TODO: Figure out whether there's a default value we can write that is never used as an entity id (0? -1? +/-MAX_VALUE?) public void writeSpawnData(ByteBuf data){ - if(this.getThrower() != null) data.writeInt(this.getThrower().getEntityId()); + data.writeInt(this.getThrower() == null ? -1 : this.getThrower().getEntityId()); } @Override - // For now, we're only writing when the thrower exists, so subclasses MUST CALL SUPER LAST. public void readSpawnData(ByteBuf data){ - if(data.isReadable()){ - Entity entity = this.world.getEntityByID(data.readInt()); - if(entity instanceof EntityLivingBase) this.thrower = (EntityLivingBase)entity; - this.ignoreEntity = this.thrower; - } + int id = data.readInt(); + if(id == -1) return; + Entity entity = this.world.getEntityByID(id); + if(entity instanceof EntityLivingBase) this.thrower = (EntityLivingBase)entity; + this.ignoreEntity = this.thrower; + } + + @Override + public SoundCategory getSoundCategory(){ + return WizardrySounds.SPELLS; } + /** Returns the maximum flight time in ticks before this projectile disappears, or -1 if it can continue + * indefinitely until it hits something. This should be constant. */ + public abstract int getLifetime(); + } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java index 5dfd2f8e..286e7259 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java @@ -1,7 +1,8 @@ package electroblob.wizardry.entity.projectile; -import java.util.List; - +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -10,18 +11,24 @@ import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import java.util.List; + public class EntityPoisonBomb extends EntityBomb { public EntityPoisonBomb(World world){ super(world); } - + + @Override + public int getLifetime(){ + return -1; + } + @Override protected void onImpact(RayTraceResult rayTrace){ @@ -29,14 +36,16 @@ public class EntityPoisonBomb extends EntityBomb { if(entityHit != null){ // This is if the poison bomb gets a direct hit - float damage = 5 * damageMultiplier; + float damage = Spells.poison_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier; entityHit.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.POISON).setProjectile(), damage); if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.POISON, entityHit)) - ((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(MobEffects.POISON, 120, 1)); + ((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(MobEffects.POISON, + Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_DURATION).intValue(), + Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_STRENGTH).intValue())); } // Particle effect @@ -48,7 +57,7 @@ public class EntityPoisonBomb extends EntityBomb { for(int i = 0; i < 60 * blastMultiplier; i++){ ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).time(35) - .clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); + .scale(2).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) .clr(0.2f + rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world); @@ -60,10 +69,10 @@ public class EntityPoisonBomb extends EntityBomb { if(!this.world.isRemote){ - this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.5F, rand.nextFloat() * 0.4F + 0.6F); - this.playSound(SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.2F, 1.0f); + this.playSound(WizardrySounds.ENTITY_POISON_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F); + this.playSound(WizardrySounds.ENTITY_POISON_BOMB_POISON, 1.2F, 1.0f); - double range = 3.0d * blastMultiplier; + double range = Spells.poison_bomb.getProperty(Spell.EFFECT_RADIUS).floatValue() * blastMultiplier; List targets = WizardryUtilities.getEntitiesWithinRadius(range, this.posX, this.posY, this.posZ, this.world); @@ -73,8 +82,10 @@ public class EntityPoisonBomb extends EntityBomb { && !MagicDamage.isEntityImmune(DamageType.POISON, target)){ target.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.POISON), - 4.0f * damageMultiplier); - target.addPotionEffect(new PotionEffect(MobEffects.POISON, 100, 1)); + Spells.poison_bomb.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier); + target.addPotionEffect(new PotionEffect(MobEffects.POISON, + Spells.poison_bomb.getProperty(Spell.SPLASH_EFFECT_DURATION).intValue(), + Spells.poison_bomb.getProperty(Spell.SPLASH_EFFECT_STRENGTH).intValue())); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java index e19592a6..cbdb5315 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java @@ -1,8 +1,9 @@ package electroblob.wizardry.entity.projectile; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; @@ -10,18 +11,24 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import java.util.List; + public class EntitySmokeBomb extends EntityBomb { public EntitySmokeBomb(World world){ super(world); } + @Override + public int getLifetime(){ + return -1; + } + @Override protected void onImpact(RayTraceResult rayTrace){ @@ -47,25 +54,26 @@ public class EntitySmokeBomb extends EntityBomb { if(!this.world.isRemote){ - this.playSound(SoundEvents.ENTITY_SPLASH_POTION_BREAK, 1.5F, rand.nextFloat() * 0.4F + 0.6F); - this.playSound(SoundEvents.BLOCK_FIRE_EXTINGUISH, 1.2F, 1.0f); + this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F); + this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMOKE, 1.2F, 1.0f); - double range = 3.0d * blastMultiplier; + double range = Spells.smoke_bomb.getProperty(Spell.BLAST_RADIUS).floatValue() * blastMultiplier; List targets = WizardryUtilities.getEntitiesWithinRadius(range, this.posX, this.posY, this.posZ, this.world); + int duration = Spells.smoke_bomb.getProperty(Spell.EFFECT_DURATION).intValue(); + for(EntityLivingBase target : targets){ if(target != this.getThrower()){ // Gives the target blindness if it is a player, mind trick otherwise (since this has the desired // effect of preventing targeting) if(target instanceof EntityPlayer){ - target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 120, 0)); + target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0)); }else if(target instanceof EntityLiving){ // New AI ((EntityLiving)target).setAttackTarget(null); - - target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, 120, 0)); + target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, duration, 0)); } } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java index f4aed2bc..93d1d756 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySpark.java @@ -1,15 +1,13 @@ package electroblob.wizardry.entity.projectile; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; @@ -26,13 +24,13 @@ public class EntitySpark extends EntityMagicProjectile { if(entityHit != null){ - float damage = 6 * damageMultiplier; - entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK), - damage); + float damage = Spells.homing_spark.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; + entityHit.attackEntityFrom(MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), + DamageType.SHOCK), damage); } - this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + this.playSound(WizardrySounds.ENTITY_HOMING_SPARK_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); // Particle effect if(world.isRemote){ @@ -47,40 +45,16 @@ public class EntitySpark extends EntityMagicProjectile { this.setDead(); } - public void onUpdate(){ - - super.onUpdate(); - - if(!this.collided && !world.isRemote){ - - double seekingRange = 5.0d; - - List entities = WizardryUtilities.getEntitiesWithinRadius(seekingRange, this.posX, - this.posY, this.posZ, this.world); - Entity target = null; - - for(Entity possibleTarget : entities){ - // Decides if current entity should be replaced. - if(target == null || this.getDistance(target) > this.getDistance(possibleTarget)){ - // Decides if new entity is a valid target. - if(WizardryUtilities.isValidTarget(this.getThrower(), possibleTarget)){ - target = possibleTarget; - } - } - } - - if(target != null && Math.abs(this.motionX) < 1 && Math.abs(this.motionY) < 1 - && Math.abs(this.motionZ) < 1){ - this.addVelocity((target.posX - this.posX) / 30, (target.posY + target.height / 2 - this.posY) / 30, - (target.posZ - this.posZ) / 30); - } - } - - if(this.ticksExisted > 100){ - this.setDead(); - } + @Override + public float getSeekingStrength(){ + return Spells.homing_spark.getProperty(Spell.SEEKING_STRENGTH).floatValue(); } - + + @Override + public int getLifetime(){ + return 50; + } + @Override public boolean hasNoGravity(){ return true; diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java index 28ddbf8a..721a06a2 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java @@ -1,8 +1,8 @@ package electroblob.wizardry.entity.projectile; -import java.util.List; - +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -11,28 +11,36 @@ import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; +import java.util.List; + public class EntitySparkBomb extends EntityBomb { + public static final String SECONDARY_MAX_TARGETS = "secondary_max_targets"; + public EntitySparkBomb(World world){ super(world); } + @Override + public int getLifetime(){ + return -1; + } + @Override protected void onImpact(RayTraceResult rayTrace){ - this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST_FAR, 0.5f, 0.5f); + this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT_BLOCK, 0.5f, 0.5f); Entity entityHit = rayTrace.entityHit; if(entityHit != null){ // This is if the spark bomb gets a direct hit - float damage = 6 * damageMultiplier; + float damage = Spells.spark_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier; - this.playSound(SoundEvents.ENTITY_GENERIC_HURT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); + this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); entityHit.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(), @@ -45,19 +53,19 @@ public class EntitySparkBomb extends EntityBomb { ParticleBuilder.spawnShockParticles(world, posX, posY + height/2, posZ); } - double seekerRange = 5.0d * blastMultiplier; + double seekerRange = Spells.spark_bomb.getProperty(Spell.EFFECT_RADIUS).doubleValue() * blastMultiplier; List targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX, this.posY, this.posZ, this.world); - for(int i = 0; i < Math.min(targets.size(), 4); i++){ + for(int i = 0; i < Math.min(targets.size(), Spells.spark_bomb.getProperty(SECONDARY_MAX_TARGETS).intValue()); i++){ boolean flag = targets.get(i) != entityHit && targets.get(i) != this.getThrower() && !(targets.get(i) instanceof EntityPlayer - && ((EntityPlayer)targets.get(i)).capabilities.isCreativeMode); + && ((EntityPlayer)targets.get(i)).isCreative()); // Detects (client side) if target is the thrower, to stop particles being spawned around them. - //if(flag && world.isRemote && targets.get(i).getEntityId() == this.casterID) flag = false; + //if(flag && world.isRemote && targets.get(i).getEntityId() == this.playerID) flag = false; if(flag){ @@ -69,7 +77,7 @@ public class EntitySparkBomb extends EntityBomb { target.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK), - 5.0f * damageMultiplier); + Spells.spark_bomb.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier); }else{ ParticleBuilder.create(Type.LIGHTNING).pos(this.getPositionVector()).target(target).spawn(world); diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java index 7508b150..48e90dd8 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityThunderbolt.java @@ -1,17 +1,21 @@ package electroblob.wizardry.entity.projectile; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; -import net.minecraft.init.SoundEvents; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; public class EntityThunderbolt extends EntityMagicProjectile { + public static final String KNOCKBACK_STRENGTH = "knockback_strength"; + public EntityThunderbolt(World par1World){ super(par1World); } @@ -27,17 +31,19 @@ public class EntityThunderbolt extends EntityMagicProjectile { if(entityHit != null){ - float damage = 3 * damageMultiplier; + float damage = Spells.thunderbolt.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier; entityHit.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(), damage); + float knockbackStrength = Spells.thunderbolt.getProperty(KNOCKBACK_STRENGTH).floatValue(); + // Knockback - entityHit.addVelocity(this.motionX * 0.2, this.motionY * 0.2, this.motionZ * 0.2); + entityHit.addVelocity(this.motionX * knockbackStrength, this.motionY * knockbackStrength, this.motionZ * knockbackStrength); } - this.playSound(SoundEvents.ENTITY_FIREWORK_LARGE_BLAST, 1.4F, 0.5f + this.rand.nextFloat() * 0.1F); + this.playSound(WizardrySounds.ENTITY_THUNDERBOLT_HIT, 1.4F, 0.5f + this.rand.nextFloat() * 0.1F); // Particle effect if(world.isRemote){ @@ -60,10 +66,11 @@ public class EntityThunderbolt extends EntityMagicProjectile { this.posZ + rand.nextFloat() * 0.2 - 0.1, 0, 0, 0); } } - - if(this.ticksExisted > 8){ - this.setDead(); - } } - + + @Override + public int getLifetime(){ + return 8; + } + } diff --git a/src/main/java/electroblob/wizardry/event/DiscoverSpellEvent.java b/src/main/java/electroblob/wizardry/event/DiscoverSpellEvent.java index 8e22c499..79fb9916 100644 --- a/src/main/java/electroblob/wizardry/event/DiscoverSpellEvent.java +++ b/src/main/java/electroblob/wizardry/event/DiscoverSpellEvent.java @@ -6,6 +6,8 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.fml.common.eventhandler.Cancelable; +import javax.annotation.Nullable; + /** * DiscoverSpellEvent is fired when a player discovers a spell by any method.
    *
    @@ -41,13 +43,30 @@ public class DiscoverSpellEvent extends PlayerEvent { public enum Source { /** Signifies that the spell was discovered by trying to cast it. */ - CASTING, + CASTING("casting"), /** Signifies that the spell was discovered using a scroll of identification. */ - IDENTIFICATION_SCROLL, + IDENTIFICATION_SCROLL("identification_scroll"), /** Signifies that the spell was discovered using commands. */ - COMMAND, + COMMAND("command"), + /** Signifies that the spell was discovered by purchasing it from a wizard. */ + PURCHASE("purchase"), /** Signifies that the spell was discovered by some other means. */ - OTHER + OTHER("other"); + + String name; + + Source(String name){ + this.name = name; + } + + /** Returns the spell discovery source with the given name, or null if no such source exists. */ + @Nullable + public static Source byName(String name){ + for(Source source : values()){ + if(source.name.equals(name)) return source; + } + return null; + } } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/event/SpellCastEvent.java b/src/main/java/electroblob/wizardry/event/SpellCastEvent.java index 3cd0a88e..ec471598 100644 --- a/src/main/java/electroblob/wizardry/event/SpellCastEvent.java +++ b/src/main/java/electroblob/wizardry/event/SpellCastEvent.java @@ -1,34 +1,71 @@ package electroblob.wizardry.event; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.entity.living.ISpellCaster; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.fml.common.eventhandler.Cancelable; +import net.minecraftforge.fml.common.eventhandler.Event; + +import javax.annotation.Nullable; /** * SpellCastEvent is the parent event class for all spell casting events. Methods which subscribe to this event will - * receive all three child events (it is recommended that you use {@link SpellCastEvent.Pre}, - * {@link SpellCastEvent.Post} or {@link SpellCastEvent.Tick}, depending on the application).
    + * receive all four child events (it is recommended that you use {@link SpellCastEvent.Pre}, + * {@link SpellCastEvent.Post}, {@link SpellCastEvent.Tick} or {@link SpellCastEvent.Finish}, depending on the application).
    *
    + * A note about spell modifiers: As of Wizardry 4.2, item-based spell casting has been reorganised, a notable change + * being that spell modifiers are no longer recalculated each tick for continuous spells. Instead, spell modifiers + * are stored in {@link WizardData WizardData} at the start (after {@code SpellCastEvent.Pre}) + * and simply passed in each tick. This means the {@code SpellModifiers} object received by {@code SpellCastEvent.Tick} + * contains those modified values, and any changes made to them will not persist between ticks. + *

    + * This means that where before you had to change the modifiers in {@code Pre} and {@code Tick}, you now only + * need to change them in {@code Pre} unless you want them to change partway through casting.
    + *

    * This event is fired on the {@link MinecraftForge#EVENT_BUS}. * * @author Electroblob * @since Wizardry 2.1 */ -public abstract class SpellCastEvent extends LivingEvent { +public abstract class SpellCastEvent extends Event { private final Spell spell; private final SpellModifiers modifiers; private final Source source; + private final EntityLivingBase caster; + private final World world; + private final double x, y, z; + private final EnumFacing direction; - public SpellCastEvent(EntityLivingBase caster, Spell spell, SpellModifiers modifiers, Source source){ - super(caster); + public SpellCastEvent(Source source, Spell spell, EntityLivingBase caster, SpellModifiers modifiers){ + super(); this.spell = spell; this.modifiers = modifiers; this.source = source; + this.caster = caster; + this.world = caster.world; // World is required for the position-based casting, but we may as well set it here + this.x = Double.NaN; // Better to use NaN than some arbitrary number, because NaN will throw an exception when + this.y = Double.NaN; // someone tries to operate on it whereas 0, for example, will likely just cause strange + this.z = Double.NaN; // behaviour - the cause of which may not be immediately obvious. + this.direction = null; + } + + public SpellCastEvent(Source source, Spell spell, World world, double x, double y, double z, EnumFacing direction, SpellModifiers modifiers){ + super(); + this.spell = spell; + this.modifiers = modifiers; + this.source = source; + this.caster = null; + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.direction = direction; } /** Returns the spell being cast. */ @@ -45,6 +82,39 @@ public abstract class SpellCastEvent extends LivingEvent { public Source getSource(){ return source; } + + /** Returns the entity that cast this spell, or null if it was cast from a dispenser or a command with coordinates. */ + @Nullable + public EntityLivingBase getCaster(){ + return caster; + } + + /** Returns the world in which this spell was cast. If the spell was cast by an entity, this is equivalent to + * {@code getCaster().world}. */ + public World getWorld(){ + return world; + } + + /** Returns the x coordinate at which this spell was cast, or NaN if the spell was not cast from a position. */ + public double getX(){ + return x; + } + + /** Returns the y coordinate at which this spell was cast, or NaN if the spell was not cast from a position. */ + public double getY(){ + return y; + } + + /** Returns the z coordinate at which this spell was cast, or NaN if the spell was not cast from a position. */ + public double getZ(){ + return z; + } + + /** Returns the direction in which this spell was cast, or null if the spell was not cast from a position. */ + @Nullable + public EnumFacing getDirection(){ + return direction; + } public enum Source { /** Signifies that the spell was cast using a wand. */ @@ -55,6 +125,8 @@ public abstract class SpellCastEvent extends LivingEvent { COMMAND, /** Signifies that the spell was cast by an {@link ISpellCaster}. */ NPC, + /** Signifies that the spell was cast from a dispenser. */ + DISPENSER, /** Signifies that the spell was cast by some other means. */ OTHER } @@ -70,6 +142,13 @@ public abstract class SpellCastEvent extends LivingEvent { * right-click action that caused it (if any) returns a result of FAIL, meaning that the right-click is passed to * the block/entity in front of the player, if any.
    *
    + * Priority convention for {@code SpellCastEvent.Pre}:
    + * {@code HIGHEST} - General spell prevention e.g. arcane jammer
    + * {@code HIGH} - Specific spell prevention e.g. spells disabled in config/JSONs
    + * {@code NORMAL} - Everything else e.g. forfeits
    + * {@code LOW} - Changes to modifiers e.g. from potion effects
    + * {@code LOWEST} - Anything that requires modifiers to be at their final values, unused in wizardry
    + *
    * This event does not have a result. {@link HasResult}
    *
    * This event is fired on the {@link MinecraftForge#EVENT_BUS}. @@ -80,10 +159,13 @@ public abstract class SpellCastEvent extends LivingEvent { @Cancelable public static class Pre extends SpellCastEvent { - public Pre(EntityLivingBase caster, Spell spell, SpellModifiers modifiers, Source source){ - super(caster, spell, modifiers, source); + public Pre(Source source, Spell spell, EntityLivingBase caster, SpellModifiers modifiers){ + super(source, spell, caster, modifiers); + } + + public Pre(Source source, Spell spell, World world, double x, double y, double z, EnumFacing direction, SpellModifiers modifiers){ + super(source, spell, world, x, y, z, direction, modifiers); } - } /** @@ -91,7 +173,8 @@ public abstract class SpellCastEvent extends LivingEvent { * whether the spell succeeds, and does not affect the spell itself. For example, wizardry uses this event to keep * track of spellcasting stats. Note that although this event is fired from both sides, it is not fired from common * code; rather, both sides fire it separately, so timing is not guaranteed. Also note that this event is only fired - * once for continuous spells, after the first casting tick.
    + * once for continuous spells, after the first casting tick. Changing the modifiers within this event will likely + * have no effect, with the exception of cooldown modifiers.
    *
    * This event is not {@link Cancelable}.
    *
    @@ -104,8 +187,12 @@ public abstract class SpellCastEvent extends LivingEvent { */ public static class Post extends SpellCastEvent { - public Post(EntityLivingBase caster, Spell spell, SpellModifiers modifiers, Source source){ - super(caster, spell, modifiers, source); + public Post(Source source, Spell spell, EntityLivingBase caster, SpellModifiers modifiers){ + super(source, spell, caster, modifiers); + } + + public Post(Source source, Spell spell, World world, double x, double y, double z, EnumFacing direction, SpellModifiers modifiers){ + super(source, spell, world, x, y, z, direction, modifiers); } } @@ -114,8 +201,9 @@ public abstract class SpellCastEvent extends LivingEvent { * SpellCastEvent.Tick is fired each tick while a continuous spell is being cast.
    *
    * This event is {@link Cancelable}. If this event is canceled, the spell is not cast, mana is not consumed, and the - * spell casting is interrupted. Cancelling this event on the client side will stop particles being spawned, but - * will not interrupt spell casting.
    + * spell casting is interrupted. Cancelling this event on the client side only will stop particles being spawned, but + * will not interrupt spell casting. Cancelling this event on the server side only may have different results + * depending on the source of the spell; as such it is recommended that this event is cancelled on both sides.
    *
    * This event does not have a result. {@link HasResult}
    *
    @@ -129,8 +217,13 @@ public abstract class SpellCastEvent extends LivingEvent { private final int count; - public Tick(EntityLivingBase caster, Spell spell, SpellModifiers modifiers, Source source, int count){ - super(caster, spell, modifiers, source); + public Tick(Source source, Spell spell, EntityLivingBase caster, SpellModifiers modifiers, int count){ + super(source, spell, caster, modifiers); + this.count = count; + } + + public Tick(Source source, Spell spell, World world, double x, double y, double z, EnumFacing direction, SpellModifiers modifiers, int count){ + super(source, spell, world, x, y, z, direction, modifiers); this.count = count; } @@ -141,4 +234,39 @@ public abstract class SpellCastEvent extends LivingEvent { } + /** + * SpellCastEvent.Finish is fired just after a continuous spell stops being cast. Use this event for anything + * that needs to know the total time for which a continuous spell has been cast, or should only happen when the + * spell finishes (as opposed to just after it starts, as in {@link Post}).
    + *
    + * This event is not {@link Cancelable}.
    + *
    + * This event does not have a result. {@link HasResult}
    + *
    + * This event is fired on the {@link MinecraftForge#EVENT_BUS}. + * + * @author Electroblob + * @since Wizardry 2.1 + */ + public static class Finish extends SpellCastEvent { + + private final int count; + + public Finish(Source source, Spell spell, EntityLivingBase caster, SpellModifiers modifiers, int count){ + super(source, spell, caster, modifiers); + this.count = count; + } + + public Finish(Source source, Spell spell, World world, double x, double y, double z, EnumFacing direction, SpellModifiers modifiers, int count){ + super(source, spell, world, x, y, z, direction, modifiers); + this.count = count; + } + + /** Returns the total number of ticks this (continuous) spell was cast for. */ + public int getCount(){ + return count; + } + + } + } diff --git a/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java b/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java index cb3ea34b..2bbfb421 100644 --- a/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java +++ b/src/main/java/electroblob/wizardry/integration/DamageSafetyChecker.java @@ -57,8 +57,8 @@ public final class DamageSafetyChecker { * This allows wizardry to request that users add it to the blacklist. * @param fallback The fallback damage source for when excessive looping is detected. This must not be the * same as the re-applied source, or this method is pointless! Usually it will be more general. - * @param knockback True to apply knockback as normal, false to use the knockback-free methods in WizardryUtilities. - * {@link WizardryUtilities#attackEntityWithoutKnockback(Entity, DamageSource, float)}. + * @param knockback True to apply knockback as normal, false to use the knockback-free methods in WizardryUtilities + * (see {@link WizardryUtilities#attackEntityWithoutKnockback(Entity, DamageSource, float)}). */ public static boolean attackEntitySafely(Entity target, DamageSource source, float damage, String originalSourceName, DamageSource fallback, boolean knockback){ @@ -67,6 +67,7 @@ public final class DamageSafetyChecker { if(originalSourceName.equals(sourceName)){ // Blacklist behaviour // Same as fallback behaviour, but without the log message + // No harm in still incrementing the counter attacksThisTick++; return knockback ? target.attackEntityFrom(fallback, damage) : WizardryUtilities.attackEntityWithoutKnockback(target, fallback, damage); @@ -99,8 +100,9 @@ public final class DamageSafetyChecker { /** * See {@link DamageSafetyChecker#attackEntitySafely(Entity, DamageSource, float, String, DamageSource, boolean)}. - * This version is for when the original source is used as a fallback, i.e. when a damage source is being replaced - * for technical reasons (e.g. summoned creatures) rather than as part of a game mechanic (e.g. shadow ward). + * This version is for when the source being replaced is used as a fallback, i.e. when a damage source is being + * replaced for technical reasons (e.g. summoned creatures) rather than as part of a game mechanic (e.g. shadow ward). + * This means that if excessive looping is detected, the code will work as if the event was never intercepted. */ public static boolean attackEntitySafely(Entity target, DamageSource source, float damage, DamageSource originalSource, boolean knockback){ return attackEntitySafely(target, source, damage, originalSource.getDamageType(), originalSource, knockback); @@ -122,9 +124,9 @@ public final class DamageSafetyChecker { boolean vanillaName = VANILLA_DAMAGE_NAMES.contains(originalSourceName); if(aborted){ - Wizardry.logger.warn("Entity attack excessive call limit exceeded, aborting entity damage entirely!"); + Wizardry.logger.warn("SoundLoopSpellEntity attack excessive call limit reached, aborting entity damage entirely!"); }else{ - Wizardry.logger.warn("Entity attack excessive call threshold exceeded, substituting for non-entity-based " + + Wizardry.logger.warn("SoundLoopSpellEntity attack excessive call threshold reached, substituting for non-entity-based " + "damage to avert a crash."); } diff --git a/src/main/java/electroblob/wizardry/integration/antiqueatlas/WizardryAntiqueAtlasIntegration.java b/src/main/java/electroblob/wizardry/integration/antiqueatlas/WizardryAntiqueAtlasIntegration.java new file mode 100644 index 00000000..8fb48157 --- /dev/null +++ b/src/main/java/electroblob/wizardry/integration/antiqueatlas/WizardryAntiqueAtlasIntegration.java @@ -0,0 +1,71 @@ +package electroblob.wizardry.integration.antiqueatlas; + +import electroblob.wizardry.Wizardry; +import hunternif.mc.atlas.api.AtlasAPI; +import hunternif.mc.atlas.registry.MarkerType; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.Loader; + +/** + * This class handles all of wizardry's integration with the Antique Atlas mod. This class contains only the code + * that requires Antique Atlas to be loaded in order to run. Conversely, all code that requires Antique Atlas to be + * loaded is located within this class or another class in the package {@code electroblob.wizardry.integration.antiqueatlas}. + * + * @since Wizardry 4.2 + * @author Electroblob + */ +public class WizardryAntiqueAtlasIntegration { + + public static final String ANTIQUE_ATLAS_MOD_ID = "antiqueatlas"; + + private static final ResourceLocation TOWER_MARKER = new ResourceLocation(Wizardry.MODID, "wizard_tower"); + private static final ResourceLocation SHRINE_MARKER = new ResourceLocation(Wizardry.MODID, "shrine"); + private static final ResourceLocation OBELISK_MARKER = new ResourceLocation(Wizardry.MODID, "obelisk"); + + private static boolean antiqueAtlasLoaded; + + public static void init(){ + antiqueAtlasLoaded = Loader.isModLoaded(ANTIQUE_ATLAS_MOD_ID); + Wizardry.proxy.registerAtlasMarkers(); // Needs routing through the proxies to make sure it's only client-side + } + + public static boolean enabled(){ + return Wizardry.settings.antiqueAtlasIntegration && antiqueAtlasLoaded; + } + + /** Places a global wizard tower marker in all antique atlases at the given coordinates in the given world if + * {@link electroblob.wizardry.Settings#autoTowerMarkers} is enabled. Server side only! */ + public static void markTower(World world, int x, int z){ + if(enabled() && Wizardry.settings.autoTowerMarkers){ + AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, TOWER_MARKER.toString(), "integration.antiqueatlas.marker." + TOWER_MARKER.toString(), x, z); + } + } + + /** Places a global obelisk marker in all antique atlases at the given coordinates in the given world if + * {@link electroblob.wizardry.Settings#autoObeliskMarkers} is enabled. Server side only! */ + public static void markObelisk(World world, int x, int z){ + if(enabled() && Wizardry.settings.autoObeliskMarkers){ + AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, OBELISK_MARKER.toString(), "integration.antiqueatlas.marker." + OBELISK_MARKER.toString(), x, z); + } + } + + /** Places a global shrine marker in all antique atlases at the given coordinates in the given world if + * {@link electroblob.wizardry.Settings#autoShrineMarkers} is enabled. Server side only! */ + public static void markShrine(World world, int x, int z){ + if(enabled() && Wizardry.settings.autoShrineMarkers){ + AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, SHRINE_MARKER.toString(), "integration.antiqueatlas.marker." + SHRINE_MARKER.toString(), x, z); + } + } + + /** Registers the marker icons with Antique Atlas. Client side only! */ + public static void registerMarkers(){ + + if(!enabled()) return; + + AtlasAPI.getMarkerAPI().registerMarker(new MarkerType(TOWER_MARKER, new ResourceLocation(Wizardry.MODID, "textures/integration/antiqueatlas/wizard_tower.png"))); + AtlasAPI.getMarkerAPI().registerMarker(new MarkerType(SHRINE_MARKER, new ResourceLocation(Wizardry.MODID, "textures/integration/antiqueatlas/shrine.png"))); + AtlasAPI.getMarkerAPI().registerMarker(new MarkerType(OBELISK_MARKER, new ResourceLocation(Wizardry.MODID, "textures/integration/antiqueatlas/obelisk.png"))); + } + +} diff --git a/src/main/java/electroblob/wizardry/integration/baubles/WizardryBaublesIntegration.java b/src/main/java/electroblob/wizardry/integration/baubles/WizardryBaublesIntegration.java new file mode 100644 index 00000000..11f56ce2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/integration/baubles/WizardryBaublesIntegration.java @@ -0,0 +1,110 @@ +package electroblob.wizardry.integration.baubles; + +import baubles.api.BaubleType; +import baubles.api.BaublesApi; +import baubles.api.IBauble; +import baubles.api.cap.BaublesCapabilities; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemArtefact; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.fml.common.Loader; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +/** + * This class handles all of wizardry's integration with the Baubles mod. This class contains only the code + * that requires Baubles to be loaded in order to run. Conversely, all code that requires Baubles to be loaded is + * located within this class or another class in the package {@code electroblob.wizardry.integration.baubles}. + * + * @since Wizardry 4.2 + * @author Electroblob + */ +public final class WizardryBaublesIntegration { + + public static final String BAUBLES_MOD_ID = "baubles"; + + private static final Map ARTEFACT_TYPE_MAP = new EnumMap<>(ItemArtefact.Type.class); + + private static boolean baublesLoaded; + + public static void init(){ + + baublesLoaded = Loader.isModLoaded(BAUBLES_MOD_ID); + + if(!enabled()) return; + + ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.RING, BaubleType.RING); + ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.AMULET, BaubleType.AMULET); + ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.CHARM, BaubleType.CHARM); + } + + public static boolean enabled(){ + return Wizardry.settings.baublesIntegration && baublesLoaded; + } + + // Wrappers for BaublesApi methods + + /** + * Return true if the given item is equipped in any bauble slot. + * @param player The player whose inventory is to be checked. + * @param item The item to check for. + * @return True if the given item is equipped in a bauble slot, false otherwise. + */ + public static boolean isBaubleEquipped(EntityPlayer player, Item item){ + return BaublesApi.isBaubleEquipped(player, item) >= 0; + } + + /** + * Returns a list of artefact stacks equipped of the given types. + * @param player The player whose inventory is to be checked. + * @param types Zero or more artefact types to check for. If omitted, searches for all types. + * @return A list of equipped artefact {@code ItemStacks}. + */ + // This could return all ItemStacks, but if an artefact type is given this doesn't really make sense. + public static List getEquippedArtefacts(EntityPlayer player, ItemArtefact.Type... types){ + + List artefacts = new ArrayList<>(); + + for(ItemArtefact.Type type : types){ + for(int slot : ARTEFACT_TYPE_MAP.get(type).getValidSlots()){ + ItemStack stack = BaublesApi.getBaublesHandler(player).getStackInSlot(slot); + if(stack.getItem() instanceof ItemArtefact) artefacts.add((ItemArtefact)stack.getItem()); + } + } + + return artefacts; + } + + // Shamelessly copied from The Twilight Forest, with a few modifications + @SuppressWarnings("unchecked") + public static final class ArtefactBaubleProvider implements ICapabilityProvider { + + private BaubleType type; + + public ArtefactBaubleProvider(ItemArtefact.Type type){ + this.type = ARTEFACT_TYPE_MAP.get(type); + } + + @Override + public boolean hasCapability(@Nonnull Capability capability, @Nullable EnumFacing facing){ + return capability == BaublesCapabilities.CAPABILITY_ITEM_BAUBLE; + } + + @Override + public T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing){ + // This lambda expression is an implementation of the entire IBauble interface + return capability == BaublesCapabilities.CAPABILITY_ITEM_BAUBLE ? (T)(IBauble)itemStack -> type : null; + } + } + +} diff --git a/src/main/java/electroblob/wizardry/item/IConjuredItem.java b/src/main/java/electroblob/wizardry/item/IConjuredItem.java index 1ab78fe2..eadfe591 100644 --- a/src/main/java/electroblob/wizardry/item/IConjuredItem.java +++ b/src/main/java/electroblob/wizardry/item/IConjuredItem.java @@ -1,59 +1,118 @@ package electroblob.wizardry.item; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.spell.SpellConjuration; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; +import net.minecraft.item.IItemPropertyGetter; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.living.LivingDropsEvent; 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; + +import javax.annotation.Nullable; +import java.util.UUID; /** * Allows wizardry to identify items that are conjured (and therefore need destroying if they leave the inventory) - * without explicitly referencing each, thereby allowing for better expandibility. + * without explicitly referencing each, thereby allowing for better expandability. */ @Mod.EventBusSubscriber public interface IConjuredItem { /** The NBT tag key used to store the duration multiplier for conjured items. */ - public static final String DURATION_MULTIPLIER_KEY = "durationMultiplier"; + String DURATION_MULTIPLIER_KEY = "durationMultiplier"; + /** The NBT tag key used to store the damage multiplier for conjured items. */ + String DAMAGE_MULTIPLIER = "damageMultiplier"; + + UUID POTENCY_MODIFIER = UUID.fromString("da067ea6-0b35-4140-8436-5476224de9dd"); /** Helper method for setting the duration multiplier (via NBT) for conjured items. */ - public static void setDurationMultiplier(ItemStack stack, float multiplier){ + static void setDurationMultiplier(ItemStack stack, float multiplier){ if(!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound()); stack.getTagCompound().setFloat(DURATION_MULTIPLIER_KEY, multiplier); } + /** Helper method for setting the damage multiplier (via NBT) for conjured items. */ + static void setDamageMultiplier(ItemStack stack, float multiplier){ + if(!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound()); + stack.getTagCompound().setFloat(DAMAGE_MULTIPLIER, multiplier); + } + + /** Helper method for getting the damage multiplier (via NBT) for conjured items. */ + static float getDamageMultiplier(ItemStack stack){ + if(!stack.hasTagCompound()) return 1; + return stack.getTagCompound().getFloat(DAMAGE_MULTIPLIER); + } + /** * Helper method for returning the max damage of a conjured item based on its NBT data. Centralises the code. * Implementors will almost certainly want to call this from {@link Item#getMaxDamage(ItemStack stack)}. */ - public default int getMaxDamageFromNBT(ItemStack stack){ + default int getMaxDamageFromNBT(ItemStack stack, Spell spell){ + + float baseDuration = spell.getProperty(SpellConjuration.ITEM_LIFETIME).floatValue(); + if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DURATION_MULTIPLIER_KEY)){ - return (int)(this.getBaseDuration() * stack.getTagCompound().getFloat(DURATION_MULTIPLIER_KEY)); + return (int)(baseDuration * stack.getTagCompound().getFloat(DURATION_MULTIPLIER_KEY)); } - return this.getBaseDuration(); + + return (int)baseDuration; } /** - * Returns the base duration in ticks for this conjured item. Should be a constant (commonly 600). Implementors may - * want to call this when setting an item's max damage in its constructor. + * Adds property overrides to define the conjuring/vanishing animation. Call this from the item's constructor. */ - public int getBaseDuration(); + default void addAnimationPropertyOverrides(){ + + if(!(this instanceof Item)) throw new ClassCastException("Cannot set up conjuring animations for a non-item!"); + + Item item = (Item)this; + + final int frames = getAnimationFrames(); + + item.addPropertyOverride(new ResourceLocation("conjure"), new IItemPropertyGetter(){ + @SideOnly(Side.CLIENT) + public float apply(ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity){ + return stack.getItemDamage() < frames ? (float)stack.getItemDamage() / frames + : (float)(stack.getMaxDamage() - stack.getItemDamage()) / frames; + } + }); + item.addPropertyOverride(new ResourceLocation("conjuring"), new IItemPropertyGetter(){ + @SideOnly(Side.CLIENT) + public float apply(ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity){ + return stack.getItemDamage() < frames + || stack.getItemDamage() > stack.getMaxDamage() - frames ? 1.0F : 0.0F; + } + }); + } + + /** Returns the number of frames in the conjuring/vanishing animation. Override to change the number of frames + * set by {@link IConjuredItem#addAnimationPropertyOverrides()}. */ + default int getAnimationFrames(){ + return 8; + } @SubscribeEvent - public static void onLivingDropsEvent(LivingDropsEvent event){ + static void onLivingDropsEvent(LivingDropsEvent event){ // Destroys conjured items if their caster dies. for(EntityItem item : event.getDrops()){ - if(item.getItem().getItem() instanceof IConjuredItem){ + // Apparently some mods don't behave and shove null items in the list, quite why I have no idea + if(item != null && item.getItem() != null && item.getItem().getItem() instanceof IConjuredItem){ item.setDead(); } } } @SubscribeEvent - public static void onItemTossEvent(ItemTossEvent event){ + static void onItemTossEvent(ItemTossEvent event){ // Prevents conjured items being thrown by dragging and dropping outside the inventory. if(event.getEntityItem().getItem().getItem() instanceof IConjuredItem){ event.setCanceled(true); diff --git a/src/main/java/electroblob/wizardry/item/IManaStoringItem.java b/src/main/java/electroblob/wizardry/item/IManaStoringItem.java new file mode 100644 index 00000000..de93846d --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/IManaStoringItem.java @@ -0,0 +1,72 @@ +package electroblob.wizardry.item; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +/** + * Interface for any items that store mana. This interface simply specifies methods for setting and getting the amount + * of mana held in the item (plus a few convenience methods); implementations may differ between items. + *

    + * In wizardry itself, mana is still implemented as durability, however, as of wizardry 4.2, the vanilla method + * {@code Item.setDamage()} has been overridden to do nothing. Instead, mana must be interacted with using the methods + * in this interface. This means operating via the item rather than the stack. + *

    + * This change prevents general item repair methods working on mana items (see issues #66 and #153), and also allows + * other items to implement mana differently if they wish. For example, a weapon that can cast spells as an ability + * might want regular durability in addition to mana, so the mana might be stored in NBT instead. Items that do not use + * durability to represent mana may need to do zero-checking themselves, as appropriate. + *

    + * Wizardry's items implement mana as the inverse of item damage; i.e. the more damaged the item, the + * less mana it has. Beware of this when converting to the new system. + *

    + * @author Electroblob + * @since Wizardry 4.2 + */ +public interface IManaStoringItem { + + /** Returns the amount of mana contained in the given item stack. */ + int getMana(ItemStack stack); + + /** Sets the amount of mana contained in the given item stack to the given value. This method does not perform any + * checks for creative mode, etc. */ + void setMana(ItemStack stack, int mana); + + /** Returns the maximum amount of mana that the given item stack can hold. */ + int getManaCapacity(ItemStack stack); + + /** + * Returns whether this item's mana should be displayed in the arcane workbench tooltip. Only called client-side. + * Ignore this method if this item is not an {@link IWorkbenchItem}. + * @param player The player using the workbench. + * @param stack The itemstack to query. + * @return True if the mana should be shown, false if not. Returns true by default. + */ + default boolean showManaInWorkbench(EntityPlayer player, ItemStack stack){ + return true; + } + + /** Convenience method that decreases the amount of mana contained in the given item stack by the given value. This + * method automatically limits the mana to a minimum of 0 and performs the relevant checks for creative mode, etc. */ + default void consumeMana(ItemStack stack, int mana, EntityLivingBase wielder){ + if(wielder instanceof EntityPlayer && ((EntityPlayer)wielder).isCreative()) return; // Mana isn't consumed in creative + setMana(stack, Math.max(getMana(stack) - mana, 0)); + } + + /** Convenience method that increases the amount of mana contained in the given item stack by the given value. + * This method automatically limits the mana to within the item's capacity. */ + // We don't really need to limit this one because Item#setDamage() ultimately limits it anyway, but we may as well + default void rechargeMana(ItemStack stack, int mana){ + setMana(stack, Math.min(getMana(stack) + mana, getManaCapacity(stack))); + } + + /** Convenience method that returns true if the given stack contains the maximum amount of mana, false otherwise. */ + default boolean isManaFull(ItemStack stack){ + return getMana(stack) == getManaCapacity(stack); + } + + /** Convenience method that returns true if the given stack contains no mana, false otherwise. */ + default boolean isManaEmpty(ItemStack stack){ + return getMana(stack) == 0; + } +} diff --git a/src/main/java/electroblob/wizardry/item/IMultiTexturedItem.java b/src/main/java/electroblob/wizardry/item/IMultiTexturedItem.java new file mode 100644 index 00000000..849f9ae8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/IMultiTexturedItem.java @@ -0,0 +1,23 @@ +package electroblob.wizardry.item; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +/** + * Interface for items that change their texture depending on their metadata. This is mainly to facilitate use of the + * convenience method {@link electroblob.wizardry.client.model.WizardryModels#registerMultiTexturedModel(Item) WizardryModels.registerMultiTexturedModel(T)}. Also works well for {@code ItemBlock}s! + * @author Electroblob + * @since Wizardry 4.2 + * @see ItemBlockMultiTexturedElemental + */ +public interface IMultiTexturedItem { + + /** + * Returns the appropriate {@code ResourceLocation} for this item's model, based on the given itemstack. + * @param stack The itemstack to return the model name for. + * @return A {@code ResourceLocation} pointing to the appropriate model file. As with any other model, this should + * include the domain (mod ID) and filename, without the rest of the filepath. + */ + ResourceLocation getModelName(ItemStack stack); +} diff --git a/src/main/java/electroblob/wizardry/item/ISpellCastingItem.java b/src/main/java/electroblob/wizardry/item/ISpellCastingItem.java new file mode 100644 index 00000000..0d532200 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ISpellCastingItem.java @@ -0,0 +1,129 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; + +/** + * Interface for items that can hold and cast one or more spells. These may be consumables, like scrolls, or they may be + * durability-based, like wands. Custom spell casting items should implement this interface to integrate properly into + * wizardry. It is no longer necessary to extend {@code ItemWand}, but you may still do so instead of implementing + * this interface if appropriate. + *

    + * This interface is used for the following:
    + * - General-purpose detection of continuous spell casting (see {@link electroblob.wizardry.util.WizardryUtilities#isCasting(EntityLivingBase, Spell)})
    + * - Display of the arcane workbench tooltip (in conjunction with {@link IManaStoringItem})
    + * - Spell HUD visibility
    + * - Spell switching controls (they won't do anything unless the player is holding an {@code ISpellCastingItem})
    + * - Artefacts that trigger a player's wands/scrolls to cast spells + * @author Electroblob + * @since Wizardry 4.2 + */ +// This could probably be turned into a capability at some point, but for the moment it's fine like this +// As we've already noted, capabilities are only useful for optional dependencies anyway +public interface ISpellCastingItem { + + /** + * Returns the spell currently equipped on the given itemstack. The given itemstack will be of this item. + * @param stack The itemstack to query. + * @return The currently equipped spell, or {@link electroblob.wizardry.registry.Spells#none Spells.none} if no spell + * is equipped. + */ + @Nonnull + Spell getCurrentSpell(ItemStack stack); + + /** + * Returns all the spells currently bound to the given itemstack. The given itemstack will be of this item. + * @param stack The itemstack to query. + * @return The bound spells, or {@link electroblob.wizardry.registry.Spells#none Spells.none} if no spell + * is equipped. + */ + default Spell[] getSpells(ItemStack stack){ + return new Spell[]{getCurrentSpell(stack)}; // Default implementation for single-spell items, because I'm lazy + } + + /** + * Selects the next spell bound to the given itemstack. The given itemstack will be of this item. + * @param stack The itemstack to query. + */ + default void selectNextSpell(ItemStack stack){ + // If it doesn't need spell-switching then don't bother the implementor with it + } + + /** + * Selects the previous spell bound to the given itemstack. The given itemstack will be of this item. + * @param stack The itemstack to query. + */ + default void selectPreviousSpell(ItemStack stack){ + // Nothing here either + } + + /** + * Returns whether the spell HUD should be shown when a player is holding this item. Only called client-side. + * @param player The player holding the item. + * @param stack The itemstack to query. + * @return True if the spell HUD should be shown, false if not. + */ + boolean showSpellHUD(EntityPlayer player, ItemStack stack); + + /** + * Returns whether this item's spells should be displayed in the arcane workbench tooltip. Only called client-side. + * Ignore this method if this item is not an {@link IWorkbenchItem}. + * @param player The player using the workbench. + * @param stack The itemstack to query. + * @return True if the spells should be shown, false if not. Returns true by default. + */ + default boolean showSpellsInWorkbench(EntityPlayer player, ItemStack stack){ + return true; + } + + // These methods were made with intention of standardising the code for casting spells using items. + // For most external uses there's no reason for them to be separate, however, it makes more sense to do so because + // then we can eliminate a bit of duplicate code from continuous vs. non-continuous spell casting. Otherwise, we'd + // need a separate method for casting continuous spells anyway. + + /** + * Returns whether the given spell can be cast by the given stack in its current state. Does not perform any actual + * spellcasting. + * + * @param stack The stack being queried; will be of this item. + * @param spell The spell to be cast. + * @param caster The player doing the casting. + * @param hand The hand in which the casting item is being held. + * @param castingTick For continuous spells, the number of ticks the spell has already been cast for. For all other + * spells, this will be zero. + * @param modifiers The modifiers with which the spell is being cast. + * @return True if the spell can be cast, false if not. + */ + boolean canCast(ItemStack stack, Spell spell, EntityPlayer caster, EnumHand hand, int castingTick, SpellModifiers modifiers); + + /** + * Casts the given spell using the given item stack. This method does not perform any checks; these are done + * in {@link ISpellCastingItem#canCast(ItemStack, Spell, EntityPlayer, EnumHand, int, SpellModifiers)}. This method + * also performs any post-casting logic, such as mana costs and cooldowns. + *

    + * N.B. Continuous spell casting from outside of the items requires a bit of extra legwork, see + * {@link WizardData} for an example. + * + * @param stack The stack being queried; will be of this item. + * @param spell The spell to be cast. + * @param caster The player doing the casting. + * @param hand The hand in which the casting item is being held. + * @param castingTick For continuous spells, the number of ticks the spell has already been cast for. For all other + * spells, this will be zero. + * @param modifiers The modifiers with which the spell is being cast. + * @return True if the spell succeeded, false if not. This is only really for the purpose of returning a result from + * {@link net.minecraft.item.Item#onItemRightClick(World, EntityPlayer, EnumHand)} and similar methods; mana costs, + * cooldowns and whatever else you might want to do post-spellcasting should be done within this method so that + * external sources don't allow spells to be cast for free, for example. + */ + boolean cast(ItemStack stack, Spell spell, EntityPlayer caster, EnumHand hand, int castingTick, SpellModifiers modifiers); + +} diff --git a/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java b/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java index 704bebec..e85fd314 100644 --- a/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java +++ b/src/main/java/electroblob/wizardry/item/IWorkbenchItem.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Items that implement this interface may be placed in the central slot of the arcane workbench as long as * {@link IWorkbenchItem#canPlace(ItemStack)} returns true. The number of spell book slots displayed is also specified * using {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}. - *

    + *

    * Items that implement this interface define what happens if they are in the central slot of the arcane workbench and * the apply button is pressed, in {@link IWorkbenchItem#onApplyButtonPressed(EntityPlayer, Slot, Slot, Slot, Slot[])}. * This is a core part of the arcane workbench refactoring in version 4.2 and allows for custom spell casting items and @@ -52,5 +52,13 @@ public interface IWorkbenchItem { * @return True if anything changed, false if not. */ boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks); + + /** + * Returns whether the tooltip (dark grey box) should be drawn when this item is in an arcane workbench. Only + * called client-side. + * @param stack The itemstack to query. + * @return True if the workbench tooltip should be shown, false if not. + */ + boolean showTooltip(ItemStack stack); } diff --git a/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java b/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java index bf4b2b25..3e40abd8 100644 --- a/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java +++ b/src/main/java/electroblob/wizardry/item/ItemArcaneTome.java @@ -1,11 +1,8 @@ package electroblob.wizardry.item; -import java.util.List; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryTabs; -import net.minecraft.client.util.ITooltipFlag; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.EnumRarity; import net.minecraft.item.Item; @@ -15,6 +12,8 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.List; + public class ItemArcaneTome extends Item { public ItemArcaneTome(){ @@ -54,7 +53,12 @@ public class ItemArcaneTome extends Item { @SideOnly(Side.CLIENT) @Override - public void addInformation(ItemStack stack, World world, List tooltip, ITooltipFlag showAdvanced){ + public void addInformation(ItemStack stack, World world, List tooltip, net.minecraft.client.util.ITooltipFlag showAdvanced){ + + if(stack.getItemDamage() < 1){ + return; // If something's up with the metadata it will display a 'generic' tome of arcana with no info + } + Tier tier = Tier.values()[stack.getItemDamage()]; Tier tier2 = Tier.values()[stack.getItemDamage() - 1]; tooltip.add(tier.getDisplayNameWithFormatting()); diff --git a/src/main/java/electroblob/wizardry/item/ItemArmourUpgrade.java b/src/main/java/electroblob/wizardry/item/ItemArmourUpgrade.java index 39eaef6e..b7307b15 100644 --- a/src/main/java/electroblob/wizardry/item/ItemArmourUpgrade.java +++ b/src/main/java/electroblob/wizardry/item/ItemArmourUpgrade.java @@ -1,12 +1,7 @@ package electroblob.wizardry.item; -import java.util.List; - -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryTabs; -import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.EnumRarity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -14,6 +9,9 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import javax.annotation.Nullable; +import java.util.List; + public class ItemArmourUpgrade extends Item { public ItemArmourUpgrade(){ @@ -35,7 +33,7 @@ public class ItemArmourUpgrade extends Item { @Override @SideOnly(Side.CLIENT) - public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { + public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, net.minecraft.client.util.ITooltipFlag flagIn) { tooltip.add(net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":armour_upgrade.desc1", "\u00A77")); tooltip.add( net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":armour_upgrade.desc2", "\u00A77", "\u00A7d")); diff --git a/src/main/java/electroblob/wizardry/item/ItemArtefact.java b/src/main/java/electroblob/wizardry/item/ItemArtefact.java new file mode 100644 index 00000000..be1e987c --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemArtefact.java @@ -0,0 +1,875 @@ +package electroblob.wizardry.item; + +import com.google.common.collect.Streams; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.entity.construct.EntityFireRing; +import electroblob.wizardry.entity.living.ISummonedCreature; +import electroblob.wizardry.entity.projectile.EntityDart; +import electroblob.wizardry.entity.projectile.EntityForceOrb; +import electroblob.wizardry.entity.projectile.EntityIceShard; +import electroblob.wizardry.event.SpellCastEvent; +import electroblob.wizardry.integration.DamageSafetyChecker; +import electroblob.wizardry.integration.baubles.WizardryBaublesIntegration; +import electroblob.wizardry.registry.*; +import electroblob.wizardry.spell.*; +import electroblob.wizardry.util.*; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IProjectile; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraftforge.common.BiomeDictionary; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.event.entity.living.LivingDeathEvent; +import net.minecraftforge.event.entity.living.LivingEvent; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraftforge.event.entity.living.PotionEvent; +import net.minecraftforge.event.entity.player.PlayerDropsEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.Event; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * Base class for all artefact items, which handles effects, textures and so on. The majority of artefacts are + * event-driven so it is unlikely that this class will need to be extended, unless other {@code Item} methods are to be + * overridden. + *

    + * This class contains methods and an enum that mirror those in {@code IBauble} from the Baubles mod. If Baubles is + * loaded, these are called via the bauble capability; otherwise, they are called from regular {@link Item} methods + * or events with appropriate checks. This allows wizardry to run with Baubles as an optional dependency. + *

    + * Do not reference any Baubles classes from subclasses of this, or the dependency will no longer be optional! + * Use {@link ItemArtefact#isArtefactActive(EntityPlayer, Item)} to test if a particular artefact is active. Use + * {@link ItemArtefact#getActiveArtefacts(EntityPlayer, Type...)} to get a list of active artefacts. + *

    + * @author Electroblob + * @since Wizardry 4.2 + * @see electroblob.wizardry.integration.baubles.WizardryBaublesIntegration + */ +@Mod.EventBusSubscriber +public class ItemArtefact extends Item { + + // Artefact checklist: + // - Create and register item, add model and texture + // - Program effect, using events if possible (if it only affects a specific spell or entity, in there is ok) + // - Add name AND description to lang files + // - Add to loot_tables/subsets/[rarity]_artefacts.json + // - Add to advancements/artefact.json and advancements/all_artefacts.json + + public enum Type { + + /** An artefact that improves attacking spells. Two of these can be active at any one time. */ RING(2), + /** An artefact that improves defensive spells. One of these can be active at any one time. */ AMULET(1), + /** An artefact that improves utility spells. One of these can be active at any one time. */ CHARM(1); + + public final int maxAtOnce; + + Type(int maxAtOnce){ + this.maxAtOnce = maxAtOnce; + } + } + + // If Baubles is not installed, artefacts will still work, but must instead be + // on the player's hotbar (and only the first n of a given type will work, where n is the number of baubles slots of that + // artefact's type). + + // Rarity was chosen over Tier here for a couple of reasons: firstly, displaying a tier would add unnecessary clutter + // to a potentially already-long tooltip whereas rarity provides a compact, neat way of displaying it that everyone is + // reasonably familiar with. Secondly, rarity makes more sense for an artefact, since it's something you find rather + // than upgrade to, and artefacts are not tied to tiers of wand/spell/whatever - they can be used whenever. + private final EnumRarity rarity; + private final Type type; + + public ItemArtefact(EnumRarity rarity, Type type){ + setMaxStackSize(1); + setCreativeTab(WizardryTabs.GEAR); + this.rarity = rarity; + this.type = type; + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return rarity; + } + + public Type getType(){ + return type; + } + + @Override + public boolean hasEffect(ItemStack stack){ + return rarity == EnumRarity.EPIC; + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, net.minecraft.client.util.ITooltipFlag flagIn){ + Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc"); + } + + @Nullable + @Override + public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable NBTTagCompound nbt){ + return WizardryBaublesIntegration.enabled() ? new WizardryBaublesIntegration.ArtefactBaubleProvider(type) : null; + } + + // IBauble does of course have an onWornTick method. However, because it's an optional dependency, it doesn't really + // make sense to use that method when it's easier to just use the isBaubleEquipped method in the same + // place as the non-baubles check. In other words, most artefacts are event-driven anyway so I'd rather have the + // tick-driven ones use events as well for the sake of consistency. + + /** + * Returns whether the given artefact is active for the given player. If Baubles is loaded, an artefact is active + * when it is equipped in an appropriate bauble slot. If Baubles is not loaded, an artefact is active if it is one + * of the first n of its type on the player's hands/hotbar, where n is the number of bauble slots of that type. + *

    + * N.B. This method is inefficient if you are defining multiple artefact behaviours in the same place. In this use + * case, it is preferable to use {@link ItemArtefact#getActiveArtefacts(EntityPlayer, Type...)}. + * + * @param player The player whose inventory is to be checked. + * @param artefact The artefact to check for. + * @return True if the player has the artefact and it is active, false if not. Always returns false if the given + * item is not an instance of {@code ItemArtefact}. + * @throws IllegalArgumentException If the given item is not an artefact. + */ + // It's cleaner to cast to ItemArtefact here than wherever it is used - items can't be stored as ItemWhatever objects + public static boolean isArtefactActive(EntityPlayer player, Item artefact){ + + if(!(artefact instanceof ItemArtefact)) throw new IllegalArgumentException("Not an artefact!"); + + if(WizardryBaublesIntegration.enabled()){ + return WizardryBaublesIntegration.isBaubleEquipped(player, artefact); + }else{ + // To find out if the given artefact is one of the first n on the player's hotbar (where n is the maximum + // number of that kind of artefact that can be active at once): + return WizardryUtilities.getPrioritisedHotbarAndOffhand(player).stream() // Retrieve the stacks in question + // Filter out all except artefacts of the same type as the given one (preserving order) + .filter(s -> s.getItem() instanceof ItemArtefact && ((ItemArtefact)s.getItem()).type == ((ItemArtefact)artefact).type) + .limit(((ItemArtefact)artefact).type.maxAtOnce) // Ignore all but the first n + .anyMatch(s -> s.getItem() == artefact); // Check if the remaining stacks contain the artefact + // Note that streaming a list DOES retain the order (unless you call unordered(), obviously) + } + } + + /** + * Returns the currently active artefacts for the given player. If Baubles is loaded, an artefact is active + * when it is equipped in an appropriate bauble slot. If Baubles is not loaded, an artefact is active if it is one + * of the first n of its type on the player's hands/hotbar, where n is the number of bauble slots of that type. + *

    + * This method is more efficient for processing multiple artefact behaviours at once. + * + * @param player The player whose inventory is to be checked. + * @param types The artefact types to check for. If omitted, all artefact types will be checked. + * @return True if the player has the artefact and it is active, false if not. Always returns false if the given + * item is not an instance of {@code ItemArtefact}. + */ + public static List getActiveArtefacts(EntityPlayer player, Type... types){ + + if(types.length == 0) types = Type.values(); + + if(WizardryBaublesIntegration.enabled()){ + return WizardryBaublesIntegration.getEquippedArtefacts(player, types); + }else{ + + List artefacts = new ArrayList<>(); + + for(Type type : types){ + artefacts.addAll(WizardryUtilities.getPrioritisedHotbarAndOffhand(player).stream() + .filter(s -> s.getItem() instanceof ItemArtefact) + .map(s -> (ItemArtefact)s.getItem()) + .filter(i -> type == i.type) + .limit(type.maxAtOnce) + .collect(Collectors.toList())); + } + + return artefacts; + } + } + + /** + * Helper method that scans through all wands on the given player's hotbar and offhand and executes the given action + * if any of them have the given spell bound to them. This is a useful code pattern for artefact effects. + * + * @param player The player whose hotbar is to be checked + * @param spell The spell to search for + * @param action A {@link Consumer} specifying the action to be performed if a wand with the given spell is found. + * The stack passed to this consumer will be the wand in question. + * @return True if the action was executed, false otherwise. + */ + public static boolean findMatchingWandAndExecute(EntityPlayer player, Spell spell, Consumer action){ + + List hotbar = WizardryUtilities.getPrioritisedHotbarAndOffhand(player); + + Optional stack = hotbar.stream().filter(s -> s.getItem() instanceof ISpellCastingItem + && Arrays.asList(((ISpellCastingItem)s.getItem()).getSpells(s)).contains(spell)).findFirst(); + + stack.ifPresent(action); + return stack.isPresent(); + } + + /** + * Helper method that scans through all wands on the given player's hotbar and offhand and casts the given spell if + * it is bound to any of them. This is a useful code pattern for artefact effects. + * + * @param player The player whose hotbar is to be checked + * @param spell The spell to search for and cast + * @return True if the spell was cast, false otherwise. + */ + public static boolean findMatchingWandAndCast(EntityPlayer player, Spell spell){ + + return findMatchingWandAndExecute(player, spell, wand -> { + + SpellModifiers modifiers = new SpellModifiers(); + + if(((ISpellCastingItem)wand.getItem()).canCast(wand, spell, player, EnumHand.MAIN_HAND, 0, modifiers)){ + ((ISpellCastingItem)wand.getItem()).cast(wand, spell, player, EnumHand.MAIN_HAND, 0, modifiers); + } + }); + } + + // ================================================ Event Handlers ================================================ + + @SubscribeEvent + public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){ + + if(event.phase == TickEvent.Phase.START){ + + EntityPlayer player = event.player; + World world = player.world; + + for(ItemArtefact artefact : getActiveArtefacts(player)){ + + if(artefact == WizardryItems.ring_condensing){ + + if(world.isRemote && player.ticksExisted % 150 == 0){ + for(ItemStack stack : WizardryUtilities.getHotbar(player)){ + // Needs to be both of these interfaces because this ring only recharges wands + // (or more accurately, chargeable spellcasting items) + if(stack.getItem() instanceof ISpellCastingItem && stack.getItem() instanceof IManaStoringItem) + ((IManaStoringItem)stack.getItem()).rechargeMana(stack, 1); + } + } + + }else if(artefact == WizardryItems.amulet_arcane_defence){ + + if(world.isRemote && player.ticksExisted % 300 == 0){ + for(ItemStack stack : player.getArmorInventoryList()){ + // IManaStoringItem is sufficient, since anything in the armour slots is probably armour + if(stack.getItem() instanceof IManaStoringItem) + ((IManaStoringItem)stack.getItem()).rechargeMana(stack, 1); + } + } + + }else if(artefact == WizardryItems.amulet_recovery){ + + if(player.shouldHeal() && player.getHealth() < player.getMaxHealth()/2 + && player.ticksExisted % 50 == 0){ + + int totalArmourMana = Streams.stream(player.getArmorInventoryList()) + .filter(s -> s.getItem() instanceof IManaStoringItem) + .mapToInt(s -> ((IManaStoringItem)s.getItem()).getMana(s)) + .sum(); + + if(totalArmourMana >= 2){ + player.heal(1); + // 2 mana per half-heart, randomly distributed + List chargedArmour = Streams.stream(player.getArmorInventoryList()) + .filter(s -> s.getItem() instanceof IManaStoringItem) + .filter(s -> !((IManaStoringItem)s.getItem()).isManaEmpty(s)) + .collect(Collectors.toList()); + + if(chargedArmour.size() == 1){ + ((IManaStoringItem)chargedArmour.get(0).getItem()).consumeMana(chargedArmour.get(0), 2, player); + }else{ + Collections.shuffle(chargedArmour); + ((IManaStoringItem)chargedArmour.get(0).getItem()).consumeMana(chargedArmour.get(0), 1, player); + ((IManaStoringItem)chargedArmour.get(1).getItem()).consumeMana(chargedArmour.get(1), 1, player); + } + } + } + + }else if(artefact == WizardryItems.amulet_glide){ + // This should be a chance per fall, so we can't just check fall distance is greater than 3 each tick + // Based on a stationary start and a gravity acceleration of 0.02 blocks/tick^2, at 3 blocks of fall + // distance the player should be falling at about 0.35b/t, so 0.5 blocks should be enough of a window + if(player.fallDistance > 3f && player.fallDistance < 3.5f && player.world.rand.nextFloat() < 0.5f){ + if(!WizardData.get(player).isCasting()) WizardData.get(player).startCastingContinuousSpell(Spells.glide, new SpellModifiers(), 600); + }else if(player.onGround){ + WizardData data = WizardData.get(player); + if(data.currentlyCasting() == Spells.glide) data.stopCastingContinuousSpell(); + } + + }else if(artefact == WizardryItems.amulet_auto_shield){ + + findMatchingWandAndExecute(player, Spells.shield, wand -> { + + List projectiles = WizardryUtilities.getEntitiesWithinRadius(5, player.posX, player.posY, player.posZ, world, Entity.class); + projectiles.removeIf(e -> !(e instanceof IProjectile)); + Vec3d look = player.getLookVec(); + Vec3d playerPos = player.getPositionVector().add(0, player.height/2, 0); + + for(Entity projectile : projectiles){ + Vec3d vec = playerPos.subtract(projectile.getPositionVector()).normalize(); + double angle = Math.acos(vec.scale(-1).dotProduct(look)); + if(angle > Math.PI * 0.4f) continue; // (Roughly) the angle the shield will protect + Vec3d velocity = new Vec3d(projectile.motionX, projectile.motionY, projectile.motionZ).normalize(); + double angle1 = Math.acos(vec.dotProduct(velocity)); + if(angle1 < Math.PI * 0.2f){ + SpellModifiers modifiers = new SpellModifiers(); + if(((ISpellCastingItem)wand.getItem()).canCast(wand, Spells.shield, player, EnumHand.MAIN_HAND, 0, modifiers)){ + ((ISpellCastingItem)wand.getItem()).cast(wand, Spells.shield, player, EnumHand.MAIN_HAND, 0, modifiers); + } + break; + } + } + }); + + }else if(artefact == WizardryItems.charm_feeding){ + // Every 5 seconds, feed the player if they are near starving + if(player.ticksExisted % 100 == 0 && player.getFoodStats().getFoodLevel() < 2){ + findMatchingWandAndCast(player, Spells.replenish_hunger); + } + } + } + } + } + + @SubscribeEvent(priority = EventPriority.LOW) + public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ + + if(event.getCaster() instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)event.getCaster(); + SpellModifiers modifiers = event.getModifiers(); + + for(ItemArtefact artefact : getActiveArtefacts(player)){ + + float potency = modifiers.get(SpellModifiers.POTENCY); + float cooldown = modifiers.get(WizardryItems.cooldown_upgrade); + Biome biome = player.world.getBiome(player.getPosition()); + + if(artefact == WizardryItems.ring_battlemage){ + + if(player.getHeldItemOffhand().getItem() instanceof ISpellCastingItem + && ImbueWeapon.isSword(player.getHeldItemMainhand().getItem())){ + modifiers.set(SpellModifiers.POTENCY, 1.1f * potency, false); + } + + }else if(artefact == WizardryItems.ring_fire_biome){ + + if(event.getSpell().getElement() == Element.FIRE + && BiomeDictionary.hasType(biome, BiomeDictionary.Type.HOT) + && BiomeDictionary.hasType(biome, BiomeDictionary.Type.DRY)){ + modifiers.set(SpellModifiers.POTENCY, 1.3f * potency, false); + } + + }else if(artefact == WizardryItems.ring_ice_biome){ + + if(event.getSpell().getElement() == Element.ICE + && BiomeDictionary.hasType(biome, BiomeDictionary.Type.SNOWY)){ + modifiers.set(SpellModifiers.POTENCY, 1.3f * potency, false); + } + + }else if(artefact == WizardryItems.ring_earth_biome){ + + if(event.getSpell().getElement() == Element.EARTH + // If it was any forest that would be far too many, so taigas and jungles are excluded + && BiomeDictionary.hasType(biome, BiomeDictionary.Type.FOREST) + && !BiomeDictionary.hasType(biome, BiomeDictionary.Type.CONIFEROUS) + && !BiomeDictionary.hasType(biome, BiomeDictionary.Type.JUNGLE)){ + modifiers.set(SpellModifiers.POTENCY, 1.3f * potency, false); + } + + }else if(artefact == WizardryItems.ring_storm){ + + if(event.getSpell().getElement() == Element.LIGHTNING && player.world.isThundering()){ + modifiers.set(WizardryItems.cooldown_upgrade, cooldown * 0.3f, false); + } + + }else if(artefact == WizardryItems.ring_full_moon){ + + if(event.getSpell().getElement() == Element.EARTH && !player.world.isDaytime() + && player.world.provider.getMoonPhase(player.world.getWorldTime()) == 0){ + modifiers.set(WizardryItems.cooldown_upgrade, cooldown * 0.3f, false); + } + + }else if(artefact == WizardryItems.ring_blockwrangler){ + + if(event.getSpell() == Spells.greater_telekinesis){ + modifiers.set(SpellModifiers.POTENCY, modifiers.get(SpellModifiers.POTENCY) * 2, false); + } + + }else if(artefact == WizardryItems.ring_conjurer){ + + if(event.getSpell() instanceof SpellConjuration){ + modifiers.set(WizardryItems.duration_upgrade, modifiers.get(WizardryItems.duration_upgrade) * 2, false); + } + + }else if(artefact == WizardryItems.charm_minion_health){ + // We COULD check the spell is a SpellMinion here, but there's really no point + modifiers.set(SpellMinion.HEALTH_MODIFIER, 1.25f * modifiers.get(SpellMinion.HEALTH_MODIFIER), true); + + }else if(artefact == WizardryItems.charm_flight){ + + if(event.getSpell() == Spells.flight || event.getSpell() == Spells.glide){ + // FIXME: Does not appear to be working, for some reason + modifiers.set(SpellModifiers.POTENCY, 1.5f * potency, true); + } + + }else if(artefact == WizardryItems.charm_experience_tome){ + + modifiers.set(SpellModifiers.PROGRESSION, modifiers.get(SpellModifiers.PROGRESSION) * 1.5f, false); + } + } + } + } + + @SubscribeEvent + public static void onSpellCastPostEvent(SpellCastEvent.Pre event){ + + if(event.getCaster() instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)event.getCaster(); + + if(isArtefactActive(player, WizardryItems.ring_paladin)){ + + if(event.getSpell() instanceof Heal || event.getSpell() instanceof HealAlly || event.getSpell() instanceof GreaterHeal){ + // Spell properties allow all three of the above spells to be dealt with the same way - neat! + float healthGained = event.getSpell().getProperty(Spell.HEALTH).floatValue() * event.getModifiers().get(SpellModifiers.POTENCY); + + List nearby = WizardryUtilities.getEntitiesWithinRadius(4, player.posX, player.posY, player.posZ, event.getWorld()); + + for(EntityLivingBase entity : nearby){ + if(AllyDesignationSystem.isAllied(player, entity) && entity.getHealth() > 0 && entity.getHealth() < entity.getMaxHealth()){ + entity.heal(healthGained * 0.2f); // 1/5 of the amount healed by the spell itself + if(event.getWorld().isRemote) ParticleBuilder.spawnHealParticles(event.getWorld(), entity); + } + } + } + } + } + } + + @SubscribeEvent + public static void onLivingUpdateEvent(LivingEvent.LivingUpdateEvent event){ + + EntityLivingBase entity = event.getEntityLiving(); + + // No point doing this every tick, every 2.5 seconds should be enough + if(entity.ticksExisted % 50 == 0 && entity.isPotionActive(WizardryPotions.mind_control)){ + + NBTTagCompound entityNBT = entity.getEntityData(); + + if(entityNBT.hasUniqueId(MindControl.NBT_KEY)){ + + Entity caster = WizardryUtilities.getEntityByUUID(entity.world, entityNBT.getUniqueId(MindControl.NBT_KEY)); + + if(caster instanceof EntityPlayer){ + + if(isArtefactActive((EntityPlayer)caster, WizardryItems.ring_mind_control)){ + + WizardryUtilities.getEntitiesWithinRadius(3, entity.posX, entity.posY, entity.posZ, entity.world, EntityLiving.class).stream() + .filter(e -> e.world.rand.nextInt(10) == 0) + .filter(MindControl::canControl) + .filter(e -> AllyDesignationSystem.isValidTarget(caster, e)) + .forEach(target -> MindControl.startControlling(target, (EntityPlayer)caster, + // Control the new target for only the remaining duration, otherwise it could go on forever! + entity.getActivePotionEffect(WizardryPotions.mind_control).getDuration())); + } + } + } + } + } + + @SubscribeEvent + public static void onLivingHurtEvent(LivingHurtEvent event){ + + if(event.getEntity() instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)event.getEntity(); + + for(ItemArtefact artefact : getActiveArtefacts(player)){ + + if(artefact == WizardryItems.amulet_warding){ + + if(!event.getSource().isUnblockable() && event.getSource().isMagicDamage()){ + event.setAmount(event.getAmount() * 0.9f); + } + + }else if(artefact == WizardryItems.amulet_fire_protection){ + + if(event.getSource().isFireDamage()) event.setAmount(event.getAmount() * 0.7f); + + }else if(artefact == WizardryItems.amulet_ice_protection){ + + if(event.getSource() instanceof IElementalDamage + && ((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.FROST) + event.setAmount(event.getAmount() * 0.7f); + + }else if(artefact == WizardryItems.amulet_channeling){ + + if(player.world.rand.nextFloat() < 0.3f && event.getSource() instanceof IElementalDamage + && ((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.SHOCK){ + event.setCanceled(true); + return; + } + + }else if(artefact == WizardryItems.amulet_fire_cloaking){ + + if(!event.getSource().isUnblockable()){ + + List fireRings = player.world.getEntitiesWithinAABB(EntityFireRing.class, player.getEntityBoundingBox()); + + for(EntityFireRing fireRing : fireRings){ + if(fireRing.getCaster() instanceof EntityPlayer && (fireRing.getCaster() == player + || AllyDesignationSystem.isOwnerAlly(player, fireRing))){ + event.setAmount(event.getAmount() * 0.25f); + } + } + } + + }else if(artefact == WizardryItems.amulet_potential){ + + if(player.world.rand.nextFloat() < 0.2f && WizardryUtilities.isMeleeDamage(event.getSource()) + && event.getSource().getTrueSource() instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase)event.getSource().getTrueSource(); + + if(player.world.isRemote){ + + ParticleBuilder.create(ParticleBuilder.Type.LIGHTNING).entity(event.getEntity()) + .pos(0, event.getEntity().height/2, 0).target(target).spawn(player.world); + + ParticleBuilder.spawnShockParticles(player.world, target.posX, + target.getEntityBoundingBox().minY + target.height/2, target.posZ); + } + + DamageSafetyChecker.attackEntitySafely(target, MagicDamage.causeDirectMagicDamage(player, + MagicDamage.DamageType.SHOCK, true), Spells.static_aura.getProperty(Spell.DAMAGE).floatValue(), event.getSource().getDamageType()); + target.playSound(WizardrySounds.SPELL_STATIC_AURA_RETALIATE, 1.0F, player.world.rand.nextFloat() * 0.4F + 1.5F); + + } + + }else if(artefact == WizardryItems.amulet_lich){ + + if(!event.getSource().isUnblockable() && player.world.rand.nextFloat() < 0.15f){ + + List nearbyMobs = WizardryUtilities.getEntitiesWithinRadius(5, player.posX, player.posY, player.posZ, player.world, EntityLiving.class); + nearbyMobs.removeIf(e -> !(e instanceof ISummonedCreature && ((ISummonedCreature)e).getCaster() == player)); + + if(!nearbyMobs.isEmpty()){ + Collections.shuffle(nearbyMobs); + // Even though we're passing the same damage source through, we still need the safety check + DamageSafetyChecker.attackEntitySafely(nearbyMobs.get(0), event.getSource(), event.getAmount(), event.getSource().getDamageType()); + event.setCanceled(true); + return; // Standard practice: stop as soon as the event is canceled + } + } + + }else if(artefact == WizardryItems.amulet_banishing){ + + if(player.world.rand.nextFloat() < 0.2f && WizardryUtilities.isMeleeDamage(event.getSource()) + && event.getSource().getTrueSource() instanceof EntityLivingBase){ + + EntityLivingBase target = (EntityLivingBase)event.getSource().getTrueSource(); + ((Banish)Spells.banish).teleport(target, target.world, 8 + target.world.rand.nextDouble() * 8); + } + + }else if(artefact == WizardryItems.amulet_transience){ + + if(player.getHealth() <= 2 && player.world.rand.nextFloat() < 0.25f){ + player.addPotionEffect(new PotionEffect(WizardryPotions.transience, 300)); + player.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, 300, 0, false, false)); + } + } + } + } + + if(event.getSource().getTrueSource() instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)event.getSource().getTrueSource(); + ItemStack mainhandItem = player.getHeldItemMainhand(); + World world = player.world; + + for(ItemArtefact artefact : getActiveArtefacts(player)){ + + if(artefact == WizardryItems.ring_fire_melee){ + // Used ItemWand intentionally because we need the element + // Other mods can always make their own events if they want their own spellcasting items to do this + if(WizardryUtilities.isMeleeDamage(event.getSource()) && mainhandItem.getItem() instanceof ItemWand + && ((ItemWand)mainhandItem.getItem()).element == Element.FIRE){ + event.getEntity().setFire(5); + } + + }else if(artefact == WizardryItems.ring_ice_melee){ + + if(WizardryUtilities.isMeleeDamage(event.getSource()) && mainhandItem.getItem() instanceof ItemWand + && ((ItemWand)mainhandItem.getItem()).element == Element.ICE){ + event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.frost, 200, 0)); + } + + }else if(artefact == WizardryItems.ring_lightning_melee){ + + if(WizardryUtilities.isMeleeDamage(event.getSource()) && mainhandItem.getItem() instanceof ItemWand + && ((ItemWand)mainhandItem.getItem()).element == Element.LIGHTNING){ + + WizardryUtilities.getEntitiesWithinRadius(3, player.posX, player.posY, player.posZ, world).stream() + .filter(WizardryUtilities::isLiving) + .min(Comparator.comparingDouble(player::getDistanceSq)) + .ifPresent(target -> { + + if(world.isRemote){ + + ParticleBuilder.create(ParticleBuilder.Type.LIGHTNING).entity(event.getEntity()) + .pos(0, event.getEntity().height/2, 0).target(target).spawn(world); + + ParticleBuilder.spawnShockParticles(world, target.posX, + target.getEntityBoundingBox().minY + target.height/2, target.posZ); + } + + DamageSafetyChecker.attackEntitySafely(target, MagicDamage.causeDirectMagicDamage(player, + MagicDamage.DamageType.SHOCK, true), Spells.static_aura.getProperty(Spell.DAMAGE).floatValue(), event.getSource().getDamageType()); + target.playSound(WizardrySounds.SPELL_STATIC_AURA_RETALIATE, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + }); + } + + }else if(artefact == WizardryItems.ring_necromancy_melee){ + + if(WizardryUtilities.isMeleeDamage(event.getSource()) && mainhandItem.getItem() instanceof ItemWand + && ((ItemWand)mainhandItem.getItem()).element == Element.NECROMANCY){ + event.getEntityLiving().addPotionEffect(new PotionEffect(MobEffects.WITHER, 200, 0)); + } + + }else if(artefact == WizardryItems.ring_earth_melee){ + + if(WizardryUtilities.isMeleeDamage(event.getSource()) && mainhandItem.getItem() instanceof ItemWand + && ((ItemWand)mainhandItem.getItem()).element == Element.EARTH){ + event.getEntityLiving().addPotionEffect(new PotionEffect(MobEffects.POISON, 200, 0)); + } + + }else if(artefact == WizardryItems.ring_shattering){ + + if(!player.world.isRemote && player.world.rand.nextFloat() < 0.15f + && event.getEntityLiving().getHealth() < 12f // Otherwise it's a bit overpowered! + && event.getEntityLiving().isPotionActive(WizardryPotions.frost) + && WizardryUtilities.isMeleeDamage(event.getSource())){ + + event.setAmount(12f); + + for(int i = 0; i < 8; i++){ + double dx = event.getEntity().world.rand.nextDouble() - 0.5; + double dy = event.getEntity().world.rand.nextDouble() - 0.5; + double dz = event.getEntity().world.rand.nextDouble() - 0.5; + EntityIceShard iceshard = new EntityIceShard(event.getEntity().world); + iceshard.setPosition(event.getEntity().posX + dx + Math.signum(dx) * event.getEntity().width, + event.getEntity().posY + event.getEntity().height/2 + dy, + event.getEntity().posZ + dz + Math.signum(dz) * event.getEntity().width); + iceshard.motionX = dx * 1.5; + iceshard.motionY = dy * 1.5; + iceshard.motionZ = dz * 1.5; + iceshard.setCaster(player); + event.getEntity().world.spawnEntity(iceshard); + } + } + + }else if(artefact == WizardryItems.ring_soulbinding){ + + // Best guess at necromancy spell damage: either it's wither damage... + if((event.getSource() instanceof IElementalDamage + && (((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.WITHER)) + // or it's direct, non-melee damage and the player is holding a wand with a necromancy spell selected + || (event.getSource().getImmediateSource() == player && !WizardryUtilities.isMeleeDamage(event.getSource()) + && Streams.stream(player.getHeldEquipment()).anyMatch(s -> s.getItem() instanceof ISpellCastingItem + && ((ISpellCastingItem)s.getItem()).getCurrentSpell(s).getElement() == Element.NECROMANCY))){ + + CurseOfSoulbinding.getSoulboundCreatures(WizardData.get(player)).add(event.getEntity().getUniqueID()); + } + + }else if(artefact == WizardryItems.ring_leeching){ + + // Best guess at necromancy spell damage: either it's wither damage... + if(player.world.rand.nextFloat() < 0.3f && ((event.getSource() instanceof IElementalDamage + && (((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.WITHER)) + // ...or it's direct, non-melee damage and the player is holding a wand with a necromancy spell selected + || (event.getSource().getImmediateSource() == player && !WizardryUtilities.isMeleeDamage(event.getSource()) + && Streams.stream(player.getHeldEquipment()).anyMatch(s -> s.getItem() instanceof ISpellCastingItem + && ((ISpellCastingItem)s.getItem()).getCurrentSpell(s).getElement() == Element.NECROMANCY + && ((ISpellCastingItem)s.getItem()).getCurrentSpell(s) != Spells.life_drain)))){ + + if(player.shouldHeal()){ + player.heal(event.getAmount() * Spells.life_drain.getProperty(LifeDrain.HEAL_FACTOR).floatValue()); + } + } + + }else if(artefact == WizardryItems.ring_poison){ + + // Best guess at earth spell damage: either it's poison damage... + if((event.getSource() instanceof IElementalDamage + && (((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.POISON)) + // ...or it was from a dart... + || event.getSource().getImmediateSource() instanceof EntityDart + // ...or it's direct, non-melee damage and the player is holding a wand with an earth spell selected + || (event.getSource().getImmediateSource() == player && !WizardryUtilities.isMeleeDamage(event.getSource()) + && Streams.stream(player.getHeldEquipment()).anyMatch(s -> s.getItem() instanceof ISpellCastingItem + && ((ISpellCastingItem)s.getItem()).getCurrentSpell(s).getElement() == Element.EARTH))){ + + event.getEntityLiving().addPotionEffect(new PotionEffect(MobEffects.POISON, 200, 0)); + } + + }else if(artefact == WizardryItems.ring_extraction){ + + // Best guess at sorcery spell damage: either it's force damage... + if((event.getSource() instanceof IElementalDamage + && (((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.FORCE)) + // ...or it was from a force orb... + || event.getSource().getImmediateSource() instanceof EntityForceOrb + // ...or it's direct, non-melee damage and the player is holding a wand with a sorcery spell selected + || (event.getSource().getImmediateSource() == player && !WizardryUtilities.isMeleeDamage(event.getSource()) + && Streams.stream(player.getHeldEquipment()).anyMatch(s -> s.getItem() instanceof ISpellCastingItem + && ((ISpellCastingItem)s.getItem()).getCurrentSpell(s).getElement() == Element.SORCERY))){ + + WizardryUtilities.getPrioritisedHotbarAndOffhand(player).stream() + .filter(s -> s.getItem() instanceof ISpellCastingItem && s.getItem() instanceof IManaStoringItem + && !((IManaStoringItem)s.getItem()).isManaFull(s)) + .findFirst() + .ifPresent(s -> ((IManaStoringItem)s.getItem()).rechargeMana(s, 4 + world.rand.nextInt(3))); + } + + } + + } + } + } + + @SubscribeEvent + public static void onLivingDeathEvent(LivingDeathEvent event){ + + if(event.getSource().getTrueSource() instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)event.getSource().getTrueSource(); + + for(ItemArtefact artefact : getActiveArtefacts(player)){ + + if(artefact == WizardryItems.ring_combustion){ + + if(event.getSource() instanceof IElementalDamage && ((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.FIRE){ + event.getEntity().world.createExplosion(event.getEntity(), event.getEntity().posX, event.getEntity().posY, + event.getEntity().posZ, 1.5f, false); + } + + }else if(artefact == WizardryItems.ring_disintegration){ + + if(event.getSource() instanceof IElementalDamage && ((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.FIRE){ + Disintegration.spawnEmbers(event.getEntity().world, player, event.getEntity(), + Spells.disintegration.getProperty(Disintegration.EMBER_COUNT).intValue()); + } + + }else if(artefact == WizardryItems.ring_arcane_frost){ + + if(!player.world.isRemote && event.getSource() instanceof IElementalDamage + && ((IElementalDamage)event.getSource()).getType() == MagicDamage.DamageType.FROST){ + + for(int i = 0; i < 8; i++){ + double dx = event.getEntity().world.rand.nextDouble() - 0.5; + double dy = event.getEntity().world.rand.nextDouble() - 0.5; + double dz = event.getEntity().world.rand.nextDouble() - 0.5; + EntityIceShard iceshard = new EntityIceShard(event.getEntity().world); + iceshard.setPosition(event.getEntity().posX + dx + Math.signum(dx) * event.getEntity().width, + event.getEntity().posY + event.getEntity().height/2 + dy, + event.getEntity().posZ + dz + Math.signum(dz) * event.getEntity().width); + iceshard.motionX = dx * 1.5; + iceshard.motionY = dy * 1.5; + iceshard.motionZ = dz * 1.5; + iceshard.setCaster(player); + event.getEntity().world.spawnEntity(iceshard); + } + } + } + } + + } + } + + @SubscribeEvent(priority = EventPriority.HIGH) // Needs to happen before gravestones, etc. + public static void onPlayerDropsEvent(PlayerDropsEvent event){ + // Amulet of the immortal allows players to hold onto a wand with resurrection + // This needs to happen or we can't cast the spell with it and use up the mana + if(isArtefactActive(event.getEntityPlayer(), WizardryItems.amulet_resurrection)){ + + EntityItem item = event.getDrops().stream() + .filter(e -> Resurrection.canStackResurrect(e.getItem(), event.getEntityPlayer())) + .findFirst().orElse(null); + + if(item == null) return; // The player didn't have a wand with resurrection on it + if(!WizardryUtilities.getHotbar(event.getEntityPlayer()).contains(ItemStack.EMPTY)) return; // No space on hotbar + + event.getDrops().remove(item); + // At this point the player probably has nothing in their hand, but if not just find a free space somewhere + if(event.getEntityPlayer().getHeldItemMainhand().isEmpty()) event.getEntityPlayer().setHeldItem(EnumHand.MAIN_HAND, item.getItem()); + else event.getEntityPlayer().addItemStackToInventory(item.getItem()); // Always chooses hotbar slots first + } + } + + @SubscribeEvent + public static void onPotionApplicableEvent(PotionEvent.PotionApplicableEvent event){ + + if(event.getEntity() instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)event.getEntity(); + + for(ItemArtefact artefact : getActiveArtefacts(player)){ + + if(artefact == WizardryItems.amulet_ice_immunity){ + + if(event.getPotionEffect().getPotion() == WizardryPotions.frost) event.setResult(Event.Result.DENY); + + }else if(artefact == WizardryItems.amulet_wither_immunity){ + + if(event.getPotionEffect().getPotion() == MobEffects.WITHER) event.setResult(Event.Result.DENY); + } + } + } + } + + @SubscribeEvent + public static void onItemPickupEvent(PlayerEvent.ItemPickupEvent event){ + + // ItemPickupEvent is just a convenient trigger for this; we don't actually care what got picked up + if(isArtefactActive(event.player, WizardryItems.charm_auto_smelt)){ + + // So this doesn't waste mana, only cast pocket furnace when it would smelt the maximum number of items + if(event.player.inventory.mainInventory.stream() + .filter(s -> !FurnaceRecipes.instance().getSmeltingResult(s).isEmpty()) + .mapToInt(ItemStack::getCount) + .sum() >= Spells.pocket_furnace.getProperty(PocketFurnace.ITEMS_SMELTED).intValue()){ + + findMatchingWandAndCast(event.player, Spells.pocket_furnace); + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java b/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java index 3e9242d6..dc15754e 100644 --- a/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java +++ b/src/main/java/electroblob/wizardry/item/ItemBlankScroll.java @@ -1,11 +1,12 @@ package electroblob.wizardry.item; -import electroblob.wizardry.WizardData; import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryTabs; import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellProperties; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Slot; import net.minecraft.item.Item; @@ -22,28 +23,33 @@ public class ItemBlankScroll extends Item implements IWorkbenchItem { return 1; } + @Override + public boolean showTooltip(ItemStack stack){ + return false; + } + @Override public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){ if(!spellBooks[0].getStack().isEmpty() && !crystals.getStack().isEmpty()){ - Spell spell = Spell.get(spellBooks[0].getStack().getItemDamage()); + Spell spell = Spell.byMetadata(spellBooks[0].getStack().getItemDamage()); WizardData data = WizardData.get(player); // Spells can only be bound to scrolls if the player has already cast them (prevents casting of master // spells without getting a master wand) // This restriction does not apply in creative mode - if(spell != Spells.none && player.capabilities.isCreativeMode || (data != null - && data.hasSpellBeenDiscovered(spell))){ + if(spell != Spells.none && player.isCreative() || (data != null + && data.hasSpellBeenDiscovered(spell)) && spell.isEnabled(SpellProperties.Context.SCROLL)){ - int cost = spell.cost; + int cost = spell.getCost() * centre.getStack().getCount(); // Continuous spell scrolls require enough mana to cast them for the duration defined in ItemScroll. if(spell.isContinuous) cost *= ItemScroll.CASTING_TIME / 20; if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL > cost){ // Rounds up to the nearest whole crystal crystals.decrStackSize(cost / Constants.MANA_PER_CRYSTAL + 1); - centre.putStack(new ItemStack(WizardryItems.scroll, 1, spell.id())); + centre.putStack(new ItemStack(WizardryItems.scroll, centre.getStack().getCount(), spell.metadata())); return true; } diff --git a/src/main/java/electroblob/wizardry/item/ItemBlockMultiTexturedElemental.java b/src/main/java/electroblob/wizardry/item/ItemBlockMultiTexturedElemental.java new file mode 100644 index 00000000..0ed575cf --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemBlockMultiTexturedElemental.java @@ -0,0 +1,42 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.constants.Element; +import net.minecraft.block.Block; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +public class ItemBlockMultiTexturedElemental extends ItemBlock implements IMultiTexturedItem { + + private final boolean separateNames; + + public ItemBlockMultiTexturedElemental(Block block, boolean separateNames){ + super(block); + this.setHasSubtypes(true); + this.setMaxDamage(0); + this.separateNames = separateNames; + } + + @Override + public ResourceLocation getModelName(ItemStack stack){ + int metadata = stack.getMetadata(); + if(metadata >= Element.values().length) metadata = 0; + return getModelName(metadata); + } + + public ResourceLocation getModelName(int metadata){ + return new ResourceLocation(this.block.getRegistryName().getNamespace(), + Element.values()[metadata].getName() + "_" + this.block.getRegistryName().getPath()); + } + + @Override + public String getTranslationKey(ItemStack stack){ + return this.separateNames ? "tile." + this.getModelName(stack).toString() : super.getTranslationKey(stack); + } + + @Override + public int getMetadata(int metadata){ + return metadata; + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemCrystal.java b/src/main/java/electroblob/wizardry/item/ItemCrystal.java new file mode 100644 index 00000000..88e4c96d --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemCrystal.java @@ -0,0 +1,44 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; + +/** Note that in 1.13, the flattening will make this class redundant, much like ItemCoal, which is probably its + * closest analog in vanilla. */ +public class ItemCrystal extends Item implements IMultiTexturedItem { + + public ItemCrystal(){ + super(); + this.setHasSubtypes(true); + this.setMaxDamage(0); + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public ResourceLocation getModelName(ItemStack stack){ + int metadata = stack.getMetadata(); + if(metadata >= Element.values().length) metadata = 0; + return new ResourceLocation(Wizardry.MODID, "crystal_" + Element.values()[metadata].getName()); + } + + @Override + public String getTranslationKey(ItemStack stack){ + return "item." + this.getModelName(stack).toString(); + } + + @Override + public void getSubItems(CreativeTabs tab, NonNullList items){ + if(tab == WizardryTabs.WIZARDRY){ + for(Element element : Element.values()){ + items.add(new ItemStack(this, 1, element.ordinal())); + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemFirebomb.java b/src/main/java/electroblob/wizardry/item/ItemFirebomb.java index 1a3a6097..c3404136 100644 --- a/src/main/java/electroblob/wizardry/item/ItemFirebomb.java +++ b/src/main/java/electroblob/wizardry/item/ItemFirebomb.java @@ -1,9 +1,9 @@ package electroblob.wizardry.item; import electroblob.wizardry.entity.projectile.EntityFirebomb; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardryTabs; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; @@ -23,15 +23,15 @@ public class ItemFirebomb extends Item { ItemStack stack = player.getHeldItem(hand); - if(!player.capabilities.isCreativeMode){ + if(!player.isCreative()){ stack.shrink(1); } - player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); + player.playSound(WizardrySounds.ENTITY_FIREBOMB_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); if(!world.isRemote){ EntityFirebomb firebomb = new EntityFirebomb(world); - firebomb.aim(player, 1.5f); + firebomb.aim(player, 1); world.spawnEntity(firebomb); } diff --git a/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java b/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java index 23655dd2..dcfe3110 100644 --- a/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java +++ b/src/main/java/electroblob/wizardry/item/ItemFlamingAxe.java @@ -1,10 +1,19 @@ package electroblob.wizardry.item; +import com.google.common.collect.Multimap; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; import net.minecraft.item.ItemAxe; import net.minecraft.item.ItemStack; import net.minecraft.world.World; @@ -13,21 +22,42 @@ import net.minecraftforge.fml.relauncher.SideOnly; public class ItemFlamingAxe extends ItemAxe implements IConjuredItem { + private EnumRarity rarity = EnumRarity.COMMON; + public ItemFlamingAxe(ToolMaterial material){ super(material, 8, -3); - setMaxDamage(getBaseDuration()); + setMaxDamage(1200); // Might cause problems if removed, the actual number is irrelevant as long as it's > 0 setNoRepair(); setCreativeTab(null); + addAnimationPropertyOverrides(); } @Override - public int getBaseDuration(){ - return 1200; + public Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack){ + + Multimap multimap = super.getItemAttributeModifiers(slot); + + if(slot == EntityEquipmentSlot.MAINHAND){ + multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(POTENCY_MODIFIER, + "Potency modifier", IConjuredItem.getDamageMultiplier(stack) - 1, WizardryUtilities.Operations.MULTIPLY_CUMULATIVE)); + } + + return multimap; + } + + public Item setRarity(EnumRarity rarity){ + this.rarity = rarity; + return this; + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return rarity; } @Override public int getMaxDamage(ItemStack stack){ - return this.getMaxDamageFromNBT(stack); + return this.getMaxDamageFromNBT(stack, Spells.flaming_axe); } @Override @@ -50,9 +80,16 @@ public class ItemFlamingAxe extends ItemAxe implements IConjuredItem { stack.setItemDamage(damage + 1); } + @Override + public Multimap getItemAttributeModifiers(EntityEquipmentSlot equipmentSlot){ + attackDamage = Spells.flaming_axe.getProperty(Spell.DAMAGE).floatValue(); + return super.getItemAttributeModifiers(equipmentSlot); + } + @Override public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder){ - if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)) target.setFire(8); + if(!MagicDamage.isEntityImmune(DamageType.FIRE, target)) + target.setFire(Spells.flaming_axe.getProperty(Spell.BURN_DURATION).intValue()); return false; } @@ -72,6 +109,16 @@ public class ItemFlamingAxe extends ItemAxe implements IConjuredItem { return 0; } + @Override + public boolean isEnchantable(ItemStack stack){ + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack stack, ItemStack book){ + return false; + } + // Cannot be dropped @Override public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ diff --git a/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java b/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java index 159d1229..cca0d046 100644 --- a/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java +++ b/src/main/java/electroblob/wizardry/item/ItemFrostAxe.java @@ -1,11 +1,19 @@ package electroblob.wizardry.item; +import com.google.common.collect.Multimap; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; import net.minecraft.item.ItemAxe; import net.minecraft.item.ItemStack; import net.minecraft.potion.PotionEffect; @@ -15,21 +23,42 @@ import net.minecraftforge.fml.relauncher.SideOnly; public class ItemFrostAxe extends ItemAxe implements IConjuredItem { + private EnumRarity rarity = EnumRarity.COMMON; + public ItemFrostAxe(ToolMaterial material){ super(material, 8, -3); - setMaxDamage(getBaseDuration()); + setMaxDamage(1200); setNoRepair(); setCreativeTab(null); + addAnimationPropertyOverrides(); } @Override - public int getBaseDuration(){ - return 1200; + public Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack){ + + Multimap multimap = super.getItemAttributeModifiers(slot); + + if(slot == EntityEquipmentSlot.MAINHAND){ + multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(POTENCY_MODIFIER, + "Potency modifier", IConjuredItem.getDamageMultiplier(stack) - 1, WizardryUtilities.Operations.MULTIPLY_CUMULATIVE)); + } + + return multimap; + } + + public Item setRarity(EnumRarity rarity){ + this.rarity = rarity; + return this; + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return rarity; } @Override public int getMaxDamage(ItemStack stack){ - return this.getMaxDamageFromNBT(stack); + return this.getMaxDamageFromNBT(stack, Spells.frost_axe); } @Override @@ -75,6 +104,16 @@ public class ItemFrostAxe extends ItemAxe implements IConjuredItem { return 0; } + @Override + public boolean isEnchantable(ItemStack stack){ + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack stack, ItemStack book){ + return false; + } + // Cannot be dropped @Override public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ diff --git a/src/main/java/electroblob/wizardry/item/ItemIdentificationScroll.java b/src/main/java/electroblob/wizardry/item/ItemIdentificationScroll.java index 8a560c5b..61375b1e 100644 --- a/src/main/java/electroblob/wizardry/item/ItemIdentificationScroll.java +++ b/src/main/java/electroblob/wizardry/item/ItemIdentificationScroll.java @@ -1,19 +1,14 @@ package electroblob.wizardry.item; -import java.util.List; - -import javax.annotation.Nullable; - -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.event.DiscoverSpellEvent; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardryTabs; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumRarity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; @@ -25,6 +20,9 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import javax.annotation.Nullable; +import java.util.List; + public class ItemIdentificationScroll extends Item { public ItemIdentificationScroll(){ @@ -38,11 +36,15 @@ public class ItemIdentificationScroll extends Item { return true; } + @Override + public EnumRarity getRarity(ItemStack stack){ + return EnumRarity.UNCOMMON; + } + @Override @SideOnly(Side.CLIENT) - public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { - tooltip.add(net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":identification_scroll.desc1", "\u00A77")); - tooltip.add(net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":identification_scroll.desc2", "\u00A77")); + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, net.minecraft.client.util.ITooltipFlag flag) { + Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc"); } @Override @@ -52,27 +54,26 @@ public class ItemIdentificationScroll extends Item { if(WizardData.get(player) != null){ - WizardData properties = WizardData.get(player); + WizardData data = WizardData.get(player); for(ItemStack stack1 : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){ if(!stack1.isEmpty()){ - Spell spell = Spell.get(stack1.getItemDamage()); + Spell spell = Spell.byMetadata(stack1.getItemDamage()); if((stack1.getItem() instanceof ItemSpellBook || stack1.getItem() instanceof ItemScroll) - && !properties.hasSpellBeenDiscovered(spell)){ + && !data.hasSpellBeenDiscovered(spell)){ if(!MinecraftForge.EVENT_BUS.post(new DiscoverSpellEvent(player, spell, DiscoverSpellEvent.Source.IDENTIFICATION_SCROLL))){ // Identification scrolls give the chat readout in creative mode, otherwise it looks like // nothing happens! - properties.discoverSpell(spell); - WizardryAdvancementTriggers.identify_spell.triggerFor(player); - player.playSound(SoundEvents.ENTITY_PLAYER_LEVELUP, 1.25f, 1); - if(!player.capabilities.isCreativeMode) stack.shrink(1); + data.discoverSpell(spell); + player.playSound(WizardrySounds.MISC_DISCOVER_SPELL, 1.25f, 1); + if(!player.isCreative()) stack.shrink(1); if(!world.isRemote) player.sendMessage(new TextComponentTranslation("spell.discover", spell.getNameForTranslationFormatted())); - return new ActionResult(EnumActionResult.SUCCESS, stack); + return new ActionResult<>(EnumActionResult.SUCCESS, stack); } } } @@ -82,7 +83,7 @@ public class ItemIdentificationScroll extends Item { new TextComponentTranslation("item." + Wizardry.MODID + ":identification_scroll.nothing_to_identify")); } - return new ActionResult(EnumActionResult.FAIL, stack); + return new ActionResult<>(EnumActionResult.FAIL, stack); } } diff --git a/src/main/java/electroblob/wizardry/item/ItemLightningHammer.java b/src/main/java/electroblob/wizardry/item/ItemLightningHammer.java new file mode 100644 index 00000000..0b7d40cd --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemLightningHammer.java @@ -0,0 +1,220 @@ +package electroblob.wizardry.item; + +import com.google.common.collect.Multimap; +import electroblob.wizardry.entity.construct.EntityHammer; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.LightningHammer; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.player.AttackEntityEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.List; +import java.util.UUID; + +@Mod.EventBusSubscriber +public class ItemLightningHammer extends Item implements IConjuredItem { + + public static final String DURATION_NBT_KEY = "duration"; + // Annoyingly we can't implement this for attack damage, but at least it gets saved for when the hammer is thrown + public static final String DAMAGE_MULTIPLIER_NBT_KEY = "damageMultiplier"; + + public static final UUID MOVEMENT_SPEED_MODIFIER = UUID.fromString("d4c3bd93-c8e3-49c5-b35b-9356663bad1b"); + + private static final double ATTACK_SPEED = -3.2; + private static final double CHAINING_RANGE = 4; + private static final float CHAINING_DAMAGE = 4; + private static final double THROW_SPEED = 0.75; + private static final double MOVEMENT_SPEED_REDUCTION = -0.25; + + public ItemLightningHammer(){ + super(); + setMaxDamage(600); + setMaxStackSize(1); + setNoRepair(); + setCreativeTab(null); + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return EnumRarity.EPIC; + } + + @Override + public int getMaxDamage(ItemStack stack){ + if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DURATION_NBT_KEY)){ + return stack.getTagCompound().getInteger(DURATION_NBT_KEY); + } + return super.getMaxDamage(stack); + } + + private float getDamageMultiplier(ItemStack stack){ + if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DAMAGE_MULTIPLIER_NBT_KEY)){ + return stack.getTagCompound().getFloat(DAMAGE_MULTIPLIER_NBT_KEY); + } + return 1; + } + + @Override + public Multimap getItemAttributeModifiers(EntityEquipmentSlot slot){ + + Multimap multimap = super.getItemAttributeModifiers(slot); + + if(slot == EntityEquipmentSlot.MAINHAND){ + multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", Spells.lightning_hammer.getProperty(Spell.DIRECT_DAMAGE).floatValue(), WizardryUtilities.Operations.ADD)); + multimap.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), new AttributeModifier(ATTACK_SPEED_MODIFIER, "Weapon modifier", ATTACK_SPEED, WizardryUtilities.Operations.ADD)); + multimap.put(SharedMonsterAttributes.MOVEMENT_SPEED.getName(), new AttributeModifier(MOVEMENT_SPEED_MODIFIER, "Weapon modifier", MOVEMENT_SPEED_REDUCTION, WizardryUtilities.Operations.MULTIPLY_FLAT)); + } + + return multimap; + } + + @Override + // This method allows the code for the item's timer to be greatly simplified by damaging it directly from + // onUpdate() and removing the workaround that involved WizardData and all sorts of crazy stuff. + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ + + if(!oldStack.isEmpty() || !newStack.isEmpty()){ + // We only care about the situation where we specifically want the animation NOT to play. + if(oldStack.getItem() == newStack.getItem() && !slotChanged) return false; + } + + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean selected){ + int damage = stack.getItemDamage(); + if(damage > stack.getMaxDamage()) entity.replaceItemInInventory(slot, ItemStack.EMPTY); + stack.setItemDamage(damage + 1); + } + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand){ + + ItemStack stack = player.getHeldItem(hand); + + if(!world.isRemote){ + EntityHammer hammer = new EntityHammer(world); + Vec3d look = player.getLookVec(); + Vec3d vec = player.getPositionEyes(1).add(look); + hammer.setPositionAndRotation(vec.x, vec.y - hammer.height/2, vec.z, player.rotationYawHead - 90, 0); + // For some reason the above method insists on clamping the pitch to between -90 and 90 + hammer.rotationPitch = 180 + player.rotationPitch; + hammer.prevRotationPitch = hammer.rotationPitch; + + float attackStrength = player.getCooledAttackStrength(0); + double speed = THROW_SPEED * attackStrength; // Throw distance depends on the attack meter + hammer.addVelocity(look.x * speed, look.y * speed, look.z * speed); + hammer.lifetime = stack.getMaxDamage() - stack.getItemDamage(); + hammer.setCaster(player); + hammer.damageMultiplier = getDamageMultiplier(stack); + hammer.spin = true; + world.spawnEntity(hammer); + } + + WizardryUtilities.playSoundAtPlayer(player, WizardrySounds.ENTITY_HAMMER_THROW, 1.0F, 0.8f); + + //player.swingArm(hand); + + // Use this instead of stack.shrink so it works regardless of whether the player is in creative mode or not + player.setHeldItem(hand, ItemStack.EMPTY); + + return ActionResult.newResult(EnumActionResult.SUCCESS, stack); + } + + @Override + public boolean getIsRepairable(ItemStack stack, ItemStack par2ItemStack){ + return false; + } + + @Override + public int getItemEnchantability(){ + return 0; + } + + @Override + public boolean isEnchantable(ItemStack stack){ + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack stack, ItemStack book){ + return false; + } + + // Cannot be dropped + @Override + public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ + return false; + } + + // Can't be done in hitEntity because that's only called server-side, and after the cooldown is reset + @SubscribeEvent + public static void onAttackEntityEvent(AttackEntityEvent event){ + + ItemStack stack = event.getEntityPlayer().getHeldItemMainhand(); + + if(stack.getItem() instanceof ItemLightningHammer && event.getTarget() instanceof EntityLivingBase){ + + EntityPlayer wielder = event.getEntityPlayer(); + EntityLivingBase hit = (EntityLivingBase)event.getTarget(); + + float attackStrength = wielder.getCooledAttackStrength(0); + + double dx = wielder.posX - hit.posX; + double dz; + for(dz = wielder.posZ - hit.posZ; dx * dx + dz * dz < 1.0E-4D; dz = (Math.random() - Math.random()) + * 0.01D){ + dx = (Math.random() - Math.random()) * 0.01D; + } + + hit.knockBack(wielder, 2 * attackStrength, dx, dz); + + if(attackStrength == 1){ // Only chains when the attack meter is full + + List nearby = WizardryUtilities.getEntitiesWithinRadius(CHAINING_RANGE, hit.posX, hit.posY, hit.posZ, hit.world); + + nearby.remove(hit); + nearby.remove(wielder); + // When held, the number of chaining targets is halved + int maxTargets = Spells.lightning_hammer.getProperty(LightningHammer.SECONDARY_MAX_TARGETS).intValue() / 2; + while(nearby.size() > maxTargets) nearby.remove(nearby.size() - 1); + + for(EntityLivingBase target : nearby){ + + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(wielder, DamageType.SHOCK), CHAINING_DAMAGE * ((ItemLightningHammer)stack.getItem()).getDamageMultiplier(stack)); + + if(hit.world.isRemote){ + ParticleBuilder.create(Type.LIGHTNING).pos(hit.getPositionVector().add(0, hit.height / 2, 0)) + .target(target).spawn(hit.world); + ParticleBuilder.spawnShockParticles(hit.world, target.posX, target.getEntityBoundingBox().minY + target.height / 2, target.posZ); + } + + //target.playSound(WizardrySounds.SPELL_SPARK, 1, 1.5f + 0.4f * world.rand.nextFloat()); + } + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/item/ItemManaFlask.java b/src/main/java/electroblob/wizardry/item/ItemManaFlask.java new file mode 100644 index 00000000..8823b632 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemManaFlask.java @@ -0,0 +1,37 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public class ItemManaFlask extends Item { + + public enum Size { + + SMALL(75, EnumRarity.COMMON), + MEDIUM(700, EnumRarity.COMMON), + LARGE(1400, EnumRarity.RARE); + + public int capacity; + public EnumRarity rarity; + + Size(int capacity, EnumRarity rarity){ + this.capacity = capacity; + this.rarity = rarity; + } + } + + public final Size size; + + public ItemManaFlask(Size size){ + super(); + this.size = size; + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return size.rarity; + } +} diff --git a/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java b/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java index 76a9f12a..a68c8aa4 100644 --- a/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java +++ b/src/main/java/electroblob/wizardry/item/ItemPoisonBomb.java @@ -1,9 +1,9 @@ package electroblob.wizardry.item; import electroblob.wizardry.entity.projectile.EntityPoisonBomb; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardryTabs; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; @@ -23,15 +23,15 @@ public class ItemPoisonBomb extends Item { ItemStack stack = player.getHeldItem(hand); - if(!player.capabilities.isCreativeMode){ + if(!player.isCreative()){ stack.shrink(1); } - player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); + player.playSound(WizardrySounds.ENTITY_POISON_BOMB_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); if(!world.isRemote){ EntityPoisonBomb poisonbomb = new EntityPoisonBomb(world); - poisonbomb.aim(player, 1.5f); + poisonbomb.aim(player, 1); world.spawnEntity(poisonbomb); } diff --git a/src/main/java/electroblob/wizardry/item/ItemPurifyingElixir.java b/src/main/java/electroblob/wizardry/item/ItemPurifyingElixir.java new file mode 100644 index 00000000..785ed409 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemPurifyingElixir.java @@ -0,0 +1,99 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Items; +import net.minecraft.item.EnumAction; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundCategory; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import javax.annotation.Nullable; +import java.util.List; + +public class ItemPurifyingElixir extends Item { + + public ItemPurifyingElixir(){ + this.setMaxStackSize(1); + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public boolean hasEffect(ItemStack stack){ + return true; + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return EnumRarity.RARE; + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, net.minecraft.client.util.ITooltipFlag flag) { + Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc"); + } + + @Override + public ItemStack onItemUseFinish(ItemStack stack, World world, EntityLivingBase entity){ + + if(!world.isRemote){ + entity.curePotionEffects(stack); + }else{ + + ParticleBuilder.spawnHealParticles(world, entity); + + for(int i = 0; i < 20; i++){ + double x = entity.posX + world.rand.nextDouble() * 2 - 1; + double y = entity.getEntityBoundingBox().minY + entity.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = entity.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.14, 0).clr(0x0f001b) + .time(20 + world.rand.nextInt(12)).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0x0f001b).spawn(world); + } + } + + world.playSound(entity.posX, entity.posY, entity.posZ, WizardrySounds.ITEM_PURIFYING_ELIXIR_DRINK, SoundCategory.PLAYERS, 1, 1, false); + + if(entity instanceof EntityPlayerMP){ + EntityPlayerMP entityplayermp = (EntityPlayerMP)entity; + CriteriaTriggers.CONSUME_ITEM.trigger(entityplayermp, stack); + } + + if(entity instanceof EntityPlayer && !((EntityPlayer)entity).capabilities.isCreativeMode){ + stack.shrink(1); + } + + return stack.isEmpty() ? new ItemStack(Items.GLASS_BOTTLE) : stack; + } + + @Override + public int getMaxItemUseDuration(ItemStack stack){ + return 32; + } + + @Override + public EnumAction getItemUseAction(ItemStack stack){ + return EnumAction.DRINK; + } + + @Override + public ActionResult onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn){ + playerIn.setActiveHand(handIn); + return new ActionResult<>(EnumActionResult.SUCCESS, playerIn.getHeldItem(handIn)); + } +} diff --git a/src/main/java/electroblob/wizardry/item/ItemScroll.java b/src/main/java/electroblob/wizardry/item/ItemScroll.java index 6f91757f..d793782b 100644 --- a/src/main/java/electroblob/wizardry/item/ItemScroll.java +++ b/src/main/java/electroblob/wizardry/item/ItemScroll.java @@ -8,7 +8,6 @@ import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.WizardryTabs; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; -import net.minecraft.client.gui.FontRenderer; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -24,10 +23,9 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -public class ItemScroll extends Item { +public class ItemScroll extends Item implements ISpellCastingItem { /** The maximum number of ticks a continuous spell scroll can be cast for (by holding the use item button). */ - // TODO: Make this configurable public static final int CASTING_TIME = 120; public ItemScroll(){ @@ -36,14 +34,24 @@ public class ItemScroll extends Item { setMaxStackSize(16); setCreativeTab(WizardryTabs.SPELLS); } + + @Override + public Spell getCurrentSpell(ItemStack stack){ + return Spell.byMetadata(stack.getItemDamage()); + } + + @Override + public boolean showSpellHUD(EntityPlayer player, ItemStack stack){ + return false; + } @Override public void getSubItems(CreativeTabs tab, NonNullList list){ if(tab == WizardryTabs.SPELLS){ // In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance - // is not required, only the id. + // is not required, only the metadata. for(int i = 0; i < Spell.getTotalSpellCount(); i++){ - // i+1 is used so that the metadata ties up with the id() method. In other words, the none spell has id + // i+1 is used so that the metadata ties up with the metadata() method. In other words, the none spell has metadata // 0 and since this is not used as a spell book the metadata starts at 1. list.add(new ItemStack(this, 1, i + 1)); } @@ -83,54 +91,25 @@ public class ItemScroll extends Item { ItemStack stack = player.getHeldItem(hand); - Spell spell = Spell.get(stack.getItemDamage()); + Spell spell = Spell.byMetadata(stack.getItemDamage()); // By default, scrolls have no modifiers - but with the event system, they could be added. SpellModifiers modifiers = new SpellModifiers(); - // If anything stops the spell working at this point, nothing else happens. - if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(player, spell, modifiers, Source.SCROLL))){ - return new ActionResult(EnumActionResult.FAIL, stack); - } - - // Now we can cast continuous spells with scrolls! - if(spell.isContinuous){ - if(!player.isHandActive()){ - player.setActiveHand(hand); - return new ActionResult(EnumActionResult.SUCCESS, stack); - } - }else{ - - if(!world.isRemote){ - - if(spell.cast(world, player, hand, 0, new SpellModifiers())){ - - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(player, spell, modifiers, Source.SCROLL)); - - if(spell.doesSpellRequirePacket()){ - // Sends a packet to all players in dimension to tell them to spawn particles. - IMessage msg = new PacketCastSpell.Message(player.getEntityId(), hand, spell.id(), modifiers); - WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); - } - - // Scrolls are consumed upon successful use in survival mode - if(!player.capabilities.isCreativeMode) stack.shrink(1); - - return new ActionResult(EnumActionResult.SUCCESS, stack); + if(canCast(stack, spell, player, hand, 0, modifiers)){ + // Now we can cast continuous spells with scrolls! + if(spell.isContinuous){ + if(!player.isHandActive()){ + player.setActiveHand(hand); + return new ActionResult<>(EnumActionResult.SUCCESS, stack); } - - // This else if check was bugging me for AGES! I can't believe I didn't compare to ItemWand before. - }else if(!spell.doesSpellRequirePacket()){ - // Client-inconsistent spell casting. This code only runs client-side. - if(spell.cast(world, player, hand, 0, modifiers)){ - // This is all that needs to happen, because everything above works fine on just the server side. - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(player, spell, modifiers, Source.SCROLL)); - return new ActionResult(EnumActionResult.SUCCESS, stack); + }else{ + if(cast(stack, spell, player, hand, 0, modifiers)){ + return new ActionResult<>(EnumActionResult.SUCCESS, stack); } } } - return new ActionResult(EnumActionResult.FAIL, stack); - + return new ActionResult<>(EnumActionResult.FAIL, stack); } // For continuous spells. The count argument actually decrements by 1 each tick. @@ -141,31 +120,68 @@ public class ItemScroll extends Item { EntityPlayer player = (EntityPlayer)user; - Spell spell = Spell.get(stack.getItemDamage()); + Spell spell = Spell.byMetadata(stack.getItemDamage()); // By default, scrolls have no modifiers - but with the event system, they could be added. SpellModifiers modifiers = new SpellModifiers(); int castingTick = stack.getMaxItemUseDuration() - count; - if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(Source.SCROLL, spell, player, modifiers, castingTick))) - return; - // Continuous spells (these must check if they can be cast each tick since the mana changes) - if(spell.isContinuous){ - - if(spell.cast(player.world, player, player.getActiveHand(), castingTick, modifiers)){ - - if(castingTick == 0) - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.SCROLL, spell, player, modifiers)); - } + // In theory the spell is always continuous here but just in case it isn't... + if(spell.isContinuous && canCast(stack, spell, player, player.getActiveHand(), castingTick, modifiers)){ + cast(stack, spell, player, player.getActiveHand(), castingTick, modifiers); + }else{ + // Scrolls normally work on the max use duration so this isn't ever reached by wizardry, but if the + // casting was interrupted by SpellCastEvent.Tick it will be used + player.stopActiveHand(); } } } + + @Override + public boolean canCast(ItemStack stack, Spell spell, EntityPlayer caster, EnumHand hand, int castingTick, SpellModifiers modifiers){ + // Even neater! + if(castingTick == 0){ + return !MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(Source.SCROLL, spell, caster, modifiers)); + }else{ + return !MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(Source.SCROLL, spell, caster, modifiers, castingTick)); + } + } + + @Override + public boolean cast(ItemStack stack, Spell spell, EntityPlayer caster, EnumHand hand, int castingTick, SpellModifiers modifiers){ + + World world = caster.world; + + if(world.isRemote && !spell.isContinuous && spell.requiresPacket()) return false; + + if(spell.cast(world, caster, hand, castingTick, modifiers)){ + + if(castingTick == 0) MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.SCROLL, spell, caster, modifiers)); + + if(!world.isRemote){ + + // Continuous spells never require packets so don't rely on the requiresPacket method to specify it + if(!spell.isContinuous && spell.requiresPacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + IMessage msg = new PacketCastSpell.Message(caster.getEntityId(), hand, spell, modifiers); + WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); + } + + // Scrolls are consumed upon successful use in survival mode + if(!spell.isContinuous && !caster.isCreative()) stack.shrink(1); + } + + return true; + } + + return false; + } @Override public void onPlayerStoppedUsing(ItemStack stack, World world, EntityLivingBase user, int timeLeft){ // Consumes a continuous spell scroll when a player in survival mode stops using it. - if(Spell.get(stack.getItemDamage()).isContinuous - && (!(user instanceof EntityPlayer) || !((EntityPlayer)user).capabilities.isCreativeMode)){ + if(Spell.byMetadata(stack.getItemDamage()).isContinuous + && (!(user instanceof EntityPlayer) || !((EntityPlayer)user).isCreative())){ stack.shrink(1); } } @@ -173,8 +189,8 @@ public class ItemScroll extends Item { @Override public ItemStack onItemUseFinish(ItemStack stack, World world, EntityLivingBase user){ // Consumes a continuous spell scroll when the casting elapses whilst in use by a player in survival mode. - if(Spell.get(stack.getItemDamage()).isContinuous - && (!(user instanceof EntityPlayer) || !((EntityPlayer)user).capabilities.isCreativeMode)){ + if(Spell.byMetadata(stack.getItemDamage()).isContinuous + && (!(user instanceof EntityPlayer) || !((EntityPlayer)user).isCreative())){ stack.shrink(1); } @@ -183,7 +199,7 @@ public class ItemScroll extends Item { @Override @SideOnly(Side.CLIENT) - public FontRenderer getFontRenderer(ItemStack stack){ + public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack){ return Wizardry.proxy.getFontRenderer(stack); } } diff --git a/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java b/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java index 880a84c4..a62a1179 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java +++ b/src/main/java/electroblob/wizardry/item/ItemSmokeBomb.java @@ -1,9 +1,9 @@ package electroblob.wizardry.item; import electroblob.wizardry.entity.projectile.EntitySmokeBomb; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardryTabs; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; @@ -23,15 +23,15 @@ public class ItemSmokeBomb extends Item { ItemStack stack = player.getHeldItem(hand); - if(!player.capabilities.isCreativeMode){ + if(!player.isCreative()){ stack.shrink(1); } - player.playSound(SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); + player.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); if(!world.isRemote){ EntitySmokeBomb smokebomb = new EntitySmokeBomb(world); - smokebomb.aim(player, 1.5f); + smokebomb.aim(player, 1); world.spawnEntity(smokebomb); } diff --git a/src/main/java/electroblob/wizardry/item/ItemSparkBomb.java b/src/main/java/electroblob/wizardry/item/ItemSparkBomb.java new file mode 100644 index 00000000..319b3dae --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemSparkBomb.java @@ -0,0 +1,41 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.entity.projectile.EntitySparkBomb; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class ItemSparkBomb extends Item { + + public ItemSparkBomb(){ + setMaxStackSize(16); + setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand){ + + ItemStack stack = player.getHeldItem(hand); + + if(!player.isCreative()){ + stack.shrink(1); + } + + player.playSound(WizardrySounds.ENTITY_SPARK_BOMB_THROW, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F)); + + if(!world.isRemote){ + EntitySparkBomb sparkBomb = new EntitySparkBomb(world); + sparkBomb.aim(player, 1); + world.spawnEntity(sparkBomb); + } + + return ActionResult.newResult(EnumActionResult.SUCCESS, stack); + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java b/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java index e457e2dd..afa653b8 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralArmour.java @@ -1,7 +1,6 @@ package electroblob.wizardry.item; -import net.minecraft.client.model.ModelBiped; -import net.minecraft.client.renderer.GlStateManager; +import electroblob.wizardry.registry.Spells; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -18,17 +17,12 @@ public class ItemSpectralArmour extends ItemArmor implements IConjuredItem { public ItemSpectralArmour(ArmorMaterial material, int renderIndex, EntityEquipmentSlot armourType){ super(material, renderIndex, armourType); setCreativeTab(null); - setMaxDamage(getBaseDuration()); - } - - @Override - public int getBaseDuration(){ - return 1800; + setMaxDamage(1200); } @Override public int getMaxDamage(ItemStack stack){ - return this.getMaxDamageFromNBT(stack); + return this.getMaxDamageFromNBT(stack, Spells.conjure_armour); } // Overridden to stop the enchantment trick making the name turn blue. @@ -73,6 +67,16 @@ public class ItemSpectralArmour extends ItemArmor implements IConjuredItem { return 0; } + @Override + public boolean isEnchantable(ItemStack stack){ + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack stack, ItemStack book){ + return false; + } + // Cannot be dropped @Override public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ @@ -89,14 +93,14 @@ public class ItemSpectralArmour extends ItemArmor implements IConjuredItem { @Override @SideOnly(Side.CLIENT) - public ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, - EntityEquipmentSlot armorSlot, ModelBiped _default){ - GlStateManager.enableBlend(); - GlStateManager.tryBlendFuncSeparate( - GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, - GlStateManager.SourceFactor.ONE, - GlStateManager.DestFactor.ZERO + public net.minecraft.client.model.ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, + EntityEquipmentSlot armorSlot, net.minecraft.client.model.ModelBiped _default){ + net.minecraft.client.renderer.GlStateManager.enableBlend(); + net.minecraft.client.renderer.GlStateManager.tryBlendFuncSeparate( + net.minecraft.client.renderer.GlStateManager.SourceFactor.SRC_ALPHA, + net.minecraft.client.renderer.GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + net.minecraft.client.renderer.GlStateManager.SourceFactor.ONE, + net.minecraft.client.renderer.GlStateManager.DestFactor.ZERO ); return super.getArmorModel(entityLiving, itemStack, armorSlot, _default); } diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java b/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java index 6ebf1cf0..421b5b8c 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralBow.java @@ -1,9 +1,7 @@ package electroblob.wizardry.item; -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; -import net.minecraft.client.Minecraft; +import electroblob.wizardry.registry.Spells; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -17,20 +15,18 @@ import net.minecraft.item.ItemArrow; import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; import net.minecraft.stats.StatList; -import net.minecraft.util.ActionResult; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumHand; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.SoundCategory; +import net.minecraft.util.*; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import javax.annotation.Nullable; + public class ItemSpectralBow extends ItemBow implements IConjuredItem { public ItemSpectralBow(){ super(); - setMaxDamage(getBaseDuration()); + setMaxDamage(1200); setNoRepair(); setCreativeTab(null); this.addPropertyOverride(new ResourceLocation("pull"), new IItemPropertyGetter(){ @@ -40,7 +36,6 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem { return 0.0F; }else{ ItemStack itemstack = entityIn.getActiveItemStack(); - // Mojang, observe - hardcoding item references into their own classes is NOT good Java. return itemstack.getItem() == ItemSpectralBow.this ? (float)(stack.getMaxItemUseDuration() - entityIn.getItemInUseCount()) / 20.0F : 0.0F; @@ -54,6 +49,7 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem { : 0.0F; } }); + addAnimationPropertyOverrides(); } @Override @@ -63,14 +59,9 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem { return true; } - @Override - public int getBaseDuration(){ - return 1200; - } - @Override public int getMaxDamage(ItemStack stack){ - return this.getMaxDamageFromNBT(stack); + return this.getMaxDamageFromNBT(stack, Spells.conjure_bow); } @Override @@ -78,27 +69,38 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem { // onUpdate() and removing the workaround that involved WizardData and all sorts of crazy stuff. public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ - // TODO: For some reason there used to be an && here instead of an ||, which makes me wonder if there's a weird - // fix I did that needs removing. if(!oldStack.isEmpty() || !newStack.isEmpty()){ // We only care about the situation where we specifically want the animation NOT to play. if(oldStack.getItem() == newStack.getItem() && !slotChanged // This code should only run on the client side, so using Minecraft is ok. - && !Minecraft.getMinecraft().player.isHandActive()) + && !net.minecraft.client.Minecraft.getMinecraft().player.isHandActive()) return false; } return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); } + // Copied fixes from ItemWand made possible by recently-added Forge hooks + + @Override + public boolean canContinueUsing(ItemStack oldStack, ItemStack newStack){ + // Ignore durability changes + if(ItemStack.areItemsEqualIgnoreDurability(oldStack, newStack)) return true; + return super.canContinueUsing(oldStack, newStack); + } + + @Override + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack){ + // Ignore durability changes + if(ItemStack.areItemsEqualIgnoreDurability(oldStack, newStack)) return false; + return super.shouldCauseBlockBreakReset(oldStack, newStack); + } + @Override public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean selected){ int damage = stack.getItemDamage(); if(damage > stack.getMaxDamage()) entity.replaceItemInInventory(slot, ItemStack.EMPTY); - // Can't damage it whilst in use because for some reason it causes the item use to constantly reset. - if(!(entity instanceof EntityLivingBase) || !((EntityLivingBase)entity).isHandActive()){ - stack.setItemDamage(damage + 1); - } + stack.setItemDamage(damage + 1); } // The following two methods re-route the displayed durability through the proxies in order to override the pausing @@ -145,19 +147,29 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem { return 0; } + @Override + public boolean isEnchantable(ItemStack stack){ + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack stack, ItemStack book){ + return false; + } + // Cannot be dropped @Override public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ return false; } - @Override - public void onUsingTick(ItemStack stack, EntityLivingBase player, int count){ - // player.getItemInUseMaxCount() is named incorrectly; you only have to look at the method to see what it really - // does. - if(stack.getItemDamage() + player.getItemInUseMaxCount() > stack.getMaxDamage()) - player.replaceItemInInventory(player.getActiveHand() == EnumHand.MAIN_HAND ? 98 : 99, ItemStack.EMPTY); - } +// @Override +// public void onUsingTick(ItemStack stack, EntityLivingBase player, int count){ +// // player.getItemInUseMaxCount() is named incorrectly; you only have to look at the method to see what it really +// // does. +// if(stack.getItemDamage() + player.getItemInUseMaxCount() > stack.getMaxDamage()) +// player.replaceItemInInventory(player.getActiveHand() == EnumHand.MAIN_HAND ? 98 : 99, ItemStack.EMPTY); +// } @Override public void onPlayerStoppedUsing(ItemStack stack, World world, EntityLivingBase entity, int timeLeft){ @@ -205,10 +217,12 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem { entityarrow.pickupStatus = EntityArrow.PickupStatus.DISALLOWED; + entityarrow.setDamage(entityarrow.getDamage() * IConjuredItem.getDamageMultiplier(stack)); + world.spawnEntity(entityarrow); } - world.playSound((EntityPlayer)null, entityplayer.posX, entityplayer.posY, entityplayer.posZ, + world.playSound(null, entityplayer.posX, entityplayer.posY, entityplayer.posZ, SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.NEUTRAL, 1.0F, 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + f * 0.5F); diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java b/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java index f178d1a3..3f40556e 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralPickaxe.java @@ -1,30 +1,44 @@ package electroblob.wizardry.item; +import electroblob.wizardry.registry.Spells; +import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; import net.minecraft.item.ItemPickaxe; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import javax.annotation.Nullable; + public class ItemSpectralPickaxe extends ItemPickaxe implements IConjuredItem { + private EnumRarity rarity = EnumRarity.COMMON; + public ItemSpectralPickaxe(ToolMaterial material){ super(material); - setMaxDamage(getBaseDuration()); + setMaxDamage(1200); setNoRepair(); setCreativeTab(null); + addAnimationPropertyOverrides(); + } + + public Item setRarity(EnumRarity rarity){ + this.rarity = rarity; + return this; } @Override - public int getBaseDuration(){ - return 1200; + public EnumRarity getRarity(ItemStack stack){ + return rarity; } @Override public int getMaxDamage(ItemStack stack){ - return this.getMaxDamageFromNBT(stack); + return this.getMaxDamageFromNBT(stack, Spells.conjure_pickaxe); } @Override @@ -47,6 +61,18 @@ public class ItemSpectralPickaxe extends ItemPickaxe implements IConjuredItem { stack.setItemDamage(damage + 1); } + @Override + public float getDestroySpeed(ItemStack stack, IBlockState state){ + float speed = super.getDestroySpeed(stack, state); + return speed > 1 ? speed * IConjuredItem.getDamageMultiplier(stack) : speed; + } + + @Override + public int getHarvestLevel(ItemStack stack, String toolClass, @Nullable EntityPlayer player, @Nullable IBlockState blockState){ + // Reuses the standard bonus amplifier calculation from SpellBuff to increase the mining level at advanced and master tier + return super.getHarvestLevel(stack, toolClass, player, blockState) + (int)((IConjuredItem.getDamageMultiplier(stack) - 1) / 0.4); + } + @Override @SideOnly(Side.CLIENT) public boolean hasEffect(ItemStack stack){ @@ -63,10 +89,19 @@ public class ItemSpectralPickaxe extends ItemPickaxe implements IConjuredItem { return 0; } + @Override + public boolean isEnchantable(ItemStack stack){ + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack stack, ItemStack book){ + return false; + } + // Cannot be dropped @Override public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ return false; } - } diff --git a/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java b/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java index 6a960b95..8a14bbab 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpectralSword.java @@ -1,7 +1,15 @@ package electroblob.wizardry.item; +import com.google.common.collect.Multimap; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemSword; import net.minecraft.world.World; @@ -10,21 +18,42 @@ import net.minecraftforge.fml.relauncher.SideOnly; public class ItemSpectralSword extends ItemSword implements IConjuredItem { + private EnumRarity rarity = EnumRarity.COMMON; + public ItemSpectralSword(ToolMaterial material){ super(material); - setMaxDamage(getBaseDuration()); + setMaxDamage(1200); setNoRepair(); setCreativeTab(null); + addAnimationPropertyOverrides(); } @Override - public int getBaseDuration(){ - return 1200; + public Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack){ + + Multimap multimap = super.getItemAttributeModifiers(slot); + + if(slot == EntityEquipmentSlot.MAINHAND){ + multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(POTENCY_MODIFIER, + "Potency modifier", IConjuredItem.getDamageMultiplier(stack) - 1, WizardryUtilities.Operations.MULTIPLY_CUMULATIVE)); + } + + return multimap; + } + + public Item setRarity(EnumRarity rarity){ + this.rarity = rarity; + return this; + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return rarity; } @Override public int getMaxDamage(ItemStack stack){ - return this.getMaxDamageFromNBT(stack); + return this.getMaxDamageFromNBT(stack, Spells.conjure_sword); } @Override @@ -63,6 +92,16 @@ public class ItemSpectralSword extends ItemSword implements IConjuredItem { return 0; } + @Override + public boolean isEnchantable(ItemStack stack){ + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack stack, ItemStack book){ + return false; + } + // Cannot be dropped @Override public boolean onDroppedByPlayer(ItemStack item, EntityPlayer player){ diff --git a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java index 359e5eac..a99dcd81 100644 --- a/src/main/java/electroblob/wizardry/item/ItemSpellBook.java +++ b/src/main/java/electroblob/wizardry/item/ItemSpellBook.java @@ -1,17 +1,10 @@ package electroblob.wizardry.item; -import java.util.List; - -import electroblob.wizardry.SpellGlyphData; -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; import electroblob.wizardry.WizardryGuiHandler; +import electroblob.wizardry.data.SpellGlyphData; import electroblob.wizardry.registry.WizardryTabs; import electroblob.wizardry.spell.Spell; -import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.EntityPlayerSP; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.util.ITooltipFlag; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; @@ -25,6 +18,8 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.oredict.OreDictionary; +import java.util.List; + public class ItemSpellBook extends Item { public ItemSpellBook(){ @@ -38,9 +33,9 @@ public class ItemSpellBook extends Item { public void getSubItems(CreativeTabs tab, NonNullList list){ if(tab == WizardryTabs.SPELLS){ // In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance - // is not required, only the id. + // is not required, only the metadata. for(int i = 0; i < Spell.getTotalSpellCount(); i++){ - // i+1 is used so that the metadata ties up with the id() method. In other words, the none spell has id + // i+1 is used so that the metadata ties up with the metadata() method. In other words, the none spell has metadata // 0 and since this is not used as a spell book the metadata starts at 1. list.add(new ItemStack(this, 1, i + 1)); } @@ -56,23 +51,19 @@ public class ItemSpellBook extends Item { @Override @SideOnly(Side.CLIENT) - public void addInformation(ItemStack itemstack, World world, List tooltip, ITooltipFlag advanced){ + public void addInformation(ItemStack itemstack, World world, List tooltip, net.minecraft.client.util.ITooltipFlag advanced){ // Tooltip is left blank for wizards buying generic spell books. - if(itemstack.getItemDamage() != OreDictionary.WILDCARD_VALUE){ - EntityPlayerSP player = Minecraft.getMinecraft().player; + if(world != null && itemstack.getItemDamage() != OreDictionary.WILDCARD_VALUE){ - Spell spell = Spell.get(itemstack.getItemDamage()); + Spell spell = Spell.byMetadata(itemstack.getItemDamage()); - boolean discovered = true; - if(player != null && Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null - && !WizardData.get(player).hasSpellBeenDiscovered(spell)){ - discovered = false; - } + boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(spell, itemstack); // Element colour is not given for undiscovered spells tooltip.add(discovered ? "\u00A77" + spell.getDisplayNameWithFormatting() - : "#\u00A79" + SpellGlyphData.getGlyphName(spell, player.world)); - tooltip.add(spell.tier.getDisplayNameWithFormatting()); + : "#\u00A79" + SpellGlyphData.getGlyphName(spell, world)); + + tooltip.add(spell.getTier().getDisplayNameWithFormatting()); } /* Removed to streamline the tooltip a bit. Information is now within the book. if(spell.isContinuous){ * tooltip.add("\u00A79Mana Cost: " + spell.cost + " per second"); }else{ tooltip.add("\u00A79Mana Cost: " + @@ -81,7 +72,7 @@ public class ItemSpellBook extends Item { @Override @SideOnly(Side.CLIENT) - public FontRenderer getFontRenderer(ItemStack stack){ + public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack){ return Wizardry.proxy.getFontRenderer(stack); } diff --git a/src/main/java/electroblob/wizardry/item/ItemWand.java b/src/main/java/electroblob/wizardry/item/ItemWand.java index 950a5a5d..1f663ff7 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWand.java +++ b/src/main/java/electroblob/wizardry/item/ItemWand.java @@ -1,34 +1,26 @@ package electroblob.wizardry.item; -import java.util.List; - -import electroblob.wizardry.SpellGlyphData; -import electroblob.wizardry.WizardData; +import com.google.common.collect.Multimap; import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.SpellGlyphData; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent.Source; import electroblob.wizardry.packet.PacketCastSpell; import electroblob.wizardry.packet.WizardryPacketHandler; -import electroblob.wizardry.registry.Spells; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardryTabs; +import electroblob.wizardry.registry.*; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.EntityPlayerSP; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.util.ITooltipFlag; +import electroblob.wizardry.util.*; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.inventory.Slot; @@ -38,46 +30,115 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.AttackEntityEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.List; +import java.util.Random; + /** - * This class is (literally) where the magic happens! All wand types are single instances of this class. There's a lot - * of quite hard-to-read code in here, but unfortunately there's not much I can do about that. For this reason, I have - * written the {@link WandHelper} class. I strongly recommend you use it for interacting with wand items wherever - * possible. - *

    - * It's unlikely that anything in this class will be of much use externally, but should you wish to use it for whatever - * reason (perhaps if you extend it), it works as follows: - *

    - * - onItemRightClick is where non-continuous spells are cast, and it sets the item in use for continuous spells
    - * - onUsingTick does the casting for continuous spells
    - * - onUpdate deals with the cooldowns for the spells - * + * This class is (literally) where the magic happens! All of wizardry's wand items are instances of this class. As of + * wizardry 4.2, it is no longer necessary to extend {@code ItemWand} thanks to {@link ISpellCastingItem}, though + * extending {@code ItemWand} may still be more appropriate for items using the same casting implementation. + *

    + * This class handles spell casting as follows: + *

    + * - {@code onItemRightClick} is where non-continuous spells are cast, and it sets the item in use for continuous spells
    + * - {@code onUsingTick} does the casting for continuous spells
    + * - {@code onUpdate} deals with the cooldowns for the spells
    + *
    + * See {@link ISpellCastingItem} for more detail on the {@code canCast(...)} and {@code cast(...)} methods.
    + * See {@link WandHelper} for everything related to wand NBT. + * * @since Wizardry 1.0 */ -public class ItemWand extends Item implements IWorkbenchItem { +@Mod.EventBusSubscriber +public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem, IManaStoringItem { /** The number of spell slots a wand has with no attunement upgrades applied. */ public static final int BASE_SPELL_SLOTS = 5; + /** The number of ticks between each time a continuous spell is added to the player's recently-cast spells. */ + private static final int CONTINUOUS_TRACKING_INTERVAL = 20; + /** The increase in progression for casting spells of the matching element. */ + private static final float ELEMENTAL_PROGRESSION_MODIFIER = 1.2f; + /** The fraction of progression lost when all recently-cast spells are the same as the one being cast. */ + private static final float MAX_PROGRESSION_REDUCTION = 0.75f; + public Tier tier; public Element element; public ItemWand(Tier tier, Element element){ super(); setMaxStackSize(1); - if(element == null || tier == Tier.BASIC){ - setCreativeTab(WizardryTabs.WIZARDRY); - } + setCreativeTab(WizardryTabs.GEAR); this.tier = tier; this.element = element; setMaxDamage(this.tier.maxCharge); + WizardryRecipes.addToManaFlaskCharging(this); + } + + @Override + public Spell getCurrentSpell(ItemStack stack){ + return WandHelper.getCurrentSpell(stack); + } + + @Override + public Spell[] getSpells(ItemStack stack){ + return WandHelper.getSpells(stack); + } + + @Override + public void selectNextSpell(ItemStack stack){ + WandHelper.selectNextSpell(stack); + } + + @Override + public void selectPreviousSpell(ItemStack stack){ + WandHelper.selectPreviousSpell(stack); + } + + @Override + public boolean showSpellHUD(EntityPlayer player, ItemStack stack){ + return true; + } + + @Override + public boolean showTooltip(ItemStack stack){ + return true; + } + + /** Does nothing, use {@link ItemWand#setMana(ItemStack, int)} to modify wand mana. */ + @Override + public void setDamage(ItemStack stack, int damage){ + // Overridden to do nothing to stop repair things from 'repairing' the mana in a wand + } + + @Override + public void setMana(ItemStack stack, int mana){ + // Using super (which can only be done from in here) bypasses the above override + super.setDamage(stack, getManaCapacity(stack) - mana); + } + + @Override + public int getMana(ItemStack stack){ + return getManaCapacity(stack) - getDamage(stack); + } + + @Override + public int getManaCapacity(ItemStack stack){ + return this.getMaxDamage(stack); } @Override @@ -88,40 +149,111 @@ public class ItemWand extends Item implements IWorkbenchItem { @Override @SideOnly(Side.CLIENT) - public FontRenderer getFontRenderer(ItemStack stack){ + public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack){ return Wizardry.proxy.getFontRenderer(stack); } + @Override + public boolean isEnchantable(ItemStack stack){ + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack stack, ItemStack book){ + return false; + } + + @Override + public boolean hasEffect(ItemStack stack){ + return !Wizardry.settings.legacyWandLevelling && this.tier.level < Tier.MASTER.level + && WandHelper.getProgression(stack) >= Tier.values()[tier.ordinal() + 1].progression; + } + // Max damage is modifiable with upgrades. @Override - public int getMaxDamage(ItemStack itemstack){ + public int getMaxDamage(ItemStack stack){ // + 0.5f corrects small float errors rounding down - return (int)(super.getMaxDamage(itemstack) * (1.0f + Constants.STORAGE_INCREASE_PER_LEVEL - * WandHelper.getUpgradeLevel(itemstack, WizardryItems.storage_upgrade)) + 0.5f); + return (int)(super.getMaxDamage(stack) * (1.0f + Constants.STORAGE_INCREASE_PER_LEVEL + * WandHelper.getUpgradeLevel(stack, WizardryItems.storage_upgrade)) + 0.5f); } @Override - public void onUpdate(ItemStack itemstack, World world, Entity entity, int slot, boolean isHeld){ + public void onCreated(ItemStack stack, World worldIn, EntityPlayer playerIn){ + setMana(stack, 0); // Wands are empty when first crafted + } - WandHelper.decrementCooldowns(itemstack); + @Override + public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean isHeld){ + + WandHelper.decrementCooldowns(stack); // Decrements wand damage (increases mana) every 1.5 seconds if it has a condenser upgrade - if(!world.isRemote && itemstack.isItemDamaged() - && world.getWorldTime() % Constants.CONDENSER_TICK_INTERVAL == 0){ + if(!world.isRemote && !this.isManaFull(stack) && world.getTotalWorldTime() % Constants.CONDENSER_TICK_INTERVAL == 0){ // If the upgrade level is 0, this does nothing anyway. - itemstack.setItemDamage( - itemstack.getItemDamage() - WandHelper.getUpgradeLevel(itemstack, WizardryItems.condenser_upgrade)); - } - - if(entity instanceof EntityPlayer && this.element != null && this.element != Element.MAGIC){ - // As it stands, this will trigger every tick. Not ideal, but I can't find a way to detect if a player - // has a certain achievement. - // TODO: check if this is somehow triggerable via JSON conditions. - WizardryAdvancementTriggers.element_master.triggerFor((EntityPlayer)entity); + this.rechargeMana(stack, WandHelper.getUpgradeLevel(stack, WizardryItems.condenser_upgrade)); } } @Override + public Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack){ + + Multimap multimap = super.getAttributeModifiers(slot, stack); + + if(slot == EntityEquipmentSlot.MAINHAND){ + int level = WandHelper.getUpgradeLevel(stack, WizardryItems.melee_upgrade); + // This check doesn't affect the damage output, but it does stop a blank line from appearing in the tooltip. + if(level > 0 && !this.isManaEmpty(stack)){ + multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), + new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Melee upgrade modifier", 2 * level, 0)); + multimap.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), new AttributeModifier(ATTACK_SPEED_MODIFIER, "Melee upgrade modifier", -2.4000000953674316D, 0)); + } + } + + return multimap; + } + + @Override + public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder){ + + int level = WandHelper.getUpgradeLevel(stack, WizardryItems.melee_upgrade); + int mana = this.getMana(stack); + + if(level > 0 && mana > 0) this.consumeMana(stack, level * 4, wielder); + + return true; + } + + @Override + public boolean canDestroyBlockInCreative(World world, BlockPos pos, ItemStack stack, EntityPlayer player){ + return WandHelper.getUpgradeLevel(stack, WizardryItems.melee_upgrade) == 0; + } + + // A proper hook was introduced for this in Forge build 14.23.5.2805 - Hallelujah, finally! + // The discussion about this was quite interesting, see the following: + // https://github.com/TeamTwilight/twilightforest/blob/1.12.x/src/main/java/twilightforest/item/ItemTFScepterLifeDrain.java + // https://github.com/MinecraftForge/MinecraftForge/pull/4834 + // Among the things mentioned were that it can be 'fixed' by doing the exact same hacks that I did, and that + // returning a result of PASS rather than SUCCESS from onItemRightClick also solves the problem (not sure why + // though, and again it's not a perfect solution) + // Edit: It seems that the hacky fix in previous versions actually introduced a wand duplication bug... oops + + @Override + public boolean canContinueUsing(ItemStack oldStack, ItemStack newStack){ + // Ignore durability changes + if(ItemStack.areItemsEqualIgnoreDurability(oldStack, newStack)) return true; + return super.canContinueUsing(oldStack, newStack); + } + + @Override + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack){ + // Ignore durability changes + if(ItemStack.areItemsEqualIgnoreDurability(oldStack, newStack)) return false; + return super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + // Only called client-side + // This method is always called on the item in oldStack, meaning that oldStack.getItem() == this public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged){ // This method does some VERY strange things! Despite its name, it also seems to affect the updating of NBT... @@ -149,18 +281,19 @@ public class ItemWand extends Item implements IWorkbenchItem { @SideOnly(Side.CLIENT) @Override - public void addInformation(ItemStack itemstack, World world, List text, ITooltipFlag advanced){ - EntityPlayerSP player = Minecraft.getMinecraft().player; + public void addInformation(ItemStack stack, World world, List text, net.minecraft.client.util.ITooltipFlag advanced){ + + EntityPlayer player = net.minecraft.client.Minecraft.getMinecraft().player; if (player == null) { return; } // +0.5f is necessary due to the error in the way floats are calculated. if(element != null) text.add("\u00A78" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wand.buff", - (int)((tier.level + 1) * Constants.DAMAGE_INCREASE_PER_TIER * 100 + 0.5f) + "%", + (int)((tier.level + 1) * Constants.POTENCY_INCREASE_PER_TIER * 100 + 0.5f) + "%", element.getDisplayName())); - Spell spell = WandHelper.getCurrentSpell(itemstack); + Spell spell = WandHelper.getCurrentSpell(stack); boolean discovered = true; - if(Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null + if(Wizardry.settings.discoveryMode && !player.isCreative() && WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){ discovered = false; } @@ -169,8 +302,19 @@ public class ItemWand extends Item implements IWorkbenchItem { discovered ? "\u00A77" + spell.getDisplayNameWithFormatting() : "#\u00A79" + SpellGlyphData.getGlyphName(spell, player.world))); - text.add("\u00A79" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wand.mana", - (this.getMaxDamage(itemstack) - this.getDamage(itemstack)), this.getMaxDamage(itemstack))); + if(advanced.isAdvanced()){ + // Advanced tooltips for debugging + text.add("\u00A79" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wand.mana", + this.getMana(stack), this.getManaCapacity(stack))); + + text.add("\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wand.progression", + WandHelper.getProgression(stack), this.tier.level < Tier.MASTER.level ? Tier.values()[tier.ordinal() + 1].progression : 0)); + +// }else{ +// +// ChargeStatus status = ChargeStatus.getChargeStatus(stack); +// text.add(status.getFormattingCode() + status.getDisplayName()); + } } @Override @@ -188,89 +332,29 @@ public class ItemWand extends Item implements IWorkbenchItem { ItemStack stack = player.getHeldItem(hand); // Alternate right-click function; overrides spell casting. - if(this.selectMinionTarget(player, world)) return new ActionResult(EnumActionResult.SUCCESS, stack); + if(this.selectMinionTarget(player, world)) return new ActionResult<>(EnumActionResult.SUCCESS, stack); Spell spell = WandHelper.getCurrentSpell(stack); - SpellModifiers modifiers = this.calculateModifiers(stack, spell); - - // If anything stops the spell working at this point, nothing else happens. - if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(player, spell, modifiers, Source.WAND))){ - return new ActionResult(EnumActionResult.FAIL, stack); - } - - // This is here to start the inUse thing, otherwise the onUsingTick method will not fire. - if(spell.isContinuous && !player.isHandActive()){ - player.setActiveHand(hand); - // Probably ought to be here. (Does it succeed though?) - return new ActionResult(EnumActionResult.SUCCESS, stack); - } - - // Conditions for the spell to be attempted. The tier check is a failsafe; it should never be false unless the - // NBT is modified directly. - if(!spell.isContinuous && spell.tier.level <= this.tier.level - // Checks that the wand has enough mana to cast the spell - && spell.cost <= (stack.getMaxDamage() - stack.getItemDamage()) - // Checks that the spell is not in cooldown or that the player is in creative mode - && (WandHelper.getCurrentCooldown(stack) == 0 || player.capabilities.isCreativeMode)){ - - // If the spell does not require a packet, the code is run in the old client-inconsistent way, since this - // means that swingItem() doesn't need packets in order to work, improving performance. - if(!world.isRemote){ - - if(spell.cast(world, player, hand, 0, modifiers)){ - - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(player, spell, modifiers, Source.WAND)); - - // = Packets = - if(spell.doesSpellRequirePacket()){ - // Sends a packet to all players in dimension to tell them to spawn particles. - // Only sent if the spell succeeded, because if the spell failed, you wouldn't - // need to spawn any particles! - IMessage msg = new PacketCastSpell.Message(player.getEntityId(), hand, spell.id(), modifiers); - WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); - } + SpellModifiers modifiers = this.calculateModifiers(stack, player, spell); + if(canCast(stack, spell, player, hand, 0, modifiers)){ + // Now we can cast continuous spells with scrolls! + if(spell.isContinuous){ + if(!player.isHandActive()){ player.setActiveHand(hand); - - // = Cooldown = - // Spells only have a cooldown in survival - if(!player.capabilities.isCreativeMode){ - - float cooldownMultiplier = 1.0f - - WandHelper.getUpgradeLevel(stack, WizardryItems.cooldown_upgrade) - * Constants.COOLDOWN_REDUCTION_PER_LEVEL; - - if(player.isPotionActive(WizardryPotions.font_of_mana)){ - // Dividing by this rather than setting it takes upgrades and font of mana into account - // simultaneously - cooldownMultiplier /= 2 - + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier(); - } - - WandHelper.setCurrentCooldown(stack, (int)(spell.cooldown * cooldownMultiplier)); - } - - // = Mana cost = - // The spell costs 20% less for every armour piece of the matching element. - int armourPieces = getMatchingArmourCount(player, spell); - - stack.damageItem((int)(spell.cost * (1.0f - armourPieces * Constants.COST_REDUCTION_PER_ARMOUR)), - player); - - return new ActionResult(EnumActionResult.SUCCESS, stack); + // Store the modifiers for use each tick + if(WizardData.get(player) != null) WizardData.get(player).itemCastingModifiers = modifiers; + // Return the player's held item so spells can change it if they wish (e.g. possession) + return new ActionResult<>(EnumActionResult.SUCCESS, player.getHeldItem(hand)); } - - }else if(!spell.doesSpellRequirePacket()){ - // Client-inconsistent spell casting. This code only runs client-side. - if(spell.cast(world, player, hand, 0, modifiers)){ - // This is all that needs to happen, because everything above works fine on just the server side. - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(player, spell, modifiers, Source.WAND)); - return new ActionResult(EnumActionResult.SUCCESS, stack); + }else{ + if(cast(stack, spell, player, hand, 0, modifiers)){ + return new ActionResult<>(EnumActionResult.SUCCESS, player.getHeldItem(hand)); } } } - return new ActionResult(EnumActionResult.FAIL, stack); + return new ActionResult<>(EnumActionResult.FAIL, stack); } // For continuous spells. The count argument actually decrements by 1 each tick. @@ -282,72 +366,155 @@ public class ItemWand extends Item implements IWorkbenchItem { EntityPlayer player = (EntityPlayer)user; Spell spell = WandHelper.getCurrentSpell(stack); - SpellModifiers modifiers = this.calculateModifiers(stack, spell); + + SpellModifiers modifiers; + + if(WizardData.get(player) != null){ + modifiers = WizardData.get(player).itemCastingModifiers; + }else{ + modifiers = this.calculateModifiers(stack, (EntityPlayer)user, spell); // Fallback to the old way, should never be used + } + int castingTick = stack.getMaxItemUseDuration() - count; - if(MinecraftForge.EVENT_BUS - .post(new SpellCastEvent.Tick(player, spell, modifiers, Source.WAND, castingTick))) - return; - // Continuous spells (these must check if they can be cast each tick since the mana changes) - if(spell.isContinuous && spell.tier.level <= this.tier.level - && spell.cost / 5 <= (stack.getMaxDamage() - stack.getItemDamage())){ + // Don't call canCast when castingTick == 0 because we already did it in onItemRightClick + if(spell.isContinuous && (castingTick == 0 || canCast(stack, spell, player, player.getActiveHand(), castingTick, modifiers))){ + cast(stack, spell, player, player.getActiveHand(), castingTick, modifiers); + }else{ + // Stops the casting if it was interrupted, either by events or because the wand ran out of mana + player.stopActiveHand(); + } + } + } - if(spell.cast(player.world, player, player.getActiveHand(), castingTick, modifiers)){ + @Override + public boolean canCast(ItemStack stack, Spell spell, EntityPlayer caster, EnumHand hand, int castingTick, SpellModifiers modifiers){ - if(castingTick == 0) - MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(player, spell, modifiers, Source.WAND)); + // Spells can only be cast if the casting events aren't cancelled... + if(castingTick == 0){ + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(Source.WAND, spell, caster, modifiers))) return false; + }else{ + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(Source.WAND, spell, caster, modifiers, castingTick))) return false; + } - // = Mana cost = - // Divides the mana cost over a second appropriately; since damage is an integer it cannot - // just be divided by 20. - // Now does five times per second regardless of the spell cost, but each time it does 1/5 of the - // cost per second. - int tickNumber = (count % 20) + 1; - // Tests if the tick counter is a multiple of 4 plus 1, i.e. is true when tickNumber = 1, 5, 9, 13 - // or 17. - // Made a slight adjustment since the counter starts on 1 and not 4. - if(tickNumber % 4 == 1){ + int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST)); - int armourPieces = getMatchingArmourCount(player, spell); + // As of wizardry 4.2 mana cost is only divided over two intervals each second + if(spell.isContinuous) cost = getDistributedCost(cost, castingTick); - switch(armourPieces){ + // ...and the wand has enough mana to cast the spell... + return cost <= this.getMana(stack) // This comes first because it changes over time + // ...and the wand is the same tier as the spell or higher... + && spell.getTier().level <= this.tier.level + // ...and either the spell is not in cooldown or the player is in creative mode + && (WandHelper.getCurrentCooldown(stack) == 0 || caster.isCreative()); + } - case 0: - stack.damageItem(spell.cost / 5, player); - break; + @Override + public boolean cast(ItemStack stack, Spell spell, EntityPlayer caster, EnumHand hand, int castingTick, SpellModifiers modifiers){ - case 1: - if(tickNumber != 17) stack.damageItem(spell.cost / 5, player); - break; + World world = caster.world; - case 2: - if(tickNumber != 9 && tickNumber != 17) stack.damageItem(spell.cost / 5, player); - break; + if(world.isRemote && !spell.isContinuous && spell.requiresPacket()) return false; - case 3: - if(tickNumber != 5 && tickNumber != 13 && tickNumber != 17) - stack.damageItem(spell.cost / 5, player); - break; + if(spell.cast(world, caster, hand, castingTick, modifiers)){ - case 4: - if(tickNumber == 1) stack.damageItem(spell.cost / 5, player); - break; + if(castingTick == 0) MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.WAND, spell, caster, modifiers)); - } + if(!world.isRemote){ + + // Continuous spells never require packets so don't rely on the requiresPacket method to specify it + if(!spell.isContinuous && spell.requiresPacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + IMessage msg = new PacketCastSpell.Message(caster.getEntityId(), hand, spell, modifiers); + WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); + } + + caster.setActiveHand(hand); + + // Mana cost + int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST)); + // As of wizardry 4.2 mana cost is only divided over two intervals each second + if(spell.isContinuous) cost = getDistributedCost(cost, castingTick); + + if(cost > 0) this.consumeMana(stack, cost, caster); + + } + + // Cooldown + if(!spell.isContinuous && !caster.isCreative()){ // Spells only have a cooldown in survival + WandHelper.setCurrentCooldown(stack, (int)(spell.getCooldown() * modifiers.get(WizardryItems.cooldown_upgrade))); + } + + // Progression + if(this.tier.level < Tier.MASTER.level && castingTick % CONTINUOUS_TRACKING_INTERVAL == 0){ + + // We don't care about cost modifiers here, otherwise players would be penalised for wearing robes! + int progression = (int)(spell.getCost() * modifiers.get(SpellModifiers.PROGRESSION)); + WandHelper.addProgression(stack, progression); + + if(!Wizardry.settings.legacyWandLevelling){ // Don't display the message if legacy wand levelling is enabled + // If the wand just gained enough progression to be upgraded... + Tier nextTier = Tier.values()[tier.ordinal() + 1]; + int excess = WandHelper.getProgression(stack) - nextTier.progression; + if(excess >= 0 && excess < progression){ + // ...display a message above the player's hotbar + caster.playSound(WizardrySounds.ITEM_WAND_LEVELUP, 1.25f, 1); + if(!world.isRemote) + caster.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":wand.levelup", + this.getItemStackDisplayName(stack), nextTier.getNameForTranslationFormatted())); } } + + WizardData.get(caster).trackRecentSpell(spell); + } + + return true; + } + + return false; + } + + @Override + public void onPlayerStoppedUsing(ItemStack stack, World world, EntityLivingBase user, int timeLeft){ + + if(user instanceof EntityPlayer){ + + EntityPlayer player = (EntityPlayer)user; + + Spell spell = WandHelper.getCurrentSpell(stack); + + SpellModifiers modifiers; + + if(WizardData.get(player) != null){ + modifiers = WizardData.get(player).itemCastingModifiers; + }else{ + modifiers = this.calculateModifiers(stack, (EntityPlayer)user, spell); // Fallback to the old way, should never be used + } + + int castingTick = stack.getMaxItemUseDuration() - timeLeft; // Might as well include this + + int cost = getDistributedCost((int)(spell.getCost() * modifiers.get(SpellModifiers.COST)), castingTick); + + // Still need to check there's enough mana or the spell will finish twice, since running out of mana is + // handled separately. + if(spell.isContinuous && spell.getTier().level <= this.tier.level && cost <= this.getMana(stack)){ + + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Finish(Source.WAND, spell, player, modifiers, castingTick)); + spell.finishCasting(world, player, Double.NaN, Double.NaN, Double.NaN, null, castingTick, modifiers); + + if(!player.isCreative()){ // Spells only have a cooldown in survival + WandHelper.setCurrentCooldown(stack, (int)(spell.getCooldown() * modifiers.get(WizardryItems.cooldown_upgrade))); + } } } } @Override - public boolean itemInteractionForEntity(ItemStack stack, EntityPlayer player, EntityLivingBase entity, - EnumHand hand){ + public boolean itemInteractionForEntity(ItemStack stack, EntityPlayer player, EntityLivingBase entity, EnumHand hand){ if(player.isSneaking() && entity instanceof EntityPlayer && WizardData.get(player) != null){ - // This is one of those "the method doing the work looks as if it's just returning a value" situations. - // ... I know, right?! I feel very programmer-y. But it's not too confusing here, and it looks neat. String string = WizardData.get(player).toggleAlly((EntityPlayer)entity) ? "item." + Wizardry.MODID + ":wand.addally" : "item." + Wizardry.MODID + ":wand.removeally"; if(!player.world.isRemote) player.sendMessage(new TextComponentTranslation(string, entity.getName())); @@ -357,8 +524,27 @@ public class ItemWand extends Item implements IWorkbenchItem { return false; } + /** Distributes the given cost (which should be the per-second cost of a continuous spell) over a second and + * returns the appropriate cost to be applied for the given tick. Currently the cost is distributed over 2 + * intervals per second, meaning the returned value is 0 unless {@code castingTick} is a multiple of 10.*/ + protected static int getDistributedCost(int cost, int castingTick){ + + int partialCost; + + if(castingTick % 20 == 0){ // Whole number of seconds has elapsed + partialCost = cost / 2 + cost % 2; // Make sure cost adds up to the correct value by adding the remainder here + }else if(castingTick % 10 == 0){ // Something-and-a-half seconds has elapsed + partialCost = cost/2; + }else{ // Some other number of ticks has elapsed + partialCost = 0; // Wands aren't damaged within half-seconds + } + + return partialCost; + } + /** Returns a SpellModifiers object with the appropriate modifiers applied for the given ItemStack and Spell. */ - protected SpellModifiers calculateModifiers(ItemStack stack, Spell spell){ + // This is now public because artefacts use it + public SpellModifiers calculateModifiers(ItemStack stack, EntityPlayer player, Spell spell){ SpellModifiers modifiers = new SpellModifiers(); @@ -375,38 +561,26 @@ public class ItemWand extends Item implements IWorkbenchItem { if(level > 0) modifiers.set(WizardryItems.blast_upgrade, 1.0f + level * Constants.BLAST_RADIUS_INCREASE_PER_LEVEL, true); - // I would have liked to have made potion effects increase in strength according to the damage multiplier, - // but the amplifier level is too discrete to make this work. For example, wither 3 for 10 seconds will kill a - // normal mob on full 20 health, but wither 2 for the same duration only deals about 6 hearts of damage in - // total. - if(this.element == spell.element){ - modifiers.set(SpellModifiers.POTENCY, 1.0f + (this.tier.level + 1) * Constants.DAMAGE_INCREASE_PER_TIER, - true); + level = WandHelper.getUpgradeLevel(stack, WizardryItems.cooldown_upgrade); + if(level > 0) + modifiers.set(WizardryItems.cooldown_upgrade, 1.0f - level * Constants.COOLDOWN_REDUCTION_PER_LEVEL, true); + + float progressionModifier = 1.0f - ((float)WizardData.get(player).countRecentCasts(spell) / WizardData.MAX_RECENT_SPELLS) + * MAX_PROGRESSION_REDUCTION; + + if(this.element == spell.getElement()){ + modifiers.set(SpellModifiers.POTENCY, 1.0f + (this.tier.level + 1) * Constants.POTENCY_INCREASE_PER_TIER, true); + progressionModifier *= ELEMENTAL_PROGRESSION_MODIFIER; } + modifiers.set(SpellModifiers.PROGRESSION, progressionModifier, false); + return modifiers; } - /** Counts the number of armour pieces the given player is wearing that match the given spell's element. */ - private int getMatchingArmourCount(EntityPlayer player, Spell spell){ - - int armourPieces = 0; - - for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ - - ItemStack armour = player.getItemStackFromSlot(slot); - - if(armour != null && armour.getItem() instanceof ItemWizardArmour - && ((ItemWizardArmour)armour.getItem()).element == spell.element) - armourPieces++; - } - - return armourPieces; - } - private boolean selectMinionTarget(EntityPlayer player, World world){ - RayTraceResult rayTrace = WizardryUtilities.standardEntityRayTrace(world, player, 16, false); + RayTraceResult rayTrace = RayTracer.standardEntityRayTrace(world, player, 16, false); if(rayTrace != null && WizardryUtilities.isLiving(rayTrace.entityHit)){ @@ -430,6 +604,8 @@ public class ItemWand extends Item implements IWorkbenchItem { return false; } + // Workbench stuff + @Override public int getSpellSlotCount(ItemStack stack){ return BASE_SPELL_SLOTS + WandHelper.getUpgradeLevel(stack, WizardryItems.attunement_upgrade); @@ -444,24 +620,31 @@ public class ItemWand extends Item implements IWorkbenchItem { // and also the entire NBT tag compound. if(upgrade.getStack().getItem() == WizardryItems.arcane_tome){ - // Checks the wand upgrade is for the tier above the wand's tier. + Tier tier = Tier.values()[upgrade.getStack().getItemDamage()]; + + // Checks the wand upgrade is for the tier above the wand's tier, and that either the wand has enough + // progression or the player is in creative mode. // It is guaranteed that: this == centre.getStack().getItem() - if(upgrade.getStack().getItemDamage() - 1 == this.tier.ordinal()){ - - Tier tier = Tier.values()[upgrade.getStack().getItemDamage()]; - - ItemStack newWand = new ItemStack(WizardryUtilities.getWand(tier, this.element)); + if((player.isCreative() || Wizardry.settings.legacyWandLevelling + || WandHelper.getProgression(centre.getStack()) >= tier.progression) + && tier.ordinal() - 1 == this.tier.ordinal()){ + + // We're not carrying over excess progression for now, but if we do want to, this is how +// if(!Wizardry.settings.legacyWandLevelling){ +// // Easy way to carry excess progression over to the new stack +// WandHelper.setProgression(centre.getStack(), WandHelper.getProgression(centre.getStack()) - tier.progression); +// } + + ItemStack newWand = new ItemStack(WizardryItems.getWand(tier, this.element)); newWand.setTagCompound(centre.getStack().getTagCompound()); - // This needs to be done after copying the tag compound so the max damage for the new wand - // takes storage upgrades into account. - newWand.setItemDamage(newWand.getMaxDamage() - (centre.getStack().getMaxDamage() - centre.getStack().getItemDamage())); - + // This needs to be done after copying the tag compound so the mana capacity for the new wand + // takes storage upgrades into account + // Note the usage of the new wand item and not 'this' to ensure the correct capacity is used + ((IManaStoringItem)newWand.getItem()).setMana(newWand, this.getMana(centre.getStack())); + centre.putStack(newWand); upgrade.decrStackSize(1); - if(tier == Tier.APPRENTICE) WizardryAdvancementTriggers.apprentice.triggerFor(player); - if(tier == Tier.MASTER) WizardryAdvancementTriggers.master.triggerFor(player); - changed = true; } @@ -474,14 +657,14 @@ public class ItemWand extends Item implements IWorkbenchItem { && WandHelper.getUpgradeLevel(centre.getStack(), specialUpgrade) < Constants.UPGRADE_STACK_LIMIT){ // Used to preserve existing mana when upgrading storage rather than creating free mana. - int prevMana = centre.getStack().getMaxDamage() - centre.getStack().getItemDamage(); + int prevMana = this.getMana(centre.getStack()); WandHelper.applyUpgrade(centre.getStack(), specialUpgrade); // Special behaviours for specific upgrades if(specialUpgrade == WizardryItems.storage_upgrade){ - - centre.getStack().setItemDamage(centre.getStack().getMaxDamage() - prevMana); + + this.setMana(centre.getStack(), prevMana); }else if(specialUpgrade == WizardryItems.attunement_upgrade){ @@ -501,9 +684,7 @@ public class ItemWand extends Item implements IWorkbenchItem { int[] newCooldowns = new int[newSlotCount]; if(cooldowns.length > 0){ - for(int i = 0; i < cooldowns.length; i++){ - newCooldowns[i] = cooldowns[i]; - } + System.arraycopy(cooldowns, 0, newCooldowns, 0, cooldowns.length); } WandHelper.setCooldowns(centre.getStack(), newCooldowns); @@ -520,7 +701,7 @@ public class ItemWand extends Item implements IWorkbenchItem { } } - // Reads NBT spell id array to variable, edits this, then writes it back to NBT. + // Reads NBT spell metadata array to variable, edits this, then writes it back to NBT. // Original spells are preserved; if a slot is left empty the existing spell binding will remain. // Accounts for spells which cannot be applied because they are above the wand's tier; these spells // will not bind but the existing spell in that slot will remain and other applicable spells will @@ -535,9 +716,9 @@ public class ItemWand extends Item implements IWorkbenchItem { for(int i = 0; i < spells.length; i++){ if(spellBooks[i].getStack() != ItemStack.EMPTY){ - Spell spell = Spell.get(spellBooks[i].getStack().getItemDamage()); - // If the wand is powerful enough for the spell and it's not already bound to that slot - if(!(spell.tier.level > this.tier.level) && spells[i] != spell){ + Spell spell = Spell.byMetadata(spellBooks[i].getStack().getItemDamage()); + // If the wand is powerful enough for the spell, it's not already bound to that slot and it's enabled for wands + if(!(spell.getTier().level > this.tier.level) && spells[i] != spell && spell.isEnabled(SpellProperties.Context.WANDS)){ spells[i] = spell; changed = true; } @@ -547,24 +728,67 @@ public class ItemWand extends Item implements IWorkbenchItem { WandHelper.setSpells(centre.getStack(), spells); // Charges wand by appropriate amount - if(crystals.getStack() != ItemStack.EMPTY){ + if(crystals.getStack() != ItemStack.EMPTY && !this.isManaFull(centre.getStack())){ - int chargeDepleted = centre.getStack().getItemDamage(); - - if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){ - - centre.getStack().setItemDamage(chargeDepleted - crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL); - crystals.decrStackSize(crystals.getStack().getCount()); - changed = true; - - }else if(chargeDepleted != 0){ + int chargeDepleted = this.getManaCapacity(centre.getStack()) - this.getMana(centre.getStack()); - centre.getStack().setItemDamage(0); - crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / Constants.MANA_PER_CRYSTAL)); - changed = true; + int manaPerItem = Constants.MANA_PER_CRYSTAL; + if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD; + if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA; + + if(crystals.getStack().getCount() * manaPerItem < chargeDepleted){ + // If there aren't enough crystals to fully charge the wand + this.rechargeMana(centre.getStack(), crystals.getStack().getCount() * manaPerItem); + crystals.decrStackSize(crystals.getStack().getCount()); + + }else{ + // If there are excess crystals (or just enough) + this.setMana(centre.getStack(), this.getManaCapacity(centre.getStack())); + crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / manaPerItem)); } + + changed = true; } return changed; } + + // hitEntity is only called server-side, so we'll have to use events + @SubscribeEvent + public static void onAttackEntityEvent(AttackEntityEvent event){ + + EntityPlayer player = event.getEntityPlayer(); + ItemStack stack = player.getHeldItemMainhand(); // Can't melee with offhand items + + if(stack.getItem() instanceof IManaStoringItem){ + + // Nobody said it had to be a wand, as long as it's got a melee upgrade it counts + int level = WandHelper.getUpgradeLevel(stack, WizardryItems.melee_upgrade); + int mana = ((IManaStoringItem)stack.getItem()).getMana(stack); + + if(level > 0 && mana > 0){ + + Random random = player.world.rand; + + player.world.playSound(player.posX, player.posY, player.posZ, WizardrySounds.ITEM_WAND_MELEE, SoundCategory.PLAYERS, 0.75f, 1, false); + + if(player.world.isRemote){ + + Vec3d origin = new Vec3d(player.posX, player.getEntityBoundingBox().minY + player.getEyeHeight(), player.posZ); + Vec3d hit = origin.add(player.getLookVec().scale(player.getDistance(event.getTarget()))); + // Generate two perpendicular vectors in the plane perpendicular to the look vec + Vec3d vec1 = player.getLookVec().rotatePitch(90); + Vec3d vec2 = player.getLookVec().crossProduct(vec1); + + for(int i = 0; i < 15; i++){ + ParticleBuilder.create(Type.SPARKLE).pos(hit) + .vel(vec1.scale(random.nextFloat() * 0.3f - 0.15f).add(vec2.scale(random.nextFloat() * 0.3f - 0.15f))) + .clr(1f, 1f, 1f).fade(0.3f, 0.5f, 1) + .time(8 + random.nextInt(4)).spawn(player.world); + } + } + } + } + } + } diff --git a/src/main/java/electroblob/wizardry/item/ItemWandUpgrade.java b/src/main/java/electroblob/wizardry/item/ItemWandUpgrade.java new file mode 100644 index 00000000..c9766b10 --- /dev/null +++ b/src/main/java/electroblob/wizardry/item/ItemWandUpgrade.java @@ -0,0 +1,32 @@ +package electroblob.wizardry.item; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryTabs; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import javax.annotation.Nullable; +import java.util.List; + +public class ItemWandUpgrade extends Item { + + public ItemWandUpgrade(){ + super(); + this.setCreativeTab(WizardryTabs.WIZARDRY); + } + + @Override + public EnumRarity getRarity(ItemStack stack){ + return EnumRarity.UNCOMMON; + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, net.minecraft.client.util.ITooltipFlag flag) { + Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc"); + } +} diff --git a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java index c3d42872..1e7c2708 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java +++ b/src/main/java/electroblob/wizardry/item/ItemWizardArmour.java @@ -1,24 +1,24 @@ package electroblob.wizardry.item; -import java.util.List; -import java.util.UUID; - import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; - +import com.google.common.collect.Streams; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Element; +import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryRecipes; import electroblob.wizardry.registry.WizardryTabs; -import net.minecraft.client.model.ModelBiped; -import net.minecraft.client.util.ITooltipFlag; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.inventory.Slot; @@ -28,14 +28,19 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumHandSide; import net.minecraft.world.World; -import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + @Mod.EventBusSubscriber -public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { +public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IManaStoringItem { // VanillaCopy, ItemArmor has this set to private for some reason. public static final UUID[] ARMOR_MODIFIERS = new UUID[] {UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")}; @@ -47,20 +52,53 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { public ItemWizardArmour(ArmorMaterial material, int renderIndex, EntityEquipmentSlot armourType, Element element){ super(material, renderIndex, armourType); this.element = element; - setCreativeTab(WizardryTabs.WIZARDRY); + setCreativeTab(WizardryTabs.GEAR); + WizardryRecipes.addToManaFlaskCharging(this); + } + + /** Should only be used by vanilla's armour damage calculations; use {@link ItemWizardArmour#setMana(ItemStack, int)} + * to modify wand mana from elsewhere. */ + @Override + public void setDamage(ItemStack stack, int damage){ + // Overridden to stop repair things from 'repairing' the mana in wizard armour + // This being armour, it's much easier to let its damage increase normally, but block it from being decreased + if(stack.getItemDamage() < damage) super.setDamage(stack, damage); + } + + @Override + public void setMana(ItemStack stack, int mana){ + // Using super (which can only be done from in here) bypasses the above override + super.setDamage(stack, getManaCapacity(stack) - mana); + } + + @Override + public int getMana(ItemStack stack){ + return getManaCapacity(stack) - getDamage(stack); + } + + @Override + public int getManaCapacity(ItemStack stack){ + return this.getMaxDamage(stack); } @Override @SideOnly(Side.CLIENT) - public void addInformation(ItemStack stack, World world, List tooltip, ITooltipFlag advanced){ + public void addInformation(ItemStack stack, World world, List tooltip, net.minecraft.client.util.ITooltipFlag advanced){ - if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) tooltip - .add("\u00A7d" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wizard_armour.legendary")); - if(element != null) + if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) + tooltip.add("\u00A7d" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wizard_armour.legendary")); + + if(element != null){ tooltip.add("\u00A78" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wizard_armour.buff", (int)(Constants.COST_REDUCTION_PER_ARMOUR * 100) + "%", element.getDisplayName())); - tooltip.add("\u00A79" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wizard_armour.mana", - (this.getMaxDamage(stack) - this.getDamage(stack)), this.getMaxDamage(stack))); + } + + // tooltip.add("\u00A79" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wizard_armour.mana", +// (this.getMaxDamage(stack) - this.getDamage(stack)), this.getMaxDamage(stack))); + +// ChargeStatus status = ChargeStatus.getChargeStatus(stack); +// +// tooltip.add(status.getFormattingCode() + status.getDisplayName()); } @Override @@ -70,32 +108,23 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { @Override @SideOnly(Side.CLIENT) - public boolean hasEffect(ItemStack stack){ - return stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary"); - } - - @Override - @SideOnly(Side.CLIENT) - public ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, - EntityEquipmentSlot armourSlot, ModelBiped _default){ - - ModelBiped model = Wizardry.proxy.getWizardArmourModel(); + public net.minecraft.client.model.ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, + EntityEquipmentSlot armourSlot, net.minecraft.client.model.ModelBiped _default){ // Legs use modelBiped - if(armourSlot == EntityEquipmentSlot.LEGS) return null; + if(armourSlot == EntityEquipmentSlot.LEGS && !entityLiving.isInvisible()) return null; + + net.minecraft.client.model.ModelBiped model = Wizardry.proxy.getWizardArmourModel(); if(model != null){ model.bipedHead.showModel = armourSlot == EntityEquipmentSlot.HEAD; model.bipedHeadwear.showModel = false; - model.bipedBody.showModel = armourSlot == EntityEquipmentSlot.CHEST - || armourSlot == EntityEquipmentSlot.LEGS; + model.bipedBody.showModel = armourSlot == EntityEquipmentSlot.CHEST; model.bipedRightArm.showModel = armourSlot == EntityEquipmentSlot.CHEST; model.bipedLeftArm.showModel = armourSlot == EntityEquipmentSlot.CHEST; - model.bipedRightLeg.showModel = armourSlot == EntityEquipmentSlot.LEGS - || armourSlot == EntityEquipmentSlot.FEET; - model.bipedLeftLeg.showModel = armourSlot == EntityEquipmentSlot.LEGS - || armourSlot == EntityEquipmentSlot.FEET; + model.bipedRightLeg.showModel = armourSlot == EntityEquipmentSlot.FEET; + model.bipedLeftLeg.showModel = armourSlot == EntityEquipmentSlot.FEET; model.isSneak = entityLiving.isSneaking(); model.isRiding = entityLiving.isRiding(); @@ -107,29 +136,29 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { ItemStack itemstackL = leftHanded ? entityLiving.getHeldItemMainhand() : entityLiving.getHeldItemOffhand(); if(!itemstackR.isEmpty()){ - model.rightArmPose = ModelBiped.ArmPose.ITEM; + model.rightArmPose = net.minecraft.client.model.ModelBiped.ArmPose.ITEM; if(entityLiving.getItemInUseCount() > 0){ EnumAction enumaction = itemstackR.getItemUseAction(); if(enumaction == EnumAction.BLOCK){ - model.rightArmPose = ModelBiped.ArmPose.BLOCK; + model.rightArmPose = net.minecraft.client.model.ModelBiped.ArmPose.BLOCK; }else if(enumaction == EnumAction.BOW){ - model.rightArmPose = ModelBiped.ArmPose.BOW_AND_ARROW; + model.rightArmPose = net.minecraft.client.model.ModelBiped.ArmPose.BOW_AND_ARROW; } } } if(!itemstackL.isEmpty()){ - model.leftArmPose = ModelBiped.ArmPose.ITEM; + model.leftArmPose = net.minecraft.client.model.ModelBiped.ArmPose.ITEM; if(entityLiving.getItemInUseCount() > 0){ EnumAction enumaction1 = itemstackL.getItemUseAction(); if(enumaction1 == EnumAction.BLOCK){ - model.leftArmPose = ModelBiped.ArmPose.BLOCK; + model.leftArmPose = net.minecraft.client.model.ModelBiped.ArmPose.BLOCK; }else if(enumaction1 == EnumAction.BOW){ - model.leftArmPose = ModelBiped.ArmPose.BOW_AND_ARROW; + model.leftArmPose = net.minecraft.client.model.ModelBiped.ArmPose.BOW_AND_ARROW; } } } @@ -144,33 +173,33 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { // Returns a completely transparent texture if the player is invisible. This is such an annoyingly easy // fix, considering how long I spent trying to do this before - a bit of lateral thinking was all it took. // Do note however that a texture pack could override this. - if(entity instanceof EntityLivingBase && ((EntityLivingBase)entity).isInvisible() - && !entity.getEntityData().getBoolean(BlockStatue.NBT_KEY)) - return "ebwizardry:textures/armour/invisible_armour.png"; +// if(entity instanceof EntityLivingBase && entity.isInvisible() && !entity.getEntityData().getBoolean(BlockStatue.PETRIFIED_NBT_KEY)) +// return "ebwizardry:textures/armour/invisible_armour.png"; - if(slot == EntityEquipmentSlot.LEGS) - return this.element == null ? "ebwizardry:textures/armour/wizard_armour_legs.png" - : "ebwizardry:textures/armour/wizard_armour_" + this.element.getUnlocalisedName() + "_legs.png"; + String s = "wizard_armour"; - return this.element == null ? "ebwizardry:textures/armour/wizard_armour.png" - : "ebwizardry:textures/armour/wizard_armour_" + this.element.getUnlocalisedName() + ".png"; + if(this.element != null) s = s + "_" + this.element.getName(); + if(slot == EntityEquipmentSlot.LEGS) s = s + "_legs"; + if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s; + + return "ebwizardry:textures/armour/" + s + ".png"; } @Override - public boolean getIsRepairable(ItemStack stack, ItemStack par2ItemStack){ + public boolean getIsRepairable(ItemStack stack, ItemStack material){ return false; } - /* - * Properly handles the defense value of the armor. This method is responisble for the tooltip on top of - * the armor value. It is also what handles armor toughness, but the wizard armor had a value of 0 for that. + /** + * Properly handles the defence value of the armour. This method is responsible for the tooltip on top of + * the armour value. It is also what handles armour toughness. */ @Override public Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack){ Multimap map = HashMultimap.create(); - if(stack.getItemDamage() < stack.getMaxDamage() && this.armorType == slot){ + if(!this.isManaEmpty(stack) && this.armorType == slot){ int defense = reductions[slot.getIndex()]; float toughness = 0f; @@ -189,30 +218,10 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { return map; } - // Fixes wizard armor breaking by disallowing setting damage above the max, since damageArmor is not always called. - // Since ISpecialArmor has been removed from this class, this may no longer be necessary, but keeping it won't hurt. + // Workbench stuff + @Override - public void setDamage(ItemStack stack, int damage) { - if(damage <= stack.getMaxDamage()) super.setDamage(stack, damage); - else super.setDamage(stack, stack.getMaxDamage()); - } - - @SubscribeEvent - public static void onLivingUpdateEvent(LivingUpdateEvent event){ - - if(event.getEntityLiving() instanceof EntityPlayer){ - - EntityPlayer player = (EntityPlayer)event.getEntityLiving(); - - for(ItemStack stack : player.getArmorInventoryList()){ - if(!(stack.getItem() instanceof ItemWizardArmour)){ - return; // If any of the armour slots doesn't contain wizard armour, don't trigger the achievement. - } - } - // If it gets this far, then all slots must be wizard armour, so trigger the achievement. - WizardryAdvancementTriggers.armour_set.triggerFor(player); - } - } + public boolean showTooltip(ItemStack stack){ return true; } @Override public int getSpellSlotCount(ItemStack stack){ @@ -241,25 +250,87 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem { } // Charges armour by appropriate amount - if(crystals.getStack() != ItemStack.EMPTY){ - - int chargeDepleted = centre.getStack().getItemDamage(); - - if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){ - - centre.getStack().setItemDamage(chargeDepleted - crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL); - crystals.decrStackSize(crystals.getStack().getCount()); - changed = true; - - }else if(chargeDepleted != 0){ + if(crystals.getStack() != ItemStack.EMPTY && !this.isManaFull(centre.getStack())){ - centre.getStack().setItemDamage(0); + int chargeDepleted = this.getManaCapacity(centre.getStack()) - this.getMana(centre.getStack()); + + if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){ + // If there aren't enough crystals to fully charge the armour + this.rechargeMana(centre.getStack(), crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL); + crystals.decrStackSize(crystals.getStack().getCount()); + + }else{ + // If there are excess crystals (or just enough) + this.setMana(centre.getStack(), this.getManaCapacity(centre.getStack())); crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / Constants.MANA_PER_CRYSTAL)); - changed = true; } + + changed = true; } return changed; } + // Event Handlers + +// @SubscribeEvent +// public static void onLivingUpdateEvent(LivingUpdateEvent event){ +// +// if(event.getEntityLiving() instanceof EntityPlayer){ +// +// EntityPlayer player = (EntityPlayer)event.getEntityLiving(); +// +// for(ItemStack stack : player.getArmorInventoryList()){ +// if(!(stack.getItem() instanceof ItemWizardArmour)){ +// return; // If any of the armour slots doesn't contain wizard armour, don't trigger the achievement. +// } +// } +// // If it gets this far, then all slots must be wizard armour, so trigger the achievement. +// WizardryAdvancementTriggers.armour_set.triggerFor(player); +// } +// } + + @SubscribeEvent(priority = EventPriority.LOW) + public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ + // Armour cost reduction + if(event.getCaster() == null) return; + int armourPieces = getMatchingArmourCount(event.getCaster(), event.getSpell().getElement()); + float multiplier = 1f - armourPieces * Constants.COST_REDUCTION_PER_ARMOUR; + if(armourPieces == WizardryUtilities.ARMOUR_SLOTS.length) multiplier -= Constants.FULL_ARMOUR_SET_BONUS; + event.getModifiers().set(SpellModifiers.COST, event.getModifiers().get(SpellModifiers.COST) * multiplier, false); + } + + /** Counts the number of armour pieces the given entity is wearing that match the given element. */ + public static int getMatchingArmourCount(EntityLivingBase entity, Element element){ + return (int)Arrays.stream(WizardryUtilities.ARMOUR_SLOTS) + .map(s -> entity.getItemStackFromSlot(s).getItem()) + .filter(i -> i instanceof ItemWizardArmour && ((ItemWizardArmour)i).element == element) + .count(); + } + + @SubscribeEvent + public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){ + // Undo the mob detection penalty for wearing armour when invisible + // Only bother doing this for players because the penalty only applies to them + if(event.getTarget() instanceof EntityPlayer && event.getEntityLiving() instanceof EntityLiving + && event.getEntityLiving().isInvisible()){ + + int armourPieces = (int)Streams.stream(event.getTarget().getArmorInventoryList()) + .filter(s -> !s.isEmpty() && !(s.getItem() instanceof ItemWizardArmour)) + .count(); + + if(armourPieces == 0) return; + + // Repeat the calculation from EntityAIFindNearestPlayer, but ignoring wizard armour + IAttributeInstance attribute = event.getEntityLiving().getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE); + double followRange = attribute == null ? 16 : attribute.getAttributeValue(); + if(event.getTarget().isSneaking()) followRange *= 0.8; + float f = armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size(); + if(f < 0.1F) f = 0.1F; + followRange *= (double)(0.7F * f); + // Don't need to worry about the isSuitableTarget check since it must already have been checked to get this far + if(event.getTarget().getDistance(event.getEntity()) > followRange) ((EntityLiving)event.getEntityLiving()).setAttackTarget(null); + } + } + } diff --git a/src/main/java/electroblob/wizardry/item/ItemWizardHandbook.java b/src/main/java/electroblob/wizardry/item/ItemWizardHandbook.java index 67a210c5..e2c6a39b 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWizardHandbook.java +++ b/src/main/java/electroblob/wizardry/item/ItemWizardHandbook.java @@ -1,13 +1,8 @@ package electroblob.wizardry.item; -import java.util.List; - -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.WizardryGuiHandler; import electroblob.wizardry.registry.WizardryTabs; -import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -16,6 +11,9 @@ import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; import net.minecraft.world.World; +import javax.annotation.Nullable; +import java.util.List; + public class ItemWizardHandbook extends Item { // Yep, I hardcoded my own name into the mod. Don't want people changing it now, do I? @@ -28,7 +26,7 @@ public class ItemWizardHandbook extends Item { } @Override - public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, net.minecraft.client.util.ITooltipFlag flag) { tooltip.add( "\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":wizard_handbook.desc", AUTHOR)); } diff --git a/src/main/java/electroblob/wizardry/loot/RandomSpell.java b/src/main/java/electroblob/wizardry/loot/RandomSpell.java index 9fe703e6..7b9848c0 100644 --- a/src/main/java/electroblob/wizardry/loot/RandomSpell.java +++ b/src/main/java/electroblob/wizardry/loot/RandomSpell.java @@ -1,57 +1,51 @@ package electroblob.wizardry.loot; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import org.apache.commons.lang3.ArrayUtils; - -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSyntaxException; - +import com.google.gson.*; import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.item.ItemScroll; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.spell.Spell; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.SpellProperties; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.JsonUtils; import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.LootContext; import net.minecraft.world.storage.loot.conditions.LootCondition; import net.minecraft.world.storage.loot.functions.LootFunction; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; /** * Loot function that allows spell books and scrolls to select a random spell based on the standard weighting. - * Automatically discounts continuous spells when the item in question is a scroll. Can be used as-is with no - * parameters, but several optional parameters are available for those wishing to customise further: - *

    + * Can be used as-is with no parameters, but several optional parameters are available for those wishing to customise further: + *

    * - spells: A list of spells to choose from. Defaults to all enabled spells.
    * - ignore_weighting: true to ignore the standard weighting and just pick a completely random spell. Defaults to * false.
    + * - undiscovered_bias: A number between 0 and 1 representing the bias towards undiscovered spells, with 0 + * being no bias and 1 meaning spells are guaranteed to be undiscovered.
    * - tiers: A list of tiers to choose from. Defaults to all tiers.
    * - elements: A list of elements to choose from. Defaults to all elements. - *

    + *

    * This class is effectively a loot table-friendly replacement for the standard weighting method in WizardryUtilities * which was the basis of all the old loot systems (not counting wizard trades, which were - and still are - completely * separate). - *

    + *

    * Since spells are stored as metadata, this could be done by having an entry for each tier and letting it pick a * random spell from that tier by setting the metadata to a random value in the range of values that correspond to that * tier. However, this creates a two-fold problem: firstly, not all spells are in tier order, and secondly, if spells * are added via addon mods the entries would have to be updated manually with the new numbers. - *

    + *

    * (This reasoning is similar to that for the enchant_randomly function in vanilla Minecraft, since you can specify NBT * data in loot tables, but using NBT in this way would be incredibly verbose and inflexible, hence the loot function.) - * - * @see WizardryUtilities#getStandardWeightedRandomSpellId(Random, boolean) + * * @author Electroblob * @since Wizardry 1.2 */ @@ -62,14 +56,16 @@ public class RandomSpell extends LootFunction { private final List spells; private final boolean ignoreWeighting; + private final float undiscoveredBias; private final List tiers; private final List elements; - protected RandomSpell(LootCondition[] conditions, List spells, boolean ignoreWeighting, List tiers, - List elements){ + protected RandomSpell(LootCondition[] conditions, List spells, boolean ignoreWeighting, + float undiscoveredBias, List tiers, List elements){ super(conditions); this.spells = spells; this.ignoreWeighting = ignoreWeighting; + this.undiscoveredBias = undiscoveredBias; this.tiers = tiers; this.elements = elements; } @@ -99,8 +95,8 @@ public class RandomSpell extends LootFunction { // Elements aren't weighted if(elements == null || elements.isEmpty()){ - // Element can only be MAGIC if tier is BASIC - if(tier == Tier.BASIC){ + // Element can only be MAGIC if tier is NOVICE + if(tier == Tier.NOVICE){ element = Element.values()[random.nextInt(Element.values().length)]; }else{ Element[] elements = ArrayUtils.removeElement(Element.values(), Element.MAGIC); @@ -114,15 +110,17 @@ public class RandomSpell extends LootFunction { // Here's a thought: does randomly selecting the element beforehand (as opposed to leaving it null and letting // the spell randomiser use any element) change the overall outcome at all? - List spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element)); - if(stack.getItem() instanceof ItemScroll) spellsList.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); + List spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, SpellProperties.Context.TREASURE)); - // Ensures the tier chosen actually has spells in it, and if not uses BASIC instead. BASIC always has at least + if(stack.getItem() instanceof ItemScroll) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL)); + if(stack.getItem() instanceof ItemSpellBook) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK)); + + // Ensures the tier chosen actually has spells in it, and if not uses NOVICE instead. NOVICE always has at least // the NONE spell since this spell cannot be disabled. - // NOTE: Commented out for now because it will interfere with the ability to specify tiers and elements. + // Commented out for now because it will interfere with the ability to specify tiers and elements. // To be honest, I may as well just say that if you disable enough spells to make this important, you deserve // less loot! - /* if(spells.isEmpty()){ spellsList = Spell.getSpells(new Spell.TierElementFilter(EnumTier.BASIC, null)); + /* if(spells.isEmpty()){ spellsList = Spell.getSpells(new Spell.TierElementFilter(EnumTier.NOVICE, null)); * if(stack.getItem() instanceof ItemScroll) spellsList.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); * } */ @@ -130,12 +128,30 @@ public class RandomSpell extends LootFunction { spellsList.retainAll(spells); } + // This method is badly-named, loot chests pass a player through too, not just mobs + // (And WHY does it only return an entity?! The underlying field is always a player so I'm casting it anyway) + EntityPlayer player = (EntityPlayer)context.getKillerPlayer(); + + // Remove either the undiscovered spells or the discovered ones, depending on the bias + if(undiscoveredBias > 0 && player != null){ + + WizardData data = WizardData.get(player); + + int discoveredCount = (int)spellsList.stream().filter(data::hasSpellBeenDiscovered).count(); + // If none have been discovered or they've all been discovered, don't bother! + if(discoveredCount > 0 && discoveredCount < spellsList.size()){ + // Kinda unintuitive but it's very neat! + boolean keepDiscovered = random.nextFloat() < 0.5f + 0.5f * undiscoveredBias; + spellsList.removeIf(s -> keepDiscovered != data.hasSpellBeenDiscovered(s)); + } + } + if(spellsList.isEmpty()){ Wizardry.logger.warn("Tried to apply the random_spell loot function to an item, but no enabled spells" + "matched the criteria specified. Substituting placeholder (metadata 0) item."); stack.setItemDamage(0); }else{ - stack.setItemDamage(spellsList.get(random.nextInt(spellsList.size())).id()); + stack.setItemDamage(spellsList.get(random.nextInt(spellsList.size())).metadata()); } return stack; @@ -162,6 +178,8 @@ public class RandomSpell extends LootFunction { object.addProperty("ignore_weighting", function.ignoreWeighting); + object.addProperty("undiscovered_bias", function.undiscoveredBias); + if(function.tiers != null && !function.tiers.isEmpty()){ JsonArray jsonarray = new JsonArray(); @@ -178,7 +196,7 @@ public class RandomSpell extends LootFunction { JsonArray jsonarray = new JsonArray(); for(Element element : function.elements){ - jsonarray.add(new JsonPrimitive(element.getUnlocalisedName())); + jsonarray.add(new JsonPrimitive(element.getName())); } object.add("elements", jsonarray); @@ -194,8 +212,7 @@ public class RandomSpell extends LootFunction { if(object.has("spells")){ - // Vanilla Minecraft calls Lists.newArrayList() here, which is completely pointless. - spells = new ArrayList(); + spells = new ArrayList<>(); // Importantly, it is necessary to specify a default (the new JsonArray) here because otherwise the // parameter will be mandatory, and the game will crash if it isn't present. @@ -215,50 +232,43 @@ public class RandomSpell extends LootFunction { boolean ignoreWeighting = JsonUtils.getBoolean(object, "ignore_weighting", false); + float undiscoveredBias = JsonUtils.getFloat(object, "undiscovered_bias", 0); + if(object.has("tiers")){ - // Vanilla Minecraft calls Lists.newArrayList() here, which is completely pointless. - tiers = new ArrayList(); + tiers = new ArrayList<>(); - jsonarray: for(JsonElement element : JsonUtils.getJsonArray(object, "tiers", new JsonArray())){ + for(JsonElement element : JsonUtils.getJsonArray(object, "tiers", new JsonArray())){ String string = JsonUtils.getString(element, "tier"); - // IDEA: If it is necessary to get tiers by name elsewhere in the future, move this to EnumTier. - for(Tier tier : Tier.values()){ - if(tier.getUnlocalisedName().equals(string)){ - tiers.add(tier); - continue jsonarray; - } + try { + tiers.add(Tier.fromName(string)); + }catch(IllegalArgumentException e){ + // If the string does not match any of the tiers, throws an exception. + throw new JsonSyntaxException("Unknown tier \'" + string + "\'"); } - // If the string does not match any of the tiers, throws an exception. - throw new JsonSyntaxException("Unknown tier \'" + string + "\'"); } } if(object.has("elements")){ - // Vanilla Minecraft calls Lists.newArrayList() here, which is completely pointless. - elements = new ArrayList(); + elements = new ArrayList<>(); - jsonarray: for(JsonElement jelement : JsonUtils.getJsonArray(object, "elements", new JsonArray())){ + for(JsonElement jelement : JsonUtils.getJsonArray(object, "elements", new JsonArray())){ String string = JsonUtils.getString(jelement, "element"); - // IDEA: If it is necessary to get elements by name elsewhere in the future, move this to - // EnumElement. - for(Element element : Element.values()){ - if(element.getUnlocalisedName().equals(string)){ - elements.add(element); - continue jsonarray; - } + try { + elements.add(Element.fromName(string)); + }catch(IllegalArgumentException e){ + // If the string does not match any of the elements, throws an exception. + throw new JsonSyntaxException("Unknown element \'" + string + "\'"); } - // If the string does not match any of the elements, throws an exception. - throw new JsonSyntaxException("Unknown element \'" + string + "\'"); } } - return new RandomSpell(conditions, spells, ignoreWeighting, tiers, elements); + return new RandomSpell(conditions, spells, ignoreWeighting, undiscoveredBias, tiers, elements); } } diff --git a/src/main/java/electroblob/wizardry/loot/WizardSpell.java b/src/main/java/electroblob/wizardry/loot/WizardSpell.java index 3609926f..72c6d35a 100644 --- a/src/main/java/electroblob/wizardry/loot/WizardSpell.java +++ b/src/main/java/electroblob/wizardry/loot/WizardSpell.java @@ -1,12 +1,8 @@ package electroblob.wizardry.loot; -import java.util.List; -import java.util.Random; - import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.living.ISpellCaster; import electroblob.wizardry.item.ItemSpellBook; @@ -18,6 +14,9 @@ import net.minecraft.world.storage.loot.LootContext; import net.minecraft.world.storage.loot.conditions.LootCondition; import net.minecraft.world.storage.loot.functions.LootFunction; +import java.util.List; +import java.util.Random; + /** * Loot function that allows spell books to select a random spell from the spells used by the ISpellCaster that dropped * them. @@ -40,7 +39,7 @@ public class WizardSpell extends LootFunction { if(context.getLootedEntity() instanceof ISpellCaster){ List spells = ((ISpellCaster)context.getLootedEntity()).getSpells(); spells.remove(Spells.magic_missile); // Can't drop magic missile - stack.setItemDamage(spells.get(random.nextInt(spells.size())).id()); + stack.setItemDamage(spells.get(random.nextInt(spells.size())).metadata()); }else{ Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster."); } diff --git a/src/main/java/electroblob/wizardry/misc/BehaviourSpellDispense.java b/src/main/java/electroblob/wizardry/misc/BehaviourSpellDispense.java new file mode 100644 index 00000000..cf75f72b --- /dev/null +++ b/src/main/java/electroblob/wizardry/misc/BehaviourSpellDispense.java @@ -0,0 +1,105 @@ +package electroblob.wizardry.misc; + +import electroblob.wizardry.data.DispenserCastingData; +import electroblob.wizardry.event.SpellCastEvent; +import electroblob.wizardry.event.SpellCastEvent.Source; +import electroblob.wizardry.item.ItemScroll; +import electroblob.wizardry.packet.PacketDispenserCastSpell; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.block.BlockDispenser; +import net.minecraft.dispenser.IBlockSource; +import net.minecraft.dispenser.IPosition; +import net.minecraft.init.Bootstrap.BehaviorDispenseOptional; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +/** + * Dispenser behaviour for casting spells from dispensers based on the metadata of the dispensed item. This class, along + * with the capability {@link DispenserCastingData DispenserCastingData}, forms the dispenser + * equivalent of {@link electroblob.wizardry.entity.living.EntityAIAttackSpell EntityAIAttackSpell}, which handles spell + * casting for NPCs. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +/* + * The dispenser and NPC casting systems are somewhat comparable in structure: + * + | Dispensers | NPCs | + | -------------------------|---------------------------| + | BehaviourSpellDispense | EntityAIAttackSpell | Handles the actual spell casting. These are slightly different + | | | | | in that EntityAIAttackSpell handles ticking for NPC spells, + | | | | | whereas for dispensers this is handled in DispenserCastingData. + | V | V | + | DispenserCastingData | ISpellCaster | Deals with data storage for spell casting. Of course, being an + | | | interface, ISpellCaster doesn't actually store the data itself. + * + */ +public class BehaviourSpellDispense extends BehaviorDispenseOptional { + + public BehaviourSpellDispense(){} + + @Override + protected ItemStack dispenseStack(IBlockSource source, ItemStack stack){ + + // This is only ever called server-side. + + successful = false; + + World world = source.getWorld(); + // This returns a position that is 0.2 blocks away from the middle of the front face of the dispenser + IPosition position = BlockDispenser.getDispensePosition(source); + EnumFacing direction = source.getBlockState().getValue(BlockDispenser.FACING); + + Spell spell = Spell.byMetadata(stack.getMetadata()); + + // If there's a block in the way, nothing happens + if(world.isSideSolid(source.getBlockPos().offset(direction), direction.getOpposite())) return stack; + + // If the scroll can never be cast by a dispenser, it should be dispensed as an item. + if(!spell.canBeCastByDispensers()) return super.dispenseStack(source, stack); + + SpellModifiers modifiers = new SpellModifiers(); + + double x = position.getX(); + double y = position.getY(); + double z = position.getZ(); + + // For horizontal dispensers, the position is lowered by 0.125 so it actually lines up with the hole. + if(direction.getAxis().isHorizontal()) y -= 0.125; + + // If the scroll can be cast by a dispenser, it should be cast. If this fails, then the scroll should stay in + // the dispenser. + if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Pre(Source.DISPENSER, spell, world, x, y, z, direction, modifiers))) + return stack; + + successful = spell.cast(world, x, y, z, direction, 0, -1, modifiers); + + if(successful){ + + MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.DISPENSER, spell, world, x, y, z, direction, modifiers)); + + stack.shrink(1); + + if(spell.isContinuous || spell.requiresPacket()){ + // Sends a packet to all players in dimension to tell them to spawn particles. + IMessage msg = new PacketDispenserCastSpell.Message(x, y, z, direction, source.getBlockPos(), spell, + spell.isContinuous ? ItemScroll.CASTING_TIME : 0, modifiers); // Non-continuous spells ignore duration + WizardryPacketHandler.net.sendToDimension(msg, world.provider.getDimension()); + } + + if(spell.isContinuous){ + DispenserCastingData data = DispenserCastingData.get(source.getBlockTileEntity()); + data.startCasting(spell, x, y, z, ItemScroll.CASTING_TIME, modifiers); + } + } + + return stack; + } + +} diff --git a/src/main/java/electroblob/wizardry/misc/Forfeit.java b/src/main/java/electroblob/wizardry/misc/Forfeit.java new file mode 100644 index 00000000..e5782a66 --- /dev/null +++ b/src/main/java/electroblob/wizardry/misc/Forfeit.java @@ -0,0 +1,487 @@ +package electroblob.wizardry.misc; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.entity.EntityMeteor; +import electroblob.wizardry.entity.construct.*; +import electroblob.wizardry.entity.living.*; +import electroblob.wizardry.entity.projectile.EntityFirebomb; +import electroblob.wizardry.entity.projectile.EntityMagicFireball; +import electroblob.wizardry.event.SpellCastEvent; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.*; +import electroblob.wizardry.spell.Banish; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.effect.EntityLightningBolt; +import net.minecraft.entity.item.EntityFallingBlock; +import net.minecraft.entity.passive.EntitySquid; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.*; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraftforge.common.IPlantable; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.function.BiConsumer; + +/** + * A {@code Forfeit} object represents a negative effect that may happen when a player attempts to cast an + * undiscovered spell. The nature and severity of the forfeit depends on the element and tier of the spell that was + * attempted.
    + *
    + * Adding a new forfeit is as simple as calling {@link Forfeit#add(Tier, Element, Forfeit)} and supplying the + * {@code Forfeit} instance along with a tier and element to associate it with. To create a forfeit, you may extend + * this class and instantiate it, or use {@link Forfeit#create(ResourceLocation, BiConsumer)} to concisely define the + * behaviour (this method is provided since most forfeits' behaviour code is fairly brief and would otherwise result in + * a large number of trivial 'stub' classes - in fact, many of wizardry's forfeits are defined in a single line).
    + *
    + * This class also handles the (event-driven) selection of forfeits and determines when one should be applied. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +// With the exception of sound events, everything forfeit-related is done right here. How about that for modularity? :P +@Mod.EventBusSubscriber +public abstract class Forfeit { + + private static final ListMultimap, Forfeit> forfeits = ArrayListMultimap.create(); + + private static final float TIER_CHANGE_CHANCE = 0.2f; + + private final ResourceLocation name; + + protected final SoundEvent sound; + + public Forfeit(ResourceLocation name){ + this.name = name; + this.sound = WizardrySounds.createSound("forfeit." + name.getPath()); + } + + public abstract void apply(World world, EntityPlayer player); + + /** + * Returns an {@link ITextComponent} for the message displayed when this forfeit is activated. + * @param implementName An {@code ITextComponent} for the name of the implement being used. This is usually + * something generic like 'wand' or 'scroll'. + * @return An {@code ITextComponent} representing this forfeit's message, for use in chat messages. + * @see Forfeit#getMessageForWand() + * @see Forfeit#getMessageForScroll() + */ + public ITextComponent getMessage(ITextComponent implementName){ + return new TextComponentTranslation("forfeit." + name.toString(), implementName); + } + + /** Wrapper for {@link Forfeit#getMessage(ITextComponent)} with {@code implementName} set to the lang file key + * {@code item.ebwizardry:wand.generic} */ + public ITextComponent getMessageForWand(){ + return getMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":wand.generic")); + } + + /** Wrapper for {@link Forfeit#getMessage(ITextComponent)} with {@code implementName} set to the lang file key + * {@code item.ebwizardry:scroll.generic} */ + public ITextComponent getMessageForScroll(){ + return getMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":scroll.generic")); + } + + /** Returns the {@link SoundEvent} played when this forfeit is activated. */ + public SoundEvent getSound(){ + return sound; + } + + public static void add(Tier tier, Element element, Forfeit forfeit){ + forfeits.put(Pair.of(tier, element), forfeit); + } + + public static Forfeit getRandomForfeit(Random random, Tier tier, Element element){ + float f = random.nextFloat(); + if(f < TIER_CHANGE_CHANCE && tier.ordinal() > 0) tier = Tier.values()[tier.ordinal() - 1]; + else if(f > 1 - TIER_CHANGE_CHANCE && tier.ordinal() < Tier.values().length-1) tier = Tier.values()[tier.ordinal() + 1]; + List matches = forfeits.get(Pair.of(tier, element)); + if(matches.isEmpty()){ + Wizardry.logger.warn("No forfeits with tier {} and element {}!", tier, element); + return null; + } + return matches.get(random.nextInt(matches.size())); + } + + public static Collection getForfeits(){ + return Collections.unmodifiableCollection(forfeits.values()); + } + + /** Static helper method that creates a {@code Forfeit} with the given name and an effect specified by the given + * consumer. This allows code to use a neater lambda expression rather than an anonymous class. */ + public static Forfeit create(ResourceLocation name, BiConsumer effect){ + return new Forfeit(name){ + @Override + public void apply(World world, EntityPlayer player){ + effect.accept(world, player); + } + }; + } + + /** Internal wrapper for {@link Forfeit#create(ResourceLocation, BiConsumer)} so I don't have to put wizardry's + * mod ID in every time. */ + private static Forfeit create(String name, BiConsumer effect){ + return create(new ResourceLocation(Wizardry.MODID, name), effect); + } + + @SubscribeEvent(priority = EventPriority.NORMAL) // Forfeits come after spell disabling but before modifiers + public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ + + if(!Wizardry.settings.discoveryMode) return; + + if(event.getCaster() instanceof EntityPlayer && !((EntityPlayer)event.getCaster()).isCreative() + && (event.getSource() == SpellCastEvent.Source.WAND || event.getSource() == SpellCastEvent.Source.SCROLL)){ + + EntityPlayer player = (EntityPlayer)event.getCaster(); + WizardData data = WizardData.get(player); + + float chance = (float)Wizardry.settings.forfeitChance; + if(ItemArtefact.isArtefactActive(player, WizardryItems.amulet_wisdom)) chance *= 0.5; + + // Use the synchronised random to ensure the same outcome on client- and server-side + if(data.synchronisedRandom.nextFloat() < chance && !data.hasSpellBeenDiscovered(event.getSpell())){ + + event.setCanceled(true); + + Forfeit forfeit = getRandomForfeit(event.getWorld().rand, event.getSpell().getTier(), event.getSpell().getElement()); + + if(forfeit == null){ // Should never happen, but just in case... + if(!event.getWorld().isRemote) player.sendMessage(new TextComponentTranslation("forfeit.ebwizardry:do_nothing")); + return; + } + + forfeit.apply(event.getWorld(), player); + + WizardryAdvancementTriggers.spell_failure.triggerFor(player); + + WizardryUtilities.playSoundAtPlayer(player, forfeit.getSound(), WizardrySounds.SPELLS, 1, 1); + + if(!event.getWorld().isRemote) player.sendMessage( + event.getSource() == SpellCastEvent.Source.WAND ? forfeit.getMessageForWand() : forfeit.getMessageForScroll()); + } + } + } + + /** Called from the preInit method in the main mod class to set up all the forfeits. */ + public static void register(){ + + add(Tier.NOVICE, Element.FIRE, create("burn_self", (w, p) -> p.setFire(5))); + + add(Tier.APPRENTICE, Element.FIRE, create("fireball", (w, p) -> { + if(!w.isRemote){ + EntityMagicFireball fireball = new EntityMagicFireball(w); + Vec3d vec = p.getPositionEyes(0).add(p.getLookVec().scale(6)); + fireball.setPosition(vec.x, vec.y, vec.z); + fireball.shoot(p.posX, p.posY + p.getEyeHeight(), p.posZ, 1.5f, 1); + w.spawnEntity(fireball); + } + })); + + add(Tier.APPRENTICE, Element.FIRE, create("firebomb", (w, p) -> { + if(!w.isRemote){ + EntityFirebomb firebomb = new EntityFirebomb(w); + firebomb.setPosition(p.posX, p.posY + 5, p.posZ); + w.spawnEntity(firebomb); + } + })); + + add(Tier.ADVANCED, Element.FIRE, create("explode", (w, p) -> w.createExplosion(null, p.posX, p.posY, p.posZ, 1, false))); + + add(Tier.ADVANCED, Element.FIRE, create("blazes", (w, p) -> { + if(!w.isRemote){ + for(int i = 0; i < 3; i++){ + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(p, 4, 2); + if(pos == null) break; + EntityBlazeMinion blaze = new EntityBlazeMinion(w); + blaze.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + w.spawnEntity(blaze); + } + } + })); + + add(Tier.MASTER, Element.FIRE, create("burn_surroundings", (w, p) -> { + if(!w.isRemote){ + List sphere = WizardryUtilities.getBlockSphere(p.getPosition(), 6); + for(BlockPos pos : sphere){ + if(w.rand.nextBoolean() && w.isAirBlock(pos)) w.setBlockState(pos, Blocks.FIRE.getDefaultState()); + } + } + })); + + add(Tier.MASTER, Element.FIRE, create("meteors", (w, p) -> { + if(!w.isRemote) for(int i=0; i<5; i++) w.spawnEntity(new EntityMeteor(w, p.posX + w.rand.nextDouble() * 16 - 8, + p.posY + 40 + w.rand.nextDouble() * 30, p.posZ + w.rand.nextDouble() * 16 - 8, + 1, WizardryUtilities.canDamageBlocks(p, w))); + })); + + add(Tier.NOVICE, Element.ICE, create("freeze_self", (w, p) -> p.addPotionEffect(new PotionEffect(WizardryPotions.frost, 200)))); + + add(Tier.APPRENTICE, Element.ICE, create("freeze_self_2", (w, p) -> p.addPotionEffect(new PotionEffect(WizardryPotions.frost, 300, 1)))); + + add(Tier.APPRENTICE, Element.ICE, create("ice_spikes", (w, p) -> { + if(!w.isRemote){ + for(int i = 0; i < 5; i++){ + EntityIceSpike iceSpike = new EntityIceSpike(w); + double x = p.posX + 2 - w.rand.nextFloat() * 4; + double z = p.posZ + 2 - w.rand.nextFloat() * 4; + Integer y = WizardryUtilities.getNearestSurface(w, new BlockPos(x, p.posY, z), EnumFacing.UP, 2, true, + WizardryUtilities.SurfaceCriteria.basedOn(World::isBlockFullCube)); + if(y == null) break; + iceSpike.setFacing(EnumFacing.UP); + iceSpike.setPosition(x, y, z); + w.spawnEntity(iceSpike); + } + } + })); + + add(Tier.ADVANCED, Element.ICE, create("blizzard", (w, p) -> { + if(!w.isRemote){ + EntityBlizzard blizzard = new EntityBlizzard(w); + blizzard.setPosition(p.posX, p.posY, p.posZ); + w.spawnEntity(blizzard); + } + })); + + add(Tier.ADVANCED, Element.ICE, create("ice_wraiths", (w, p) -> { + if(!w.isRemote){ + for(int i = 0; i < 3; i++){ + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(p, 4, 2); + if(pos == null) break; + EntityIceWraith iceWraith = new EntityIceWraith(w); + iceWraith.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + w.spawnEntity(iceWraith); + } + } + })); + + add(Tier.MASTER, Element.ICE, create("hailstorm", (w, p) -> { + if(!w.isRemote){ + EntityHailstorm hailstorm = new EntityHailstorm(w); + hailstorm.setPosition(p.posX, p.posY + 5, p.posZ - 3); // Subtract 3 from z because it's facing south (yaw 0) + w.spawnEntity(hailstorm); + } + })); + + add(Tier.MASTER, Element.ICE, create("ice_giant", (w, p) -> { + if(!w.isRemote){ + EntityIceGiant iceGiant = new EntityIceGiant(w); + iceGiant.setPosition(p.posX + p.getLookVec().x * 4, p.posY, p.posZ + p.getLookVec().z * 4); + w.spawnEntity(iceGiant); + } + })); + + add(Tier.NOVICE, Element.LIGHTNING, create("thunder", (w, p) -> { + p.addVelocity(-p.getLookVec().x, 0, -p.getLookVec().z); + if(w.isRemote) w.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, p.posX, p.posY, p.posZ, 0, 0, 0); + })); + + add(Tier.APPRENTICE, Element.LIGHTNING, create("storm", (w, p) -> { + int standardWeatherTime = (300 + (new Random()).nextInt(600)) * 20; + w.getWorldInfo().setRaining(true); + w.getWorldInfo().setRainTime(standardWeatherTime); + w.getWorldInfo().setThundering(true); + w.getWorldInfo().setThunderTime(standardWeatherTime); + })); + + add(Tier.APPRENTICE, Element.LIGHTNING, create("lightning_sigils", (w, p) -> { + if(!w.isRemote){ + for(EnumFacing direction : EnumFacing.HORIZONTALS){ + BlockPos pos = p.getPosition().offset(direction, 2); + Integer y = WizardryUtilities.getNearestFloor(w, pos, 2); + if(y == null) continue; + EntityLightningSigil sigil = new EntityLightningSigil(w); + sigil.setPosition(pos.getX() + 0.5, y, pos.getZ() + 0.5); + w.spawnEntity(sigil); + } + } + })); + + add(Tier.ADVANCED, Element.LIGHTNING, create("lightning", (w, p) -> w.addWeatherEffect(new EntityLightningBolt(w, p.posX, p.posY, p.posZ, false)))); + + add(Tier.ADVANCED, Element.LIGHTNING, create("paralyse_self", (w, p) -> p.addPotionEffect(new PotionEffect(WizardryPotions.paralysis, 200)))); + + add(Tier.ADVANCED, Element.LIGHTNING, create("lightning_wraiths", (w, p) -> { + if(!w.isRemote){ + for(int i = 0; i < 3; i++){ + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(p, 4, 2); + if(pos == null) break; + EntityLightningWraith lightningWraith = new EntityLightningWraith(w); + lightningWraith.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + w.spawnEntity(lightningWraith); + } + } + })); + + add(Tier.MASTER, Element.LIGHTNING, create("storm_elementals", (w, p) -> { + if(!w.isRemote){ + for(EnumFacing direction : EnumFacing.HORIZONTALS){ + BlockPos pos = p.getPosition().offset(direction, 3); + EntityStormElemental stormElemental = new EntityStormElemental(w); + stormElemental.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + w.spawnEntity(stormElemental); + } + } + })); + + add(Tier.NOVICE, Element.NECROMANCY, create("nausea", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, 400)))); + + add(Tier.APPRENTICE, Element.NECROMANCY, create("zombie_horde", (w, p) -> { + if(!w.isRemote){ + for(int i = 0; i < 3; i++){ + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(p, 4, 2); + if(pos == null) break; + EntityZombieMinion zombie = new EntityZombieMinion(w); + zombie.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + w.spawnEntity(zombie); + } + } + })); + + add(Tier.ADVANCED, Element.NECROMANCY, create("wither_self", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.WITHER, 400)))); + + add(Tier.MASTER, Element.NECROMANCY, create("cripple_self", (w, p) -> p.attackEntityFrom(DamageSource.MAGIC, p.getHealth() - 1))); + + add(Tier.MASTER, Element.NECROMANCY, create("shadow_wraiths", (w, p) -> { + if(!w.isRemote){ + for(EnumFacing direction : EnumFacing.HORIZONTALS){ + BlockPos pos = p.getPosition().offset(direction, 3); + EntityShadowWraith wraith = new EntityShadowWraith(w); + wraith.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + w.spawnEntity(wraith); + } + } + })); + + add(Tier.NOVICE, Element.EARTH, create("snares", (w, p) -> { + if(!w.isRemote){ + for(EnumFacing direction : EnumFacing.HORIZONTALS){ + BlockPos pos = p.getPosition().offset(direction); + w.setBlockState(pos, WizardryBlocks.snare.getDefaultState()); + } + } + })); + + add(Tier.NOVICE, Element.EARTH, create("squid", (w, p) -> { + if(!w.isRemote){ + EntitySquid squid = new EntitySquid(w); + squid.setPosition(p.posX, p.posY + 3, p.posZ); + w.spawnEntity(squid); + } + })); + + add(Tier.APPRENTICE, Element.EARTH, create("uproot_plants", (w, p) -> { + if(!w.isRemote){ + List sphere = WizardryUtilities.getBlockSphere(p.getPosition(), 5); + sphere.removeIf(pos -> !(w.getBlockState(pos).getBlock() instanceof IPlantable)); + sphere.forEach(pos -> w.destroyBlock(pos, true)); + } + })); + + add(Tier.APPRENTICE, Element.EARTH, create("poison_self", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.POISON, 400, 1)))); + + add(Tier.ADVANCED, Element.EARTH, create("flood", (w, p) -> { + if(!w.isRemote){ + List sphere = WizardryUtilities.getBlockSphere(p.getPosition().up(), 2); + sphere.removeIf(pos -> !WizardryUtilities.canBlockBeReplaced(w, pos, true)); + sphere.forEach(pos -> w.setBlockState(pos, Blocks.WATER.getDefaultState())); + } + })); + + add(Tier.MASTER, Element.EARTH, create("bury_self", (w, p) -> { + if(!w.isRemote){ + List sphere = WizardryUtilities.getBlockSphere(p.getPosition(), 4); + sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube()); + sphere.forEach(pos -> { + EntityFallingBlock block = new EntityFallingBlock(w, pos.getX() + 0.5, pos.getY() + 0.5, + pos.getZ() + 0.5, w.getBlockState(pos)); + block.motionY = 0.3 * (4 - (p.getPosition().getY() - pos.getY())); + w.spawnEntity(block); + }); + } + })); + + add(Tier.NOVICE, Element.SORCERY, create("spill_inventory", (w, p) -> { + for(int i = 0; i < p.inventory.mainInventory.size(); i++){ + ItemStack stack = p.inventory.mainInventory.get(i); + if(!stack.isEmpty()){ + p.dropItem(stack, true, false); + p.inventory.mainInventory.set(i, ItemStack.EMPTY); + } + } + })); + + add(Tier.APPRENTICE, Element.SORCERY, create("teleport_self", (w, p) -> ((Banish)Spells.banish).teleport(p, w, 8 + w.rand.nextDouble() * 8))); + + add(Tier.ADVANCED, Element.SORCERY, create("levitate_self", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.LEVITATION, 200)))); + + add(Tier.ADVANCED, Element.SORCERY, create("vex_horde", (w, p) -> { + if(!w.isRemote){ + for(int i = 0; i < 4; i++){ + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(p, 4, 2); + if(pos == null) break; + EntityVexMinion vex = new EntityVexMinion(w); + vex.setPosition(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5); + w.spawnEntity(vex); + } + } + })); + + add(Tier.MASTER, Element.SORCERY, create("black_hole", (w, p) -> { + EntityBlackHole blackHole = new EntityBlackHole(w); + Vec3d vec = p.getPositionEyes(1).add(p.getLookVec().scale(4)); + blackHole.setPosition(vec.x, vec.y, vec.z); + w.spawnEntity(blackHole); + })); + + add(Tier.MASTER, Element.SORCERY, create("arrow_rain", (w, p) -> { + if(!w.isRemote){ + EntityArrowRain arrowRain = new EntityArrowRain(w); + arrowRain.setPosition(p.posX, p.posY + 5, p.posZ - 3); // Subtract 3 from z because it's facing south (yaw 0) + w.spawnEntity(arrowRain); + } + })); + + add(Tier.NOVICE, Element.HEALING, create("damage_self", (w, p) -> p.attackEntityFrom(DamageSource.MAGIC, 4))); + + add(Tier.NOVICE, Element.HEALING, create("spill_armour", (w, p) -> { + for(int i = 0; i < p.inventory.armorInventory.size(); i++){ + ItemStack stack = p.inventory.armorInventory.get(i); + if(!stack.isEmpty()){ + p.dropItem(stack, true, false); + p.inventory.armorInventory.set(i, ItemStack.EMPTY); + } + } + })); + + add(Tier.APPRENTICE, Element.HEALING, create("hunger", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.HUNGER, 400, 4)))); + + add(Tier.APPRENTICE, Element.HEALING, create("blind_self", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 200)))); + + add(Tier.ADVANCED, Element.HEALING, create("weaken_self", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 600, 3)))); + + add(Tier.ADVANCED, Element.HEALING, create("jam_self", (w, p) -> p.addPotionEffect(new PotionEffect(WizardryPotions.arcane_jammer, 300)))); + + add(Tier.MASTER, Element.HEALING, create("curse_self", (w, p) -> p.addPotionEffect(new PotionEffect(WizardryPotions.curse_of_undeath, Integer.MAX_VALUE)))); + + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/util/WildcardTradeList.java b/src/main/java/electroblob/wizardry/misc/WildcardTradeList.java similarity index 98% rename from src/main/java/electroblob/wizardry/util/WildcardTradeList.java rename to src/main/java/electroblob/wizardry/misc/WildcardTradeList.java index d7a60a2a..0917bcfa 100644 --- a/src/main/java/electroblob/wizardry/util/WildcardTradeList.java +++ b/src/main/java/electroblob/wizardry/misc/WildcardTradeList.java @@ -1,4 +1,4 @@ -package electroblob.wizardry.util; +package electroblob.wizardry.misc; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/electroblob/wizardry/util/WizardryPathFinder.java b/src/main/java/electroblob/wizardry/misc/WizardryPathFinder.java similarity index 99% rename from src/main/java/electroblob/wizardry/util/WizardryPathFinder.java rename to src/main/java/electroblob/wizardry/misc/WizardryPathFinder.java index 898f9b4c..edd4156b 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryPathFinder.java +++ b/src/main/java/electroblob/wizardry/misc/WizardryPathFinder.java @@ -1,11 +1,6 @@ -package electroblob.wizardry.util; - -import java.util.Set; - -import javax.annotation.Nullable; +package electroblob.wizardry.misc; import com.google.common.collect.Sets; - import electroblob.wizardry.spell.Clairvoyance; import net.minecraft.entity.EntityLiving; import net.minecraft.pathfinding.NodeProcessor; @@ -15,6 +10,9 @@ import net.minecraft.pathfinding.PathPoint; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; +import javax.annotation.Nullable; +import java.util.Set; + /** * Minecraft's pathfinder refused to play nicely, so I 'borrowed' its code and fiddled with it. Currently this is only * used for the {@link Clairvoyance} spell. diff --git a/src/main/java/electroblob/wizardry/packet/PacketCastContinuousSpell.java b/src/main/java/electroblob/wizardry/packet/PacketCastContinuousSpell.java index 35516b63..a4c30b65 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketCastContinuousSpell.java +++ b/src/main/java/electroblob/wizardry/packet/PacketCastContinuousSpell.java @@ -1,16 +1,19 @@ package electroblob.wizardry.packet; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.packet.PacketCastContinuousSpell.Message; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; /** * [Server -> Client] This packet is sent when the /cast command is used with a continuous spell, in order to - * sync the relevant variables in {@link electroblob.wizardry.WizardData WizardData}. + * sync the relevant variables in {@link WizardData WizardData}. */ public class PacketCastContinuousSpell implements IMessageHandler { @@ -21,12 +24,7 @@ public class PacketCastContinuousSpell implements IMessageHandler Wizardry.proxy.handleCastContinuousSpellPacket(message)); } return null; @@ -34,24 +32,23 @@ public class PacketCastContinuousSpell implements IMessageHandler { if(ctx.side.isClient()){ // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy // methods any more than necessary. - net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ - @Override - public void run(){ - Wizardry.proxy.handleCastSpellPacket(message); - } - }); + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleCastSpellPacket(message)); } return null; @@ -52,10 +48,10 @@ public class PacketCastSpell implements IMessageHandler { public Message(){ } - public Message(int casterID, EnumHand hand, int spellID, SpellModifiers modifiers){ + public Message(int casterID, EnumHand hand, Spell spell, SpellModifiers modifiers){ this.casterID = casterID; - this.spellID = spellID; + this.spellID = spell.networkID(); this.modifiers = modifiers; this.hand = hand == null ? EnumHand.MAIN_HAND : hand; } diff --git a/src/main/java/electroblob/wizardry/packet/PacketCastSpellAtPos.java b/src/main/java/electroblob/wizardry/packet/PacketCastSpellAtPos.java new file mode 100644 index 00000000..bb9047b7 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketCastSpellAtPos.java @@ -0,0 +1,85 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import io.netty.buffer.ByteBuf; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** + * [Server -> Client] This packet is sent when a spell is cast at a position by commands and returns true, and is + * sent to clients so they can spawn the particles themselves. + */ +// Soooo many spell casting packets... +public class PacketCastSpellAtPos implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleCastSpellAtPosPacket(message)); + } + + return null; + } + + public static class Message implements IMessage { + + /** Position for the spell */ + public Vec3d position; + /** Direction for the spell */ + public EnumFacing direction; + /** ID of the spell being cast */ + public int spellID; + /** SpellModifiers for the spell */ + public SpellModifiers modifiers; + /** Number of ticks to cast the spell for, or -1 for non-continuous spells */ + public int duration; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + public Message(Vec3d position, EnumFacing direction, Spell spell, SpellModifiers modifiers){ + this(position, direction, spell, modifiers, -1); + } + + public Message(Vec3d position, EnumFacing direction, Spell spell, SpellModifiers modifiers, int duration){ + this.spellID = spell.networkID(); + this.modifiers = modifiers; + this.position = position; + this.direction = direction; + this.duration = duration; + } + + @Override + public void fromBytes(ByteBuf buf){ + + // The order is important + position = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble()); + direction = EnumFacing.byIndex(buf.readInt()); + this.spellID = buf.readInt(); + this.modifiers = new SpellModifiers(); + this.modifiers.read(buf); + this.duration = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf){ + + buf.writeDouble(position.x); + buf.writeDouble(position.y); + buf.writeDouble(position.z); + buf.writeInt(direction.getIndex()); + buf.writeInt(spellID); + this.modifiers.write(buf); + buf.writeInt(duration); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketClairvoyance.java b/src/main/java/electroblob/wizardry/packet/PacketClairvoyance.java index cc3b919b..62a4c7ab 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketClairvoyance.java +++ b/src/main/java/electroblob/wizardry/packet/PacketClairvoyance.java @@ -1,8 +1,5 @@ package electroblob.wizardry.packet; -import java.util.ArrayList; -import java.util.List; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.packet.PacketClairvoyance.Message; import io.netty.buffer.ByteBuf; @@ -12,6 +9,9 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import java.util.ArrayList; +import java.util.List; + /** * [Server -> Client] This packet is sent when a player casts the clairvoyance spell to allow pathing to chunks * outside the render distance. diff --git a/src/main/java/electroblob/wizardry/packet/PacketConquerShrine.java b/src/main/java/electroblob/wizardry/packet/PacketConquerShrine.java new file mode 100644 index 00000000..7b04362e --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketConquerShrine.java @@ -0,0 +1,58 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import io.netty.buffer.ByteBuf; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** + * [Server -> Client] This packet is sent when a shrine is conquered to update nearby clients and spawn particles. + */ +public class PacketConquerShrine implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleConquerShrinePacket(message)); + } + + return null; + } + + public static class Message implements IMessage { + + public int x; + public int y; + public int z; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + public Message(BlockPos pos){ + this.x = pos.getX(); + this.y = pos.getY(); + this.z = pos.getZ(); + } + + @Override + public void fromBytes(ByteBuf buf){ + // The order is important + this.x = buf.readInt(); + this.y = buf.readInt(); + this.z = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketControlInput.java b/src/main/java/electroblob/wizardry/packet/PacketControlInput.java index c0f3132d..f2a43d39 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketControlInput.java +++ b/src/main/java/electroblob/wizardry/packet/PacketControlInput.java @@ -1,12 +1,18 @@ package electroblob.wizardry.packet; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.packet.PacketControlInput.Message; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Possession; +import electroblob.wizardry.spell.Resurrection; import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; -import electroblob.wizardry.util.WandHelper; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; import io.netty.buffer.ByteBuf; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; @@ -22,45 +28,100 @@ public class PacketControlInput implements IMessageHandler { final EntityPlayerMP player = ctx.getServerHandler().player; - player.getServerWorld().addScheduledTask(new Runnable(){ + player.getServerWorld().addScheduledTask(() -> { - public void run(){ + ItemStack wand = player.getHeldItemMainhand(); - ItemStack wand = player.getHeldItemMainhand(); + if(!(wand.getItem() instanceof ISpellCastingItem)){ + wand = player.getHeldItemOffhand(); + } - if(!(wand.getItem() instanceof ItemWand)){ - wand = player.getHeldItemOffhand(); - } + switch(message.controlType){ - switch(message.controlType){ - - case APPLY_BUTTON: + case APPLY_BUTTON: + if(!(player.openContainer instanceof ContainerArcaneWorkbench)){ + Wizardry.logger.warn("Received a PacketControlInput, but the player that sent it was not " + + "currently using an arcane workbench. This should not happen!"); + }else{ ((ContainerArcaneWorkbench)player.openContainer).onApplyButtonPressed(player); - break; - - case NEXT_SPELL_KEY: - - if(wand.getItem() instanceof ItemWand){ - - WandHelper.selectNextSpell(wand); - // This line fixes the bug with continuous spells casting when they shouldn't be - player.stopActiveHand(); - } - - break; - - case PREVIOUS_SPELL_KEY: - - if(wand.getItem() instanceof ItemWand){ - - WandHelper.selectPreviousSpell(wand); - // This line fixes the bug with continuous spells casting when they shouldn't be - player.stopActiveHand(); - } - - break; } + + break; + + case NEXT_SPELL_KEY: + + if(wand.getItem() instanceof ISpellCastingItem){ + + ((ISpellCastingItem)wand.getItem()).selectNextSpell(wand); + // This line fixes the bug with continuous spells casting when they shouldn't be + player.stopActiveHand(); + } + + break; + + case PREVIOUS_SPELL_KEY: + + if(wand.getItem() instanceof ISpellCastingItem){ + + ((ISpellCastingItem)wand.getItem()).selectPreviousSpell(wand); + // This line fixes the bug with continuous spells casting when they shouldn't be + player.stopActiveHand(); + } + + break; + + case RESURRECT_BUTTON: + + if(player.isDead && Resurrection.getRemainingWaitTime(player.deathTime) == 0){ + + ItemStack stack = WizardryUtilities.getHotbar(player).stream() + .filter(s -> Resurrection.canStackResurrect(s, player)).findFirst().orElse(null); + + if(stack != null){ + // This should suffice, since this is the only way a player can cast resurrection when dead! + ((ISpellCastingItem)stack.getItem()).cast(stack, Spells.resurrection, player, EnumHand.MAIN_HAND, 0, new SpellModifiers()); + break; + } + } + + Wizardry.logger.warn("Received a resurrect button packet, but the player that sent it was not" + + " currently able to resurrect. This should not happen!"); + + break; + + case CANCEL_RESURRECT: + + if(player.world.getGameRules().getBoolean("keepInventory")) break; // Shouldn't even receive this + + if(player.isDead){ + + ItemStack stack = WizardryUtilities.getHotbar(player).stream() + .filter(s -> Resurrection.canStackResurrect(s, player)).findFirst().orElse(null); + + if(stack != null){ + player.dropItem(stack, true, false); + player.inventory.deleteStack(stack); // Might as well + break; + } + + Wizardry.logger.warn("Received a cancel resurrect packet, but the player that sent it was not" + + " holding a wand with the resurrection spell. This should not happen!"); + } + + Wizardry.logger.warn("Received a cancel resurrect packet, but the player that sent it was not" + + " currently dead. This should not happen!"); + + break; + + case POSSESSION_PROJECTILE: + + if(!Possession.isPossessing(player)) Wizardry.logger.warn("Received a possession projectile packet, " + + "but the player that sent it is not currently possessing anything!"); + + Possession.shootProjectile(player); + + break; } }); } @@ -68,8 +129,8 @@ public class PacketControlInput implements IMessageHandler { return null; } - public static enum ControlType { - APPLY_BUTTON, NEXT_SPELL_KEY, PREVIOUS_SPELL_KEY; + public enum ControlType { + APPLY_BUTTON, NEXT_SPELL_KEY, PREVIOUS_SPELL_KEY, RESURRECT_BUTTON, CANCEL_RESURRECT, POSSESSION_PROJECTILE } public static class Message implements IMessage { diff --git a/src/main/java/electroblob/wizardry/packet/PacketDispenserCastSpell.java b/src/main/java/electroblob/wizardry/packet/PacketDispenserCastSpell.java new file mode 100644 index 00000000..3975bd14 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketDispenserCastSpell.java @@ -0,0 +1,94 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.packet.PacketDispenserCastSpell.Message; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellModifiers; +import io.netty.buffer.ByteBuf; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** + * [Server -> Client] This packet is sent when a spell is cast by a dispenser and returns true, and is sent to + * clients so they can spawn the particles. Unlike the player packets, this is for both continuous and + * non-continuous spells. + */ +public class PacketDispenserCastSpell implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleDispenserCastSpellPacket(message)); + } + + return null; + } + + public static class Message implements IMessage { + + /** ID of the spell being cast */ + public int spellID; + /** Coordinates of the spell origin */ + public double x, y, z; + /** Spell casting direction */ + public EnumFacing direction; + /** BlockPos of the block that cast this spell. Not necessarily the same as the (x, y, z) coordinates. */ + public BlockPos pos; + /** The number of ticks to cast the spell for, or -1 if the spell should be cast until stopped. */ + public int duration; + /** SpellModifiers for the spell */ + public SpellModifiers modifiers; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){ + } + + public Message(double x, double y, double z, EnumFacing direction, BlockPos pos, Spell spell, int duration, SpellModifiers modifiers){ + + this.x = x; + this.y = y; + this.z = z; + this.direction = direction; + this.pos = pos; + this.spellID = spell.networkID(); + this.duration = duration; + this.modifiers = modifiers; + + } + + @Override + public void fromBytes(ByteBuf buf){ + + // The order is important + this.x = buf.readDouble(); + this.y = buf.readDouble(); + this.z = buf.readDouble(); + this.direction = EnumFacing.values()[buf.readInt()]; + this.pos = BlockPos.fromLong(buf.readLong()); + this.spellID = buf.readInt(); + this.duration = buf.readInt(); + this.modifiers = new SpellModifiers(); + this.modifiers.read(buf); + } + + @Override + public void toBytes(ByteBuf buf){ + + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeInt(direction.ordinal()); + buf.writeLong(pos.toLong()); + buf.writeInt(spellID); + buf.writeInt(duration); + this.modifiers.write(buf); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketEmitterData.java b/src/main/java/electroblob/wizardry/packet/PacketEmitterData.java new file mode 100644 index 00000000..4fe8c704 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketEmitterData.java @@ -0,0 +1,55 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.command.SpellEmitter; +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import java.util.ArrayList; +import java.util.List; + +/** + * [Server -> Client] This packet is sent each time a player joins a world to synchronise the client-side spell + * emitters with the server-side ones. + */ +public class PacketEmitterData implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleEmitterDataPacket(message)); + } + + return null; + } + + public static class Message implements IMessage { + + public List emitters; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + public Message(List emitters){ + this.emitters = emitters; + } + + @Override + public void fromBytes(ByteBuf buf){ + emitters = new ArrayList<>(); + while(buf.isReadable()){ + emitters.add(SpellEmitter.read(buf)); + } + } + + @Override + public void toBytes(ByteBuf buf){ + emitters.forEach(s -> s.write(buf)); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketEndSlowTime.java b/src/main/java/electroblob/wizardry/packet/PacketEndSlowTime.java new file mode 100644 index 00000000..e4d276f8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketEndSlowTime.java @@ -0,0 +1,47 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.Entity; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Server -> Client] This packet is sent when the slow time potion effect expires or is removed from an + * entity to unblock all nearby entities' updates. */ +public class PacketEndSlowTime implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleEndSlowTimePacket(message)); + } + + return null; + } + + public static class Message implements IMessage { + + public int hostID; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){ + } + + public Message(Entity host){ + this.hostID = host.getEntityId(); + } + + @Override + public void fromBytes(ByteBuf buf){ + this.hostID = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(hostID); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketGlyphData.java b/src/main/java/electroblob/wizardry/packet/PacketGlyphData.java index 883794d1..23e4b7c3 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketGlyphData.java +++ b/src/main/java/electroblob/wizardry/packet/PacketGlyphData.java @@ -1,8 +1,5 @@ package electroblob.wizardry.packet; -import java.util.ArrayList; -import java.util.List; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.packet.PacketGlyphData.Message; import io.netty.buffer.ByteBuf; @@ -11,6 +8,9 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import java.util.ArrayList; +import java.util.List; + /** * [Server -> Client] This packet is sent each time a player joins a world to synchronise the client-side spell * glyph names with the server-side ones. @@ -23,12 +23,7 @@ public class PacketGlyphData implements IMessageHandler { if(ctx.side.isClient()){ // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy // methods any more than necessary. - net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ - @Override - public void run(){ - Wizardry.proxy.handleGlyphDataPacket(message); - } - }); + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleGlyphDataPacket(message)); } return null; @@ -52,8 +47,8 @@ public class PacketGlyphData implements IMessageHandler { @Override public void fromBytes(ByteBuf buf){ - names = new ArrayList(); - descriptions = new ArrayList(); + names = new ArrayList<>(); + descriptions = new ArrayList<>(); while(buf.isReadable()){ names.add(ByteBufUtils.readUTF8String(buf)); descriptions.add(ByteBufUtils.readUTF8String(buf)); diff --git a/src/main/java/electroblob/wizardry/packet/PacketNPCCastSpell.java b/src/main/java/electroblob/wizardry/packet/PacketNPCCastSpell.java index 4151d9a3..a25b308d 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketNPCCastSpell.java +++ b/src/main/java/electroblob/wizardry/packet/PacketNPCCastSpell.java @@ -3,6 +3,7 @@ package electroblob.wizardry.packet; import electroblob.wizardry.Wizardry; import electroblob.wizardry.entity.living.ISpellCaster; import electroblob.wizardry.packet.PacketNPCCastSpell.Message; +import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.SpellModifiers; import io.netty.buffer.ByteBuf; import net.minecraft.util.EnumHand; @@ -52,10 +53,10 @@ public class PacketNPCCastSpell implements IMessageHandler { public Message(){ } - public Message(int casterID, int targetID, EnumHand hand, int spellID, SpellModifiers modifiers){ + public Message(int casterID, int targetID, EnumHand hand, Spell spell, SpellModifiers modifiers){ this.casterID = casterID; this.targetID = targetID; - this.spellID = spellID; + this.spellID = spell.networkID(); this.modifiers = modifiers; this.hand = hand == null ? EnumHand.MAIN_HAND : hand; } diff --git a/src/main/java/electroblob/wizardry/packet/PacketPlayerSync.java b/src/main/java/electroblob/wizardry/packet/PacketPlayerSync.java index 879db01e..6fca18bc 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketPlayerSync.java +++ b/src/main/java/electroblob/wizardry/packet/PacketPlayerSync.java @@ -1,9 +1,8 @@ package electroblob.wizardry.packet; -import java.util.HashSet; -import java.util.Set; - import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.IVariable; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.packet.PacketPlayerSync.Message; import electroblob.wizardry.spell.Spell; import io.netty.buffer.ByteBuf; @@ -11,9 +10,11 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import java.util.*; + /** * [Server -> Client] This packet is sent to synchronise any fields that need synchronising in - * {@link electroblob.wizardry.WizardData WizardData}. This packet is not sent often enough and is too small to warrant + * {@link WizardData WizardData}. This packet is not sent often enough and is too small to warrant * having separate packets for each field that needs synchronising. */ public class PacketPlayerSync implements IMessageHandler { @@ -24,12 +25,7 @@ public class PacketPlayerSync implements IMessageHandler { if(ctx.side.isClient()){ // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy // methods any more than necessary. - net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ - @Override - public void run(){ - Wizardry.proxy.handlePlayerSyncPacket(message); - } - }); + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handlePlayerSyncPacket(message)); } return null; @@ -37,36 +33,51 @@ public class PacketPlayerSync implements IMessageHandler { public static class Message implements IMessage { + public long seed; public Set spellsDiscovered; public int selectedMinionID; + public Map spellData; // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) public Message(){ } - public Message(Set spellsDiscovered2, int selectedMinionID){ - this.spellsDiscovered = spellsDiscovered2; + public Message(long seed, Set spellsDiscovered, int selectedMinionID, Map spellData){ + this.seed = seed; + this.spellsDiscovered = spellsDiscovered; this.selectedMinionID = selectedMinionID; + this.spellData = spellData; } @Override public void fromBytes(ByteBuf buf){ + + this.seed = buf.readLong(); this.selectedMinionID = buf.readInt(); - this.spellsDiscovered = new HashSet(); + + this.spellData = new HashMap<>(); + WizardData.getSyncedVariables().forEach(v -> spellData.put(v, v.read(buf))); + // Have to send empty tags to guarantee correct ByteBuf size/order, but no point keeping the resulting nulls + spellData.values().removeIf(Objects::isNull); + + this.spellsDiscovered = new HashSet<>(); while(buf.isReadable()){ - this.spellsDiscovered.add(Spell.get(buf.readInt())); + this.spellsDiscovered.add(Spell.byNetworkID(buf.readInt())); } } @Override + @SuppressWarnings("unchecked") // We know it's ok public void toBytes(ByteBuf buf){ + buf.writeLong(seed); buf.writeInt(selectedMinionID); - if(this.spellsDiscovered == null) return; + WizardData.getSyncedVariables().forEach(v -> v.write(buf, spellData.get(v))); + if(this.spellsDiscovered == null) return; for(Spell spell : this.spellsDiscovered){ - buf.writeInt(spell.id()); + buf.writeInt(spell.networkID()); } } } diff --git a/src/main/java/electroblob/wizardry/packet/PacketPossession.java b/src/main/java/electroblob/wizardry/packet/PacketPossession.java new file mode 100644 index 00000000..34c5e3e3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketPossession.java @@ -0,0 +1,58 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import javax.annotation.Nullable; + +/** [Server -> Client] This packet is sent when a player possesses an entity or when a player stops possessing + * to update all clients. */ +public class PacketPossession implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handlePossessionPacket(message)); + } + + return null; + } + + public static class Message implements IMessage { + + public int playerID; + public int targetID; + public int duration; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){ + } + + public Message(EntityPlayer host, @Nullable EntityLiving target, int duration){ + this.playerID = host.getEntityId(); + this.targetID = target == null ? -1 : target.getEntityId(); + this.duration = duration; + } + + @Override + public void fromBytes(ByteBuf buf){ + this.playerID = buf.readInt(); + this.targetID = buf.readInt(); + this.duration = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(playerID); + buf.writeInt(targetID); + buf.writeInt(duration); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketRequestAdvancementSync.java b/src/main/java/electroblob/wizardry/packet/PacketRequestAdvancementSync.java new file mode 100644 index 00000000..a4d7fc9c --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketRequestAdvancementSync.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.packet; + +import io.netty.buffer.ByteBuf; +import net.minecraft.advancements.Advancement; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import java.util.ArrayList; + +/** [Client -> Server] Fired on resource reload to request that the server re-sync the player's advancements. */ +public class PacketRequestAdvancementSync implements IMessageHandler { + + @Override + public PacketSyncAdvancements.Message onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isServer()){ + + final EntityPlayerMP player = ctx.getServerHandler().player; + + ArrayList advancements = new ArrayList<>(); + + for(Advancement advancement : player.getServer().getAdvancementManager().getAdvancements()){ + if(player.getAdvancements().getProgress(advancement).isDone()) advancements.add(advancement.getId()); + } + + return new PacketSyncAdvancements.Message(false, advancements.toArray(new ResourceLocation[0])); + } + + return null; + } + + + public static class Message implements IMessage { + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + // Don't need to put anything in here! + + @Override + public void fromBytes(ByteBuf buf){} + + @Override + public void toBytes(ByteBuf buf){} + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketResurrection.java b/src/main/java/electroblob/wizardry/packet/PacketResurrection.java new file mode 100644 index 00000000..5526489e --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketResurrection.java @@ -0,0 +1,47 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** + * [Server -> Client] This packet is sent to clients in the same dimension when a player is resurrected. + */ +public class PacketResurrection implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleResurrectionPacket(message)); + } + + return null; + } + + public static class Message implements IMessage { + + public int playerID; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){} + + public Message(int playerID){ + this.playerID = playerID; + } + + @Override + public void fromBytes(ByteBuf buf){ + this.playerID = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(playerID); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketSpellProperties.java b/src/main/java/electroblob/wizardry/packet/PacketSpellProperties.java new file mode 100644 index 00000000..acacde6a --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketSpellProperties.java @@ -0,0 +1,64 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.SpellProperties; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import java.util.ArrayList; +import java.util.List; + +/** [Server -> Client] This packet is sent to sync server-side spell properties with clients on login. */ +public class PacketSpellProperties implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isServer()){ + + final EntityPlayerMP player = ctx.getServerHandler().player; + + player.getServerWorld().addScheduledTask(() -> { + for(int i=0; i propertiesList = new ArrayList<>(); + int i = 0; + + while(buf.isReadable()){ + propertiesList.add(new SpellProperties(Spell.byNetworkID(i++), buf)); + } + + propertiesArray = propertiesList.toArray(new SpellProperties[0]); + } + + @Override + public void toBytes(ByteBuf buf){ + for(SpellProperties properties : propertiesArray) properties.write(buf); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketSyncAdvancements.java b/src/main/java/electroblob/wizardry/packet/PacketSyncAdvancements.java new file mode 100644 index 00000000..f5fc1d78 --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketSyncAdvancements.java @@ -0,0 +1,61 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.Wizardry; +import io.netty.buffer.ByteBuf; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.network.ByteBufUtils; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import java.util.ArrayList; + +/** [Server -> Client] This packet is fired on login and on advancement gain to update the handbook progress. */ +public class PacketSyncAdvancements implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isClient()){ + // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy + // methods any more than necessary. + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleAdvancementSyncPacket(message)); + } + + return null; + } + + public static class Message implements IMessage { + + public boolean showToasts; + public ResourceLocation[] completedAdvancements; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){ + } + + public Message(boolean showToasts, ResourceLocation... completed){ + this.showToasts = showToasts; + this.completedAdvancements = completed; + } + + @Override + public void fromBytes(ByteBuf buf){ + showToasts = buf.readBoolean(); + ArrayList advancements = new ArrayList<>(); + while(buf.isReadable()){ + advancements.add(new ResourceLocation(ByteBufUtils.readUTF8String(buf))); + } + this.completedAdvancements = advancements.toArray(new ResourceLocation[0]); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeBoolean(showToasts); + for(ResourceLocation advancement : completedAdvancements){ + ByteBufUtils.writeUTF8String(buf, advancement.toString()); + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java b/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java index c8afb156..9fc16ac5 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java +++ b/src/main/java/electroblob/wizardry/packet/PacketSyncSettings.java @@ -21,13 +21,7 @@ public class PacketSyncSettings implements IMessageHandler { if(ctx.side.isClient()){ // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy // any more than necessary. - net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ - @Override - public void run(){ - copySettings(message); - } - }); - + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> copySettings(message)); } return null; @@ -35,16 +29,14 @@ public class PacketSyncSettings implements IMessageHandler { private static void copySettings(Message message){ Wizardry.settings.discoveryMode = message.settings.discoveryMode; - // Wizardry.settings.maxSpellCommandMultiplier = message.settings.maxSpellCommandMultiplier; - // Wizardry.settings.castCommandName = message.settings.castCommandName; - // Wizardry.settings.discoverspellCommandName = message.settings.discoverspellCommandName; - // Wizardry.settings.allyCommandName = message.settings.allyCommandName; - // Wizardry.settings.alliesCommandName = message.settings.alliesCommandName; + Wizardry.settings.creativeBypassesArcaneLock = message.settings.creativeBypassesArcaneLock; + Wizardry.settings.slowTimeAffectsPlayers = message.settings.slowTimeAffectsPlayers; + Wizardry.settings.forfeitChance = message.settings.forfeitChance; } public static class Message implements IMessage { - /** EntityID of the caster */ + /** Instance of wizardry's settings object */ public Settings settings; // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) @@ -62,21 +54,17 @@ public class PacketSyncSettings implements IMessageHandler { settings = new Settings(); // The order is important settings.discoveryMode = buf.readBoolean(); - // settings.maxSpellCommandMultiplier = buf.readDouble(); - // settings.castCommandName = ByteBufUtils.readUTF8String(buf); - // settings.discoverspellCommandName = ByteBufUtils.readUTF8String(buf); - // settings.allyCommandName = ByteBufUtils.readUTF8String(buf); - // settings.alliesCommandName = ByteBufUtils.readUTF8String(buf); + settings.creativeBypassesArcaneLock = buf.readBoolean(); + settings.slowTimeAffectsPlayers = buf.readBoolean(); + settings.forfeitChance = buf.readFloat(); } @Override public void toBytes(ByteBuf buf){ buf.writeBoolean(settings.discoveryMode); - // buf.writeDouble(settings.maxSpellCommandMultiplier); - // ByteBufUtils.writeUTF8String(buf, settings.castCommandName); - // ByteBufUtils.writeUTF8String(buf, settings.discoverspellCommandName); - // ByteBufUtils.writeUTF8String(buf, settings.allyCommandName); - // ByteBufUtils.writeUTF8String(buf, settings.alliesCommandName); + buf.writeBoolean(settings.creativeBypassesArcaneLock); + buf.writeBoolean(settings.slowTimeAffectsPlayers); + buf.writeFloat((float)settings.forfeitChance); // Configs don't have floats but this can only be 0-1 anyway } } } diff --git a/src/main/java/electroblob/wizardry/packet/PacketTransportation.java b/src/main/java/electroblob/wizardry/packet/PacketTransportation.java index 8f6e5a0e..afb07f7d 100644 --- a/src/main/java/electroblob/wizardry/packet/PacketTransportation.java +++ b/src/main/java/electroblob/wizardry/packet/PacketTransportation.java @@ -19,12 +19,7 @@ public class PacketTransportation implements IMessageHandler if(ctx.side.isClient()){ // Using a fully qualified name is a good course of action here; we don't really want to clutter the proxy // methods any more than necessary. - net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(new Runnable(){ - @Override - public void run(){ - Wizardry.proxy.handleTransportationPacket(message); - } - }); + net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleTransportationPacket(message)); } return null; diff --git a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java index ed40e136..41d12d0d 100644 --- a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java +++ b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java @@ -22,6 +22,16 @@ public class WizardryPacketHandler { registerMessage(PacketClairvoyance.class, PacketClairvoyance.Message.class); registerMessage(PacketSyncSettings.class, PacketSyncSettings.Message.class); registerMessage(PacketNPCCastSpell.class, PacketNPCCastSpell.Message.class); + registerMessage(PacketDispenserCastSpell.class, PacketDispenserCastSpell.Message.class); + registerMessage(PacketSpellProperties.class, PacketSpellProperties.Message.class); + registerMessage(PacketSyncAdvancements.class, PacketSyncAdvancements.Message.class); + registerMessage(PacketRequestAdvancementSync.class, PacketRequestAdvancementSync.Message.class); + registerMessage(PacketEndSlowTime.class, PacketEndSlowTime.Message.class); + registerMessage(PacketResurrection.class, PacketResurrection.Message.class); + registerMessage(PacketCastSpellAtPos.class, PacketCastSpellAtPos.Message.class); + registerMessage(PacketEmitterData.class, PacketEmitterData.Message.class); + registerMessage(PacketPossession.class, PacketPossession.Message.class); + registerMessage(PacketConquerShrine.class, PacketConquerShrine.Message.class); } private static int nextPacketId = 0; diff --git a/src/main/java/electroblob/wizardry/potion/Curse.java b/src/main/java/electroblob/wizardry/potion/Curse.java new file mode 100644 index 00000000..09b9e8ab --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/Curse.java @@ -0,0 +1,70 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.util.ArrayList; +import java.util.List; + +/** A curse is a permanent potion effect, which is displayed in the inventory with a special background and + * no timer. It also allows for longer potion effect names by wrapping them onto two lines. */ +public class Curse extends PotionMagicEffect { + + private static final ResourceLocation BACKGROUND = new ResourceLocation(Wizardry.MODID, "textures/gui/curse_background.png"); + + public Curse(boolean isBadEffect, int liquidColour, ResourceLocation texture){ + super(isBadEffect, liquidColour, texture); + } + + @Override + public boolean shouldRenderInvText(PotionEffect effect){ + return false; + } + + @Override + public List getCurativeItems(){ + return new ArrayList<>(); // Cannot be cured! + } + + @Override + @SideOnly(Side.CLIENT) + public void renderInventoryEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc){ + + mc.renderEngine.bindTexture(BACKGROUND); + electroblob.wizardry.client.DrawingUtils.drawTexturedRect(x, y, 0, 0, 140, 32, 256, 256); + + super.renderInventoryEffect(x, y, effect, mc); + + String name = net.minecraft.client.resources.I18n.format(this.getName()); + + // Amplifier 0 (which would be I) is not rendered and the tooltips only go up to X (amplifier 9) + // The vanilla implementation uses elseifs and only goes up to 4... how lazy. + if(effect.getAmplifier() > 0 && effect.getAmplifier() < 10){ + name = name + " " + net.minecraft.client.resources.I18n.format("enchantment.level." + (effect.getAmplifier() + 1)); + } + + List lines = mc.fontRenderer.listFormattedStringToWidth(name, 100); + + int i=0; + for(String line : lines){ + int h = lines.size() == 1 ? 5 : i * (mc.fontRenderer.FONT_HEIGHT + 1); + mc.fontRenderer.drawStringWithShadow(line, (float)(x + 10 + 18), (float)(y + 6 + h), 0xbf00ee); + i++; + } + } + + @Override + @SideOnly(Side.CLIENT) + public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha){ + + net.minecraft.client.renderer.GlStateManager.color(1, 1, 1, 1); + mc.renderEngine.bindTexture(BACKGROUND); + electroblob.wizardry.client.DrawingUtils.drawTexturedRect(x, y, 141, 0, 24, 24, 256, 256); + super.renderHUDEffect(x, y, effect, mc, alpha); + } + +} diff --git a/src/main/java/electroblob/wizardry/potion/CurseEnfeeblement.java b/src/main/java/electroblob/wizardry/potion/CurseEnfeeblement.java new file mode 100644 index 00000000..69daa132 --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/CurseEnfeeblement.java @@ -0,0 +1,49 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.util.FoodStats; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.lang.reflect.Field; + +@Mod.EventBusSubscriber +public class CurseEnfeeblement extends Curse { + + // Yay more reflection + private static final Field foodTimer; + + static { + foodTimer = ObfuscationReflectionHelper.findField(FoodStats.class, "field_75123_d"); + foodTimer.setAccessible(true); + } + + public CurseEnfeeblement(boolean isBadEffect, int liquiidColour){ + super(isBadEffect, liquiidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_curse_of_enfeeblement.png")); + // This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet. + this.setPotionName("potion." + Wizardry.MODID + ":curse_of_enfeeblement"); + this.registerPotionAttributeModifier(SharedMonsterAttributes.MAX_HEALTH, + "2e8c378e-3d51-4ba1-b02c-591b5d968a05", -0.2, 1); + } + + @SubscribeEvent + public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){ + // Players are the only entities with natural regeneration + // This can't be done in performEffect as that method only gets called every 20 ticks or so + // Don't bother trying to prevent it unless the player is full enough + if(event.player.isPotionActive(WizardryPotions.curse_of_enfeeblement) && event.player.getFoodStats().getFoodLevel() > 17){ + try{ + // Constantly setting this to zero prevents natural regeneration + foodTimer.set(event.player.getFoodStats(), 0); + }catch(IllegalAccessException e){ + Wizardry.logger.error("Error setting player food timer: ", e); + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/potion/CurseUndeath.java b/src/main/java/electroblob/wizardry/potion/CurseUndeath.java new file mode 100644 index 00000000..6f2d0a9f --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/CurseUndeath.java @@ -0,0 +1,58 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; + +public class CurseUndeath extends Curse { + + public CurseUndeath(boolean isBadEffect, int liquiidColour){ + super(isBadEffect, liquiidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_curse_of_undeath.png")); + // This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet. + this.setPotionName("potion." + Wizardry.MODID + ":curse_of_undeath"); + } + + @Override + public boolean isReady(int duration, int amplifier){ + return true; + } + + @Override + public void performEffect(EntityLivingBase entitylivingbase, int strength){ + + // Adapted from EntityZombie + if(entitylivingbase.world.isDaytime() && !entitylivingbase.world.isRemote){ + + float f = entitylivingbase.getBrightness(); + + if(f > 0.5F && entitylivingbase.world.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F + && entitylivingbase.world.canSeeSky(new BlockPos(entitylivingbase.posX, + entitylivingbase.posY + (double)entitylivingbase.getEyeHeight(), entitylivingbase.posZ))){ + + boolean flag = true; + ItemStack itemstack = entitylivingbase.getItemStackFromSlot(EntityEquipmentSlot.HEAD); + + if(!itemstack.isEmpty()){ + if(itemstack.isItemStackDamageable()){ + + itemstack.setItemDamage(itemstack.getItemDamage() + entitylivingbase.world.rand.nextInt(2)); + + if(itemstack.getItemDamage() >= itemstack.getMaxDamage()){ + entitylivingbase.renderBrokenItemStack(itemstack); + entitylivingbase.setItemStackToSlot(EntityEquipmentSlot.HEAD, ItemStack.EMPTY); + } + } + + flag = false; + } + + if(flag){ + entitylivingbase.setFire(8); + } + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java b/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java index c1c565ff..ab0ec6e0 100644 --- a/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java +++ b/src/main/java/electroblob/wizardry/potion/ICustomPotionParticles.java @@ -1,7 +1,6 @@ package electroblob.wizardry.potion; -import java.util.stream.Collectors; - +import net.minecraft.entity.EntityLivingBase; import net.minecraft.potion.PotionEffect; import net.minecraft.potion.PotionUtils; import net.minecraft.world.World; @@ -10,16 +9,23 @@ import net.minecraftforge.event.entity.living.PotionColorCalculationEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.util.stream.Collectors; + /** - * Interface for potion effects that spawn custom particles instead of (or as well as) the vanilla 'swirly' particles. - * To hide the vanilla 'swirly' particles, set the potion's liquid colour to 0 (black). By default, potions that implement - * this interface no longer mix their colour with other potions. + * Interface for potion effects that spawn custom particles instead of (or as well as) the vanilla 'swirly' particles.
    + *
    + * To hide the vanilla 'swirly' particles, set the potion's liquid colour to 0 (black). By default, potions that + * implement this interface do not mix their colour with other potions.
    + *
    + * Potions that implement this interface also implement {@link ISyncedPotion} since any custom particles require syncing + * to disappear correctly when the effect ends; if syncing is not required, override + * {@link ISyncedPotion#shouldSync(EntityLivingBase)} to return false. * * @author Electroblob * @since Wizardry 1.2 */ @Mod.EventBusSubscriber -public interface ICustomPotionParticles { +public interface ICustomPotionParticles extends ISyncedPotion { /** * Called from the event handler to spawn a single custom potion particle. To get an instance of @@ -65,4 +71,5 @@ public interface ICustomPotionParticles { p -> !(p instanceof ICustomPotionParticles && !((ICustomPotionParticles)p).shouldMixColour())) .collect(Collectors.toList()))); } + } diff --git a/src/main/java/electroblob/wizardry/potion/ISyncedPotion.java b/src/main/java/electroblob/wizardry/potion/ISyncedPotion.java new file mode 100644 index 00000000..76741001 --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/ISyncedPotion.java @@ -0,0 +1,81 @@ +package electroblob.wizardry.potion; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.play.server.SPacketEntityEffect; +import net.minecraft.network.play.server.SPacketRemoveEntityEffect; +import net.minecraftforge.event.entity.living.PotionEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +/** + * Interface for potion effects that need syncing to ensure client and server side are consistent. Simply implement + * this interface and the potion will be synced automatically. + * + * @author Electroblob + * @since Wizardry 1.2 + */ +@Mod.EventBusSubscriber +public interface ISyncedPotion { + + /** The distance from an entity with this effect within which players will receive potion update packets. */ + double SYNC_RADIUS = 64; + + /** Returns true if this potion should sync with nearby clients when added to / removed from an entity and on + * expiry, false if not. The host entity is provided in case syncing is entity-dependent. Defaults to true. */ + default boolean shouldSync(EntityLivingBase host){ + return true; + } + + // The following event handlers fix the inconsistencies caused by clients not syncing correctly + // These packets are only sent for players with potion effects in vanilla, and only to that player's client + + // This one is only actually necessary if the effect gets added via a server-side method e.g. commands + // Unfortunately there's no way of checking that, so we'll just have to live with the extra packets + @SubscribeEvent + public static void onPotionAddedEvent(PotionEvent.PotionAddedEvent event){ + + if(event.getPotionEffect().getPotion() instanceof ISyncedPotion + && ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){ + + if(!event.getEntityLiving().world.isRemote){ + event.getEntityLiving().world.playerEntities.stream() + .filter(p -> p.getDistanceSq(event.getEntityLiving()) < SYNC_RADIUS * SYNC_RADIUS) + // Apparently unchecked casting in a lambda expression doesn't generate a warning. Who knew? + // (We know this cast is safe though) + .forEach(p -> ((EntityPlayerMP)p).connection.sendPacket(new SPacketEntityEffect( + event.getEntity().getEntityId(), event.getPotionEffect()))); + } + } + } + + @SubscribeEvent + public static void onPotionExpiryEvent(PotionEvent.PotionExpiryEvent event){ + + if(event.getPotionEffect().getPotion() instanceof ISyncedPotion + && ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){ + + if(!event.getEntityLiving().world.isRemote){ + event.getEntityLiving().world.playerEntities.stream() + .filter(p -> p.getDistanceSq(event.getEntityLiving()) < SYNC_RADIUS * SYNC_RADIUS) + .forEach(p -> ((EntityPlayerMP)p).connection.sendPacket(new SPacketRemoveEntityEffect( + event.getEntity().getEntityId(), event.getPotionEffect().getPotion()))); + } + } + } + + @SubscribeEvent + public static void onPotionRemoveEvent(PotionEvent.PotionRemoveEvent event){ + + if(event.getPotionEffect().getPotion() instanceof ISyncedPotion + && ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){ + + if(!event.getEntityLiving().world.isRemote){ + event.getEntityLiving().world.playerEntities.stream() + .filter(p -> p.getDistanceSq(event.getEntityLiving()) < SYNC_RADIUS * SYNC_RADIUS) + .forEach(p -> ((EntityPlayerMP)p).connection.sendPacket(new SPacketRemoveEntityEffect( + event.getEntity().getEntityId(), event.getPotionEffect().getPotion()))); + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/potion/PotionContainment.java b/src/main/java/electroblob/wizardry/potion/PotionContainment.java new file mode 100644 index 00000000..672d6ba6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/PotionContainment.java @@ -0,0 +1,121 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +@Mod.EventBusSubscriber +public class PotionContainment extends PotionMagicEffect { + + public static final String ENTITY_TAG = "containmentPos"; + + public PotionContainment(boolean isBadEffect, int liquidColour){ + super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_containment.png")); + this.setPotionName("potion." + Wizardry.MODID + ":containment"); + } + + @Override + public boolean isReady(int duration, int amplifier){ + return true; // Execute the effect every tick + } + + public static float getContainmentDistance(int effectStrength){ + return 15 - effectStrength * 4; + } + + @Override + public void performEffect(EntityLivingBase target, int strength){ + + float maxDistance = getContainmentDistance(strength); + + // Initialise the containment position to the entity's position if it wasn't set already + if(!target.getEntityData().hasKey(ENTITY_TAG)){ + target.getEntityData().setTag(ENTITY_TAG, NBTUtil.createPosTag(new BlockPos(target.getPositionVector().subtract(0.5, 0.5, 0.5)))); + } + + Vec3d origin = WizardryUtilities.getCentre(NBTUtil.getPosFromTag(target.getEntityData().getCompoundTag(ENTITY_TAG))); + + double x = target.posX, y = target.posY, z = target.posZ; + + // Containment fields are cubes so we're dealing with each axis separately + if(target.getEntityBoundingBox().maxX > origin.x + maxDistance) x = origin.x + maxDistance - target.width/2; + if(target.getEntityBoundingBox().minX < origin.x - maxDistance) x = origin.x - maxDistance + target.width/2; + + if(target.getEntityBoundingBox().maxY > origin.y + maxDistance) y = origin.y + maxDistance - target.height; + if(target.getEntityBoundingBox().minY < origin.y - maxDistance) y = origin.y - maxDistance; + + if(target.getEntityBoundingBox().maxZ > origin.z + maxDistance) z = origin.z + maxDistance - target.width/2; + if(target.getEntityBoundingBox().minZ < origin.z - maxDistance) z = origin.z - maxDistance + target.width/2; + + if(x != target.posX || y != target.posY || z != target.posZ){ + +// if(target.world.isRemote){ +// +// if(x != target.posX){ +// for(int i = 0; i < 20; i++){ +// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos( +// x, +// target.getEntityBoundingBox().minY + target.height * target.world.rand.nextFloat(), +// target.posZ + target.width * (target.world.rand.nextFloat() - 0.5f)) +// .face(EnumFacing.EAST).clr(0.8f, 0.9f, 1).spawn(target.world); +// } +// } +// +// if(y != target.posY){ +// for(int i = 0; i < 20; i++){ +// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos( +// target.posX + target.width * (target.world.rand.nextFloat() - 0.5f), +// y, +// target.posZ + target.width * (target.world.rand.nextFloat() - 0.5f)) +// .face(EnumFacing.UP).clr(0.8f, 0.9f, 1).spawn(target.world); +// } +// } +// +// if(z != target.posZ){ +// for(int i = 0; i < 20; i++){ +// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos( +// target.posX + target.width * (target.world.rand.nextFloat() - 0.5f), +// target.getEntityBoundingBox().minY + target.height * target.world.rand.nextFloat(), +// z) +// .face(EnumFacing.SOUTH).clr(0.8f, 0.9f, 1).spawn(target.world); +// } +// } +// } + + WizardryUtilities.undoGravity(target); + target.addVelocity(0.35 * Math.signum(x - target.posX), 0.35 * Math.signum(y - target.posY), 0.35 * Math.signum(z - target.posZ)); + target.setPositionAndUpdate(x, y, z); + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } +// +// target.world.playSound(target.posX, target.posY, target.posZ, WizardrySounds.ENTITY_FORCEFIELD_DEFLECT, +// WizardrySounds.SPELLS, 0.3f, 1f, false); + + } + + // Need to do this here because it's the only way to hook into potion ending both client- and server-side + if(target.getActivePotionEffect(this).getDuration() <= 1) target.getEntityData().removeTag(ENTITY_TAG); + + } + + @SubscribeEvent + public static void onLivingUpdateEvent(LivingUpdateEvent event){ + if(event.getEntityLiving().getEntityData().hasKey(ENTITY_TAG) + && !event.getEntityLiving().isPotionActive(WizardryPotions.containment)){ + event.getEntityLiving().getEntityData().removeTag(ENTITY_TAG); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/potion/PotionDecay.java b/src/main/java/electroblob/wizardry/potion/PotionDecay.java index 025c9e16..c4562d3c 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionDecay.java +++ b/src/main/java/electroblob/wizardry/potion/PotionDecay.java @@ -1,24 +1,19 @@ package electroblob.wizardry.potion; -import java.util.List; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.entity.construct.EntityDecay; import electroblob.wizardry.registry.WizardryPotions; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.potion.Potion; -import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; 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; + +import java.util.List; @Mod.EventBusSubscriber public class PotionDecay extends PotionMagicEffect { @@ -40,8 +35,8 @@ public class PotionDecay extends PotionMagicEffect { } @Override - public void performEffect(EntityLivingBase target, int strength){ - target.attackEntityFrom(DamageSource.WITHER, 1); + public void performEffect(EntityLivingBase host, int strength){ + host.attackEntityFrom(DamageSource.WITHER, 1); } @SubscribeEvent diff --git a/src/main/java/electroblob/wizardry/potion/PotionFrost.java b/src/main/java/electroblob/wizardry/potion/PotionFrost.java index cba91fd6..28b89553 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionFrost.java +++ b/src/main/java/electroblob/wizardry/potion/PotionFrost.java @@ -1,21 +1,16 @@ package electroblob.wizardry.potion; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.constants.Constants; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.potion.PotionEffect; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.event.entity.player.PlayerEvent.BreakSpeed; 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; @Mod.EventBusSubscriber public class PotionFrost extends PotionMagicEffect implements ICustomPotionParticles { diff --git a/src/main/java/electroblob/wizardry/potion/PotionFrostStep.java b/src/main/java/electroblob/wizardry/potion/PotionFrostStep.java new file mode 100644 index 00000000..4c369526 --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/PotionFrostStep.java @@ -0,0 +1,116 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import net.minecraft.block.BlockLiquid; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.enchantment.EnchantmentFrostWalker; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.lang.reflect.Field; + +@Mod.EventBusSubscriber +public class PotionFrostStep extends PotionMagicEffect implements ICustomPotionParticles { + + private static final Field prevBlockPos = ObfuscationReflectionHelper.findField(EntityLivingBase.class, "field_184620_bC"); + + public PotionFrostStep(boolean isBadEffect, int liquidColour){ + super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_frost_step.png")); + this.setPotionName("potion." + Wizardry.MODID + ":frost_step"); + } + +// @Override +// public boolean isReady(int duration, int amplifier){ +// return true; // Execute the effect every tick +// } + + @Override + public void spawnCustomParticle(World world, double x, double y, double z){ + ParticleBuilder.create(Type.SNOW).pos(x, y, z).time(15 + world.rand.nextInt(5)).spawn(world); + } + + // Use LivingUpdateEvent instead of performEffect because it gets called before the actual frost walker processing + // performEffect is called afterwards, at which point prevBlockPos has already been set to the current position + // regardless of whether the player is wearing frost walker boots or not + + @SubscribeEvent + public static void onLivingUpdateEvent(LivingUpdateEvent event){ + + EntityLivingBase host = event.getEntityLiving(); + + if(host.isPotionActive(WizardryPotions.frost_step)){ + // Mimics the behaviour of the frost walker enchantment itself + if(!host.world.isRemote){ + + BlockPos currentPos = new BlockPos(host); + + try{ + + if(!currentPos.equals(prevBlockPos.get(host))){ + + prevBlockPos.set(host, currentPos); + + int strength = host.getActivePotionEffect(WizardryPotions.frost_step).getAmplifier(); + + EnchantmentFrostWalker.freezeNearby(host, host.world, currentPos, strength); + + if(host instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)host, WizardryItems.charm_lava_walking)){ + freezeNearbyLava(host, host.world, currentPos, strength); + } + } + + }catch(IllegalAccessException e){ + Wizardry.logger.error("Error accessing living entity previous block pos:", e); + } + } + } + } + + /** Copied from {@link EnchantmentFrostWalker#freezeNearby(EntityLivingBase, World, BlockPos, int)} and modified + * to turn lava to obsidian crust blocks instead. */ + private static void freezeNearbyLava(EntityLivingBase living, World world, BlockPos pos, int level){ + + if(living.onGround){ + + float f = (float)Math.min(16, 2 + level); + BlockPos.MutableBlockPos pos1 = new BlockPos.MutableBlockPos(0, 0, 0); + + for(BlockPos.MutableBlockPos pos2 : BlockPos.getAllInBoxMutable(pos.add((double)(-f), -1.0D, (double)(-f)), pos.add((double)f, -1.0D, (double)f))){ + + if(pos2.distanceSqToCenter(living.posX, living.posY, living.posZ) <= (double)(f * f)){ + + pos1.setPos(pos2.getX(), pos2.getY() + 1, pos2.getZ()); + IBlockState state1 = world.getBlockState(pos1); + + if(state1.getMaterial() == Material.AIR){ + + IBlockState state2 = world.getBlockState(pos2); + + if(state2.getMaterial() == Material.LAVA && (state2.getBlock() == Blocks.LAVA || state2.getBlock() == Blocks.FLOWING_LAVA) && state2.getValue(BlockLiquid.LEVEL) == 0 && world.mayPlace(WizardryBlocks.obsidian_crust, pos2, false, EnumFacing.DOWN, null)){ + world.setBlockState(pos2, WizardryBlocks.obsidian_crust.getDefaultState()); + world.scheduleUpdate(pos2.toImmutable(), WizardryBlocks.obsidian_crust, MathHelper.getInt(living.getRNG(), 60, 120)); + } + } + } + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java b/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java index cf7f5820..72b2f747 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java +++ b/src/main/java/electroblob/wizardry/potion/PotionMagicEffect.java @@ -1,6 +1,5 @@ package electroblob.wizardry.potion; -import electroblob.wizardry.client.DrawingUtils; import net.minecraft.entity.EntityLivingBase; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; @@ -42,7 +41,7 @@ public class PotionMagicEffect extends Potion { @SideOnly(Side.CLIENT) protected void drawIcon(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc){ mc.renderEngine.bindTexture(texture); - DrawingUtils.drawTexturedRect(x, y, 0, 0, 18, 18, 18, 18); + electroblob.wizardry.client.DrawingUtils.drawTexturedRect(x, y, 0, 0, 18, 18, 18, 18); } } diff --git a/src/main/java/electroblob/wizardry/potion/PotionSlowTime.java b/src/main/java/electroblob/wizardry/potion/PotionSlowTime.java new file mode 100644 index 00000000..b6e1f51d --- /dev/null +++ b/src/main/java/electroblob/wizardry/potion/PotionSlowTime.java @@ -0,0 +1,172 @@ +package electroblob.wizardry.potion; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.packet.PacketEndSlowTime; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.spell.SlowTime; +import electroblob.wizardry.spell.Spell; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IProjectile; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.event.entity.living.PotionEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.List; + +@Mod.EventBusSubscriber +public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion { + + // FIXME: Minecarts with entities in them (and, I suspect, any other ridden entities) go crazy when time-slowed + + public PotionSlowTime(boolean isBadEffect, int liquidColour){ + super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_slow_time.png")); + this.setPotionName("potion." + Wizardry.MODID + ":slow_time"); + } + + private static double getEffectRadius(){ + return Spells.slow_time.getProperty(Spell.EFFECT_RADIUS).doubleValue(); + } + + public static void unblockNearbyEntities(EntityLivingBase host){ + List targetsBeyondRange = WizardryUtilities.getEntitiesWithinRadius(getEffectRadius() + 3, host.posX, host.posY, host.posZ, host.world, Entity.class); + targetsBeyondRange.forEach(e -> e.updateBlocked = false); + } + + // Not done in performEffect because it's client-inconsistent; it only fires on the client of the player with the + // potion effect, and doesn't fire on the client at all for non-players + private static void performEffectConsistent(EntityLivingBase host, int strength){ + + boolean stopTime = host instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)host, WizardryItems.charm_stop_time); + + int interval = strength * 4 + 6; + + // Mark all entities within range + List targetsInRange = WizardryUtilities.getEntitiesWithinRadius(getEffectRadius(), host.posX, host.posY, host.posZ, host.world, Entity.class); + targetsInRange.remove(host); + // Other entities with the slow time effect are unaffected + targetsInRange.removeIf(t -> t instanceof EntityLivingBase && ((EntityLivingBase)t).isPotionActive(WizardryPotions.slow_time)); + if(!Wizardry.settings.slowTimeAffectsPlayers) targetsInRange.removeIf(t -> t instanceof EntityPlayer); + targetsInRange.removeIf(t -> t instanceof EntityArrow && t.isEntityInsideOpaqueBlock()); + + for(Entity entity : targetsInRange){ + + // If time is stopped, block all updates; otherwise block all updates except every [interval] ticks + entity.updateBlocked = stopTime || host.ticksExisted % interval != 0; + + if(!stopTime && entity.world.isRemote){ + + // Client-side movement interpolation (smoothing) + + if(entity.onGround) entity.motionY = 0; // Don't ask. It just works. + +// if(entity instanceof EntityLivingBase){ +// ((EntityLivingBase)entity).prevLimbSwingAmount = ((EntityLivingBase)entity).limbSwingAmount; +// ((EntityLivingBase)entity).swingProgress = ((EntityLivingBase)entity).prevSwingProgress; +// ((EntityLivingBase)entity).renderYawOffset = ((EntityLivingBase)entity).prevRenderYawOffset; +// ((EntityLivingBase)entity).rotationYawHead = ((EntityLivingBase)entity).prevRotationYawHead; +// } + + if(entity.updateBlocked){ + // When the update is blocked, the entity is moved 1/interval times the distance it would have moved + double x = entity.posX + entity.motionX * 1d / (double)interval; + double y = entity.posY + entity.motionY * 1d / (double)interval; + double z = entity.posZ + entity.motionZ * 1d / (double)interval; + + entity.prevPosX = entity.posX; + entity.prevPosY = entity.posY; + entity.prevPosZ = entity.posZ; + + entity.posX = x; + entity.posY = y; + entity.posZ = z; + + }else{ + // When the update is not blocked, the entity is moved BACK 1-1/interval times the distance it moved + // This is because the entity already covered most of that distance when its update was blocked + entity.posX += entity.motionX * 1d / (double)interval; + entity.posY += entity.motionY * 1d / (double)interval; + entity.posZ += entity.motionZ * 1d / (double)interval; + + double x = entity.posX - entity.motionX * 1d / (double)interval; + double y = entity.posY - entity.motionY * 1d / (double)interval; + double z = entity.posZ - entity.motionZ * 1d / (double)interval; + + entity.prevPosX = x; + entity.prevPosY = y; + entity.prevPosZ = z; + } + } + + if(entity.world.isRemote && host.ticksExisted % 2 == 0){ + int lifetime = 15; + double dx = (entity.world.rand.nextDouble() - 0.5D) * 2 * (double)entity.width; + double dy = (entity.world.rand.nextDouble() - 0.5D) * 2 * (double)entity.width; + double dz = (entity.world.rand.nextDouble() - 0.5D) * 2 * (double)entity.width; + double x = entity.posX + dx; + double y = entity instanceof IProjectile ? entity.posY + dy : entity.posY + entity.height/2 + dy; + double z = entity.posZ + dz; + ParticleBuilder.create(ParticleBuilder.Type.DUST) + .pos(x, y, z) + .vel(-dx/lifetime, -dy/lifetime, -dz/lifetime) + .clr(0x5be3bb).time(15).spawn(entity.world); + } + } + + // Un-mark all entities that have just left range + List targetsBeyondRange = WizardryUtilities.getEntitiesWithinRadius(getEffectRadius() + 3, host.posX, host.posY, host.posZ, host.world, Entity.class); + targetsBeyondRange.removeAll(targetsInRange); + targetsBeyondRange.forEach(e -> e.updateBlocked = false); + + } + + @SubscribeEvent + public static void onLivingUpdateEvent(LivingUpdateEvent event){ + + EntityLivingBase entity = event.getEntityLiving(); + + if(entity.isPotionActive(WizardryPotions.slow_time)){ + performEffectConsistent(entity, entity.getActivePotionEffect(WizardryPotions.slow_time).getAmplifier()); + } + } + + @SubscribeEvent + public static void onPotionAddedEvent(PotionEvent.PotionAddedEvent event){ + if(event.getEntity().world.isRemote && event.getPotionEffect().getPotion() == WizardryPotions.slow_time + && event.getEntity() == net.minecraft.client.Minecraft.getMinecraft().player){ + if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SlowTime.SHADER); + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); + } + } + + @SubscribeEvent + public static void onPotionExpiryEvent(PotionEvent.PotionExpiryEvent event){ + if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() == WizardryPotions.slow_time){ + unblockNearbyEntities(event.getEntityLiving()); + if(!event.getEntity().world.isRemote){ + WizardryPacketHandler.net.sendToDimension(new PacketEndSlowTime.Message(event.getEntityLiving()), event.getEntity().dimension); + } + } + } + + @SubscribeEvent + public static void onPotionRemoveEvent(PotionEvent.PotionRemoveEvent event){ + if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() == WizardryPotions.slow_time){ + unblockNearbyEntities(event.getEntityLiving()); + if(!event.getEntity().world.isRemote){ + WizardryPacketHandler.net.sendToDimension(new PacketEndSlowTime.Message(event.getEntityLiving()), event.getEntity().dimension); + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/registry/Spells.java b/src/main/java/electroblob/wizardry/registry/Spells.java index eb775f1e..5398da75 100644 --- a/src/main/java/electroblob/wizardry/registry/Spells.java +++ b/src/main/java/electroblob/wizardry/registry/Spells.java @@ -1,49 +1,11 @@ package electroblob.wizardry.registry; -import org.apache.commons.lang3.tuple.Triple; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityBlackHole; -import electroblob.wizardry.entity.construct.EntityBlizzard; -import electroblob.wizardry.entity.construct.EntityFireRing; -import electroblob.wizardry.entity.construct.EntityFireSigil; -import electroblob.wizardry.entity.construct.EntityForcefield; -import electroblob.wizardry.entity.construct.EntityFrostSigil; -import electroblob.wizardry.entity.construct.EntityHealAura; -import electroblob.wizardry.entity.construct.EntityLightningSigil; -import electroblob.wizardry.entity.living.EntityBlazeMinion; -import electroblob.wizardry.entity.living.EntityIceGiant; -import electroblob.wizardry.entity.living.EntityIceWraith; -import electroblob.wizardry.entity.living.EntityLightningWraith; -import electroblob.wizardry.entity.living.EntityPhoenix; -import electroblob.wizardry.entity.living.EntitySilverfishMinion; -import electroblob.wizardry.entity.living.EntitySpiderMinion; -import electroblob.wizardry.entity.living.EntityStormElemental; -import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; -import electroblob.wizardry.entity.living.EntityZombieMinion; -import electroblob.wizardry.entity.projectile.EntityDarknessOrb; -import electroblob.wizardry.entity.projectile.EntityDart; -import electroblob.wizardry.entity.projectile.EntityFirebolt; -import electroblob.wizardry.entity.projectile.EntityFirebomb; -import electroblob.wizardry.entity.projectile.EntityForceArrow; -import electroblob.wizardry.entity.projectile.EntityForceOrb; -import electroblob.wizardry.entity.projectile.EntityIceCharge; -import electroblob.wizardry.entity.projectile.EntityIceLance; -import electroblob.wizardry.entity.projectile.EntityIceShard; -import electroblob.wizardry.entity.projectile.EntityLightningArrow; -import electroblob.wizardry.entity.projectile.EntityLightningDisc; -import electroblob.wizardry.entity.projectile.EntityMagicMissile; -import electroblob.wizardry.entity.projectile.EntityPoisonBomb; -import electroblob.wizardry.entity.projectile.EntitySmokeBomb; -import electroblob.wizardry.entity.projectile.EntitySpark; -import electroblob.wizardry.entity.projectile.EntitySparkBomb; -import electroblob.wizardry.entity.projectile.EntityThunderbolt; +import electroblob.wizardry.entity.construct.*; +import electroblob.wizardry.entity.living.*; +import electroblob.wizardry.entity.projectile.*; import electroblob.wizardry.spell.*; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.RegistryEvent; @@ -53,6 +15,8 @@ import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.RegistryBuilder; +import javax.annotation.Nonnull; + /** * Class responsible for defining, storing and registering all of wizardry's spells. Use this to access individual * spell instances, similar to the {@code Blocks} and {@code Items} classes. @@ -60,23 +24,16 @@ import net.minecraftforge.registries.RegistryBuilder; * @author Electroblob * @since Wizardry 2.1 */ -// In case anyone was wondering, the reason @ObjectHolder is useful within one mod is that it allows you to initialise -// stuff during the registry events (or whenever), whilst still having a final field (which is important, not only -// because it makes the text go bold, but also because it stops anyone fiddling with your fields). "Why would I want to -// initialise things within the registry events?", I hear you ask - well, for one, custom registries don't like it if -// you haven't created the registry before you start calling constructors of classes extending IForgeRegistryEntry.Impl, -// and secondly, you might want to initialise objects based on certain conditions - perhaps a config option, or whether -// another mod is installed. This, presumably, is why everyone at forge is encouraging us to use @ObjectHolder. @ObjectHolder(Wizardry.MODID) @Mod.EventBusSubscriber public final class Spells { + private Spells(){} // No instances! + // This is here because this class is already an event handler. @SubscribeEvent public static void createRegistry(RegistryEvent.NewRegistry event){ - // Beats me why we need both of these. Surely the type parameter means it already knows? - // EDIT: It's probably because of type erasure, thinking about it. RegistryBuilder builder = new RegistryBuilder<>(); builder.setType(Spell.class); builder.setName(new ResourceLocation(Wizardry.MODID, "spells")); @@ -85,158 +42,200 @@ public final class Spells { Spell.registry = builder.create(); } + @Nonnull + @SuppressWarnings("ConstantConditions") + private static T placeholder(){ return null; } + // Wizardry 1.0 spells - public static final Spell none = null; - public static final Spell magic_missile = null; - public static final Spell ignite = null; - public static final Spell freeze = null; - public static final Spell snowball = null; - public static final Spell arc = null; - public static final Spell thunderbolt = null; - public static final Spell summon_zombie = null; - public static final Spell snare = null; - public static final Spell dart = null; - public static final Spell light = null; - public static final Spell telekinesis = null; - public static final Spell heal = null; + public static final Spell none = placeholder(); + public static final Spell magic_missile = placeholder(); + public static final Spell ignite = placeholder(); + public static final Spell freeze = placeholder(); + public static final Spell snowball = placeholder(); + public static final Spell arc = placeholder(); + public static final Spell thunderbolt = placeholder(); + public static final Spell summon_zombie = placeholder(); + public static final Spell snare = placeholder(); + public static final Spell dart = placeholder(); + public static final Spell light = placeholder(); + public static final Spell telekinesis = placeholder(); + public static final Spell heal = placeholder(); - public static final Spell fireball = null; - public static final Spell flame_ray = null; - public static final Spell firebomb = null; - public static final Spell fire_sigil = null; - public static final Spell firebolt = null; - public static final Spell frost_ray = null; - public static final Spell summon_snow_golem = null; - public static final Spell ice_shard = null; - public static final Spell ice_statue = null; - public static final Spell frost_sigil = null; - public static final Spell lightning_ray = null; - public static final Spell spark_bomb = null; - public static final Spell homing_spark = null; - public static final Spell lightning_sigil = null; - public static final Spell lightning_arrow = null; - public static final Spell life_drain = null; - public static final Spell summon_skeleton = null; - public static final Spell metamorphosis = null; - public static final Spell wither = null; - public static final Spell poison = null; - public static final Spell growth_aura = null; - public static final Spell bubble = null; - public static final Spell whirlwind = null; - public static final Spell poison_bomb = null; - public static final Spell summon_spirit_wolf = null; - public static final Spell blink = null; - public static final Spell agility = null; - public static final Spell conjure_sword = null; - public static final Spell conjure_pickaxe = null; - public static final Spell conjure_bow = null; - public static final Spell force_arrow = null; - public static final Spell shield = null; - public static final Spell replenish_hunger = null; - public static final Spell cure_effects = null; - public static final Spell heal_ally = null; + public static final Spell fireball = placeholder(); + public static final Spell flame_ray = placeholder(); + public static final Spell firebomb = placeholder(); + public static final Spell fire_sigil = placeholder(); + public static final Spell firebolt = placeholder(); + public static final Spell frost_ray = placeholder(); + public static final Spell summon_snow_golem = placeholder(); + public static final Spell ice_shard = placeholder(); + public static final Spell ice_statue = placeholder(); + public static final Spell frost_sigil = placeholder(); + public static final Spell lightning_ray = placeholder(); + public static final Spell spark_bomb = placeholder(); + public static final Spell homing_spark = placeholder(); + public static final Spell lightning_sigil = placeholder(); + public static final Spell lightning_arrow = placeholder(); + public static final Spell life_drain = placeholder(); + public static final Spell summon_skeleton = placeholder(); + public static final Spell metamorphosis = placeholder(); + public static final Spell wither = placeholder(); + public static final Spell poison = placeholder(); + public static final Spell growth_aura = placeholder(); + public static final Spell bubble = placeholder(); + public static final Spell whirlwind = placeholder(); + public static final Spell poison_bomb = placeholder(); + public static final Spell summon_spirit_wolf = placeholder(); + public static final Spell blink = placeholder(); + public static final Spell agility = placeholder(); + public static final Spell conjure_sword = placeholder(); + public static final Spell conjure_pickaxe = placeholder(); + public static final Spell conjure_bow = placeholder(); + public static final Spell force_arrow = placeholder(); + public static final Spell shield = placeholder(); + public static final Spell replenish_hunger = placeholder(); + public static final Spell cure_effects = placeholder(); + public static final Spell heal_ally = placeholder(); - public static final Spell summon_blaze = null; - public static final Spell ring_of_fire = null; - public static final Spell detonate = null; - public static final Spell fire_resistance = null; - public static final Spell fireskin = null; - public static final Spell flaming_axe = null; - public static final Spell blizzard = null; - public static final Spell summon_ice_wraith = null; - public static final Spell ice_shroud = null; - public static final Spell ice_charge = null; - public static final Spell frost_axe = null; - public static final Spell invoke_weather = null; - public static final Spell chain_lightning = null; - public static final Spell lightning_bolt = null; - public static final Spell summon_lightning_wraith = null; - public static final Spell static_aura = null; - public static final Spell lightning_disc = null; - public static final Spell mind_control = null; - public static final Spell summon_wither_skeleton = null; - public static final Spell entrapment = null; - public static final Spell wither_skull = null; - public static final Spell darkness_orb = null; - public static final Spell shadow_ward = null; - public static final Spell decay = null; - public static final Spell water_breathing = null; - public static final Spell tornado = null; - public static final Spell glide = null; - public static final Spell summon_spirit_horse = null; - public static final Spell spider_swarm = null; - public static final Spell slime = null; - public static final Spell petrify = null; - public static final Spell invisibility = null; - public static final Spell levitation = null; - public static final Spell force_orb = null; - public static final Spell transportation = null; - public static final Spell spectral_pathway = null; - public static final Spell phase_step = null; - public static final Spell vanishing_box = null; - public static final Spell greater_heal = null; - public static final Spell healing_aura = null; - public static final Spell forcefield = null; - public static final Spell ironflesh = null; - public static final Spell transience = null; + public static final Spell summon_blaze = placeholder(); + public static final Spell ring_of_fire = placeholder(); + public static final Spell detonate = placeholder(); + public static final Spell fire_resistance = placeholder(); + public static final Spell fireskin = placeholder(); + public static final Spell flaming_axe = placeholder(); + public static final Spell blizzard = placeholder(); + public static final Spell summon_ice_wraith = placeholder(); + public static final Spell ice_shroud = placeholder(); + public static final Spell ice_charge = placeholder(); + public static final Spell frost_axe = placeholder(); + public static final Spell invoke_weather = placeholder(); + public static final Spell chain_lightning = placeholder(); + public static final Spell lightning_bolt = placeholder(); + public static final Spell summon_lightning_wraith = placeholder(); + public static final Spell static_aura = placeholder(); + public static final Spell lightning_disc = placeholder(); + public static final Spell mind_control = placeholder(); + public static final Spell summon_wither_skeleton = placeholder(); + public static final Spell entrapment = placeholder(); + public static final Spell wither_skull = placeholder(); + public static final Spell darkness_orb = placeholder(); + public static final Spell shadow_ward = placeholder(); + public static final Spell decay = placeholder(); + public static final Spell water_breathing = placeholder(); + public static final Spell tornado = placeholder(); + public static final Spell glide = placeholder(); + public static final Spell summon_spirit_horse = placeholder(); + public static final Spell spider_swarm = placeholder(); + public static final Spell slime = placeholder(); + public static final Spell petrify = placeholder(); + public static final Spell invisibility = placeholder(); + public static final Spell levitation = placeholder(); + public static final Spell force_orb = placeholder(); + public static final Spell transportation = placeholder(); + public static final Spell spectral_pathway = placeholder(); + public static final Spell phase_step = placeholder(); + public static final Spell vanishing_box = placeholder(); + public static final Spell greater_heal = placeholder(); + public static final Spell healing_aura = placeholder(); + public static final Spell forcefield = placeholder(); + public static final Spell ironflesh = placeholder(); + public static final Spell transience = placeholder(); - public static final Spell meteor = null; - public static final Spell firestorm = null; - public static final Spell summon_phoenix = null; - public static final Spell ice_age = null; - public static final Spell wall_of_frost = null; - public static final Spell summon_ice_giant = null; - public static final Spell thunderstorm = null; - public static final Spell lightning_hammer = null; - public static final Spell plague_of_darkness = null; - public static final Spell summon_skeleton_legion = null; - public static final Spell summon_shadow_wraith = null; - public static final Spell forests_curse = null; - public static final Spell flight = null; - public static final Spell silverfish_swarm = null; - public static final Spell black_hole = null; - public static final Spell shockwave = null; - public static final Spell summon_iron_golem = null; - public static final Spell arrow_rain = null; - public static final Spell diamondflesh = null; - public static final Spell font_of_vitality = null; + public static final Spell meteor = placeholder(); + public static final Spell fire_breath = placeholder(); + public static final Spell summon_phoenix = placeholder(); + public static final Spell ice_age = placeholder(); + public static final Spell wall_of_frost = placeholder(); + public static final Spell summon_ice_giant = placeholder(); + public static final Spell thunderstorm = placeholder(); + public static final Spell lightning_hammer = placeholder(); + public static final Spell plague_of_darkness = placeholder(); + public static final Spell summon_skeleton_legion = placeholder(); + public static final Spell summon_shadow_wraith = placeholder(); + public static final Spell forests_curse = placeholder(); + public static final Spell flight = placeholder(); + public static final Spell silverfish_swarm = placeholder(); + public static final Spell black_hole = placeholder(); + public static final Spell shockwave = placeholder(); + public static final Spell summon_iron_golem = placeholder(); + public static final Spell arrow_rain = placeholder(); + public static final Spell diamondflesh = placeholder(); + public static final Spell font_of_vitality = placeholder(); // Wizardry 1.1 spells - public static final Spell smoke_bomb = null; - public static final Spell mind_trick = null; - public static final Spell leap = null; + public static final Spell smoke_bomb = placeholder(); + public static final Spell mind_trick = placeholder(); + public static final Spell leap = placeholder(); - public static final Spell pocket_furnace = null; - public static final Spell intimidate = null; - public static final Spell banish = null; - public static final Spell sixth_sense = null; - public static final Spell darkvision = null; - public static final Spell clairvoyance = null; - public static final Spell pocket_workbench = null; - public static final Spell imbue_weapon = null; - public static final Spell invigorating_presence = null; - public static final Spell oakflesh = null; + public static final Spell pocket_furnace = placeholder(); + public static final Spell intimidate = placeholder(); + public static final Spell banish = placeholder(); + public static final Spell sixth_sense = placeholder(); + public static final Spell darkvision = placeholder(); + public static final Spell clairvoyance = placeholder(); + public static final Spell pocket_workbench = placeholder(); + public static final Spell imbue_weapon = placeholder(); + public static final Spell invigorating_presence = placeholder(); + public static final Spell oakflesh = placeholder(); - public static final Spell greater_fireball = null; - public static final Spell flaming_weapon = null; - public static final Spell ice_lance = null; - public static final Spell freezing_weapon = null; - public static final Spell ice_spikes = null; - public static final Spell lightning_pulse = null; - public static final Spell curse_of_soulbinding = null; - public static final Spell cobwebs = null; - public static final Spell decoy = null; - public static final Spell arcane_jammer = null; - public static final Spell conjure_armour = null; - public static final Spell group_heal = null; + public static final Spell greater_fireball = placeholder(); + public static final Spell flaming_weapon = placeholder(); + public static final Spell ice_lance = placeholder(); + public static final Spell freezing_weapon = placeholder(); + public static final Spell ice_spikes = placeholder(); + public static final Spell lightning_pulse = placeholder(); + public static final Spell curse_of_soulbinding = placeholder(); + public static final Spell cobwebs = placeholder(); + public static final Spell decoy = placeholder(); + public static final Spell arcane_jammer = placeholder(); + public static final Spell conjure_armour = placeholder(); + public static final Spell group_heal = placeholder(); - public static final Spell hailstorm = null; - public static final Spell lightning_web = null; - public static final Spell summon_storm_elemental = null; - public static final Spell earthquake = null; - public static final Spell font_of_mana = null; + public static final Spell hailstorm = placeholder(); + public static final Spell lightning_web = placeholder(); + public static final Spell summon_storm_elemental = placeholder(); + public static final Spell earthquake = placeholder(); + public static final Spell font_of_mana = placeholder(); + + // Wizardry 4.2 spells + + public static final Spell mine = placeholder(); + public static final Spell conjure_block = placeholder(); + public static final Spell muffle = placeholder(); + public static final Spell ward = placeholder(); + public static final Spell evade = placeholder(); + + public static final Spell iceball = placeholder(); + public static final Spell charge = placeholder(); + public static final Spell reversal = placeholder(); + public static final Spell grapple = placeholder(); + public static final Spell divination = placeholder(); + public static final Spell empowering_presence = placeholder(); + + public static final Spell disintegration = placeholder(); + public static final Spell combustion_rune = placeholder(); + public static final Spell frost_step = placeholder(); + public static final Spell paralysis = placeholder(); + public static final Spell shulker_bullet = placeholder(); + public static final Spell curse_of_undeath = placeholder(); + public static final Spell dragon_fireball = placeholder(); + public static final Spell greater_telekinesis = placeholder(); + public static final Spell vex_swarm = placeholder(); + public static final Spell arcane_lock = placeholder(); + public static final Spell containment = placeholder(); + public static final Spell satiety = placeholder(); + public static final Spell greater_ward = placeholder(); + public static final Spell ray_of_purification = placeholder(); + public static final Spell remove_curse = placeholder(); + + public static final Spell possession = placeholder(); + public static final Spell curse_of_enfeeblement = placeholder(); + public static final Spell forest_of_thorns = placeholder(); + public static final Spell speed_time = placeholder(); + public static final Spell slow_time = placeholder(); + public static final Spell resurrection = placeholder(); @SubscribeEvent public static void register(RegistryEvent.Register event){ @@ -244,34 +243,34 @@ public final class Spells { IForgeRegistry registry = event.getRegistry(); registry.register(new None()); - registry.register(new SpellArrow("magic_missile", Tier.BASIC, Element.MAGIC, 5, 10, EntityMagicMissile::new, 2, WizardrySounds.SPELL_MAGIC).soundValues(1, 1.4f, 0.4f)); + registry.register(new SpellArrow<>("magic_missile", EntityMagicMissile::new).addProperties(Spell.DAMAGE).soundValues(1, 1.4f, 0.4f)); registry.register(new Ignite()); registry.register(new Freeze()); registry.register(new Snowball()); registry.register(new Arc()); - registry.register(new SpellProjectile("thunderbolt", Tier.BASIC, Element.LIGHTNING, 10, 15, EntityThunderbolt::new, 2.5f, WizardrySounds.SPELL_ICE).soundValues(0.8f, 0.9f, 0.2f)); - registry.register(new SpellMinion<>("summon_zombie", Tier.BASIC, Element.NECROMANCY, 10, 40, EntityZombieMinion::new, 600, WizardrySounds.SPELL_SUMMONING).soundValues(7, 0.6f, 0)); + registry.register(new SpellProjectile<>("thunderbolt", EntityThunderbolt::new).addProperties(Spell.DAMAGE, EntityThunderbolt.KNOCKBACK_STRENGTH).soundValues(0.8f, 0.9f, 0.2f)); + registry.register(new SummonZombie()); registry.register(new Snare()); - registry.register(new SpellArrow("dart", Tier.BASIC, Element.EARTH, 5, 10, EntityDart::new, 2, SoundEvents.ENTITY_ARROW_SHOOT).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellArrow<>("dart", EntityDart::new).addProperties(Spell.DAMAGE, Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new Light()); registry.register(new Telekinesis()); registry.register(new Heal()); - registry.register(new Fireball()); + registry.register(new SpellProjectile<>("fireball", EntityMagicFireball::new).addProperties(Spell.DAMAGE, Spell.BURN_DURATION));//new Fireball()); registry.register(new FlameRay()); - registry.register(new SpellProjectile("firebomb", Tier.APPRENTICE, Element.FIRE, 15, 25, EntityFirebomb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); - registry.register(new SpellConstructRanged<>("fire_sigil", Tier.APPRENTICE, Element.FIRE, SpellType.CONSTRUCT, 10, 20, EntityFireSigil::new, -1, 10, SoundEvents.ITEM_FLINTANDSTEEL_USE).floor(true)); - registry.register(new SpellProjectile("firebolt", Tier.APPRENTICE, Element.FIRE, 10, 10, EntityFirebolt::new, 2.5f, SoundEvents.ENTITY_BLAZE_SHOOT)); + registry.register(new SpellProjectile<>("firebomb", EntityFirebomb::new).addProperties(Spell.DIRECT_DAMAGE, Spell.SPLASH_DAMAGE, Spell.BLAST_RADIUS, Spell.BURN_DURATION).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellConstructRanged<>("fire_sigil", EntityFireSigil::new, true).floor(true).addProperties(Spell.DAMAGE, Spell.BURN_DURATION)); + registry.register(new SpellProjectile<>("firebolt", EntityFirebolt::new).addProperties(Spell.DAMAGE, Spell.BURN_DURATION)); registry.register(new FrostRay()); registry.register(new SummonSnowGolem()); - registry.register(new SpellArrow("ice_shard", Tier.APPRENTICE, Element.ICE, 10, 10, EntityIceShard::new, 2, WizardrySounds.SPELL_ICE).soundValues(1, 1.6f, 0.4f)); + registry.register(new SpellArrow<>("ice_shard", EntityIceShard::new).addProperties(Spell.DAMAGE, Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH).soundValues(1, 1.6f, 0.4f)); registry.register(new IceStatue()); - registry.register(new SpellConstructRanged<>("frost_sigil", Tier.APPRENTICE, Element.ICE, SpellType.CONSTRUCT, 10, 20, EntityFrostSigil::new, -1, 10, WizardrySounds.SPELL_ICE).floor(true)); + registry.register(new SpellConstructRanged<>("frost_sigil", EntityFrostSigil::new, true).floor(true).addProperties(Spell.DAMAGE, Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH)); registry.register(new LightningRay()); - registry.register(new SpellProjectile("spark_bomb", Tier.APPRENTICE, Element.LIGHTNING, 15, 25, EntitySparkBomb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); - registry.register(new SpellProjectile("homing_spark", Tier.APPRENTICE, Element.LIGHTNING, 10, 20, EntitySpark::new, 0.5f, WizardrySounds.SPELL_CONJURATION).soundValues(1.0f, 0.4f, 0.2f)); - registry.register(new SpellConstructRanged<>("lightning_sigil", Tier.APPRENTICE, Element.LIGHTNING, SpellType.CONSTRUCT, 10, 20, EntityLightningSigil::new, -1, 10, WizardrySounds.SPELL_CONJURATION).floor(true)); - registry.register(new SpellArrow("lightning_arrow", Tier.APPRENTICE, Element.LIGHTNING, 15, 20, EntityLightningArrow::new, 2, WizardrySounds.SPELL_LIGHTNING).soundValues(1, 1.45f, 0.3f)); + registry.register(new SpellProjectile<>("spark_bomb", EntitySparkBomb::new).addProperties(Spell.DIRECT_DAMAGE, Spell.EFFECT_RADIUS, EntitySparkBomb.SECONDARY_MAX_TARGETS, Spell.SPLASH_DAMAGE).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellProjectile<>("homing_spark", EntitySpark::new).addProperties(Spell.DAMAGE, Spell.SEEKING_STRENGTH).soundValues(1.0f, 0.4f, 0.2f)); + registry.register(new SpellConstructRanged<>("lightning_sigil", EntityLightningSigil::new, true).floor(true).addProperties(Spell.DIRECT_DAMAGE, Spell.EFFECT_RADIUS, EntityLightningSigil.SECONDARY_MAX_TARGETS, Spell.SPLASH_DAMAGE)); + registry.register(new SpellArrow<>("lightning_arrow", EntityLightningArrow::new).addProperties(Spell.DAMAGE).soundValues(1, 1.45f, 0.3f)); registry.register(new LifeDrain()); registry.register(new SummonSkeleton()); registry.register(new Metamorphosis()); @@ -280,69 +279,69 @@ public final class Spells { registry.register(new GrowthAura()); registry.register(new Bubble()); registry.register(new Whirlwind()); - registry.register(new SpellProjectile("poison_bomb", Tier.APPRENTICE, Element.EARTH, 15, 25, EntityPoisonBomb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellProjectile<>("poison_bomb", EntityPoisonBomb::new).addProperties(Spell.DIRECT_DAMAGE, Spell.EFFECT_RADIUS, Spell.DIRECT_EFFECT_DURATION, Spell.DIRECT_EFFECT_STRENGTH, Spell.SPLASH_DAMAGE, Spell.SPLASH_EFFECT_DURATION, Spell.SPLASH_EFFECT_STRENGTH).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new SummonSpiritWolf()); registry.register(new Blink()); - registry.register(new SpellBuff("agility", Tier.APPRENTICE, Element.SORCERY, SpellType.BUFF, 20, 40, WizardrySounds.SPELL_HEAL, 0.4f, 1.0f, 0.8f, Triple.of(MobEffects.SPEED, 600, 1), Triple.of(MobEffects.JUMP_BOOST, 600, 1)).soundValues(0.7f, 1.2f, 0.4f)); - registry.register(new SpellConjuration("conjure_sword", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 25, 50, WizardryItems.spectral_sword, WizardrySounds.SPELL_CONJURATION)); - registry.register(new SpellConjuration("conjure_pickaxe", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 25, 50, WizardryItems.spectral_pickaxe, WizardrySounds.SPELL_CONJURATION)); - registry.register(new SpellConjuration("conjure_bow", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 40, 50, WizardryItems.spectral_bow, WizardrySounds.SPELL_CONJURATION)); - registry.register(new SpellArrow("force_arrow", Tier.APPRENTICE, Element.SORCERY, 15, 20, EntityForceArrow::new, 1, WizardrySounds.SPELL_FORCE).soundValues(1, 1.3f, 0.2f)); + registry.register(new SpellBuff("agility", 0.4f, 1.0f, 0.8f, () -> MobEffects.SPEED, () -> MobEffects.JUMP_BOOST).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellConjuration("conjure_sword", WizardryItems.spectral_sword)); + registry.register(new SpellConjuration("conjure_pickaxe", WizardryItems.spectral_pickaxe)); + registry.register(new SpellConjuration("conjure_bow", WizardryItems.spectral_bow)); + registry.register(new ForceArrow()); registry.register(new Shield()); registry.register(new ReplenishHunger()); registry.register(new CureEffects()); registry.register(new HealAlly()); - registry.register(new SpellMinion<>("summon_blaze", Tier.ADVANCED, Element.FIRE, 40, 200, EntityBlazeMinion::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.2f)); - registry.register(new SpellConstruct<>("ring_of_fire", Tier.ADVANCED, Element.FIRE, SpellType.CONSTRUCT, 30, 100, EnumAction.BOW, EntityFireRing::new, 600, SoundEvents.ENTITY_BLAZE_SHOOT)); + registry.register(new SpellMinion<>("summon_blaze", EntityBlazeMinion::new).soundValues(1, 1.1f, 0.2f)); + registry.register(new SpellConstruct<>("ring_of_fire", EnumAction.BOW, EntityFireRing::new, false).floor(true).addProperties(Spell.DAMAGE, Spell.BURN_DURATION)); registry.register(new Detonate()); - registry.register(new SpellBuff("fire_resistance", Tier.ADVANCED, Element.FIRE, SpellType.DEFENCE, 20, 80, WizardrySounds.SPELL_HEAL, 1, 0.5f, 0, Triple.of(MobEffects.FIRE_RESISTANCE, 600, 0)).soundValues(0.7f, 1.2f, 0.4f)); - registry.register(new SpellBuff("fireskin", Tier.ADVANCED, Element.FIRE, SpellType.DEFENCE, 40, 250, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 0.5f, 0, Triple.of(WizardryPotions.fireskin, 600, 0))); + registry.register(new SpellBuff("fire_resistance", 1, 0.5f, 0, () -> MobEffects.FIRE_RESISTANCE).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("fireskin", 1, 0.5f, 0, () -> WizardryPotions.fireskin).addProperties(Spell.BURN_DURATION)); registry.register(new FlamingAxe()); - registry.register(new SpellConstructRanged<>("blizzard", Tier.ADVANCED, Element.ICE, SpellType.CONSTRUCT, 40, 100, EntityBlizzard::new, 600, 20, WizardrySounds.SPELL_ICE)); - registry.register(new SpellMinion<>("summon_ice_wraith", Tier.ADVANCED, Element.ICE, 40, 200, EntityIceWraith::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.2f)); - registry.register(new SpellBuff("ice_shroud", Tier.ADVANCED, Element.ICE, SpellType.DEFENCE, 40, 250, WizardrySounds.SPELL_ICE, 0.3f, 0.5f, 1, Triple.of(WizardryPotions.ice_shroud, 600, 0)).soundValues(1, 1.6f, 0.4f)); - registry.register(new SpellProjectile("ice_charge", Tier.ADVANCED, Element.ICE, 20, 30, EntityIceCharge::new, 1.5f, WizardrySounds.SPELL_ICE).soundValues(1, 1.6f, 0.4f)); + registry.register(new SpellConstructRanged<>("blizzard", EntityBlizzard::new, false).addProperties(Spell.EFFECT_RADIUS)); + registry.register(new SpellMinion<>("summon_ice_wraith", EntityIceWraith::new).soundValues(1, 1.1f, 0.2f)); + registry.register(new SpellBuff("ice_shroud", 0.3f, 0.5f, 1, () -> WizardryPotions.ice_shroud).addProperties(Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH).soundValues(1, 1.6f, 0.4f)); + registry.register(new SpellProjectile<>("ice_charge", EntityIceCharge::new).addProperties(Spell.DAMAGE, Spell.EFFECT_RADIUS, Spell.DIRECT_EFFECT_DURATION, Spell.DIRECT_EFFECT_STRENGTH, Spell.SPLASH_EFFECT_DURATION, Spell.SPLASH_EFFECT_STRENGTH, EntityIceCharge.ICE_SHARDS).soundValues(1, 1.6f, 0.4f)); registry.register(new FrostAxe()); registry.register(new InvokeWeather()); registry.register(new ChainLightning()); registry.register(new LightningBolt()); - registry.register(new SpellMinion<>("summon_lightning_wraith", Tier.ADVANCED, Element.LIGHTNING, 40, 200, EntityLightningWraith::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.2f)); - registry.register(new SpellBuff("static_aura", Tier.ADVANCED, Element.LIGHTNING, SpellType.DEFENCE, 40, 250, WizardrySounds.SPELL_SPARK, 0, 0.5f, 0.7f, Triple.of(WizardryPotions.static_aura, 600, 0)).soundValues(1, 1.6f, 0.4f)); - registry.register(new SpellProjectile("lightning_disc", Tier.ADVANCED, Element.LIGHTNING, 25, 60, EntityLightningDisc::new, 1.2f, WizardrySounds.SPELL_LIGHTNING).soundValues(1, 0.95f, 0.3f)); + registry.register(new SpellMinion<>("summon_lightning_wraith", EntityLightningWraith::new).soundValues(1, 1.1f, 0.2f)); + registry.register(new SpellBuff("static_aura", 0, 0.5f, 0.7f, () -> WizardryPotions.static_aura).addProperties(Spell.DAMAGE).soundValues(1, 1.6f, 0.4f)); + registry.register(new SpellProjectile<>("lightning_disc", EntityLightningDisc::new).addProperties(Spell.DAMAGE, Spell.SEEKING_STRENGTH).soundValues(1, 0.95f, 0.3f)); registry.register(new MindControl()); - registry.register(new SpellMinion<>("summon_wither_skeleton", Tier.ADVANCED, Element.NECROMANCY, 35, 150, EntityWitherSkeletonMinion::new, 600, WizardrySounds.SPELL_SUMMONING).soundValues(7, 0.6f, 0)); + registry.register(new SummonWitherSkeleton()); registry.register(new Entrapment()); registry.register(new WitherSkull()); - registry.register(new SpellProjectile("darkness_orb", Tier.ADVANCED, Element.NECROMANCY, 20, 20, EntityDarknessOrb::new, 0.5f, SoundEvents.ENTITY_WITHER_SHOOT).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellProjectile<>("darkness_orb", EntityDarknessOrb::new).addProperties(Spell.DAMAGE, Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new ShadowWard()); registry.register(new Decay()); - registry.register(new SpellBuff("water_breathing", Tier.ADVANCED, Element.EARTH, SpellType.BUFF, 30, 250, WizardrySounds.SPELL_HEAL, 0.3f, 0.3f, 1, Triple.of(MobEffects.WATER_BREATHING, 1200, 0)){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("water_breathing", 0.3f, 0.3f, 1, () -> MobEffects.WATER_BREATHING){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Tornado()); registry.register(new Glide()); registry.register(new SummonSpiritHorse()); - registry.register(new SpellMinion<>("spider_swarm", Tier.ADVANCED, Element.EARTH, 45, 200, EntitySpiderMinion::new, 600, SoundEvents.BLOCK_FIRE_EXTINGUISH).soundValues(1, 1.1f, 0.1f).quantity(5).range(3)); + registry.register(new SpellMinion<>("spider_swarm", EntitySpiderMinion::new).soundValues(1, 1.1f, 0.1f)); registry.register(new Slime()); registry.register(new Petrify()); - registry.register(new SpellBuff("invisibility", Tier.ADVANCED, Element.SORCERY, SpellType.BUFF, 35, 200, WizardrySounds.SPELL_HEAL, 0.7f, 1, 1, Triple.of(MobEffects.INVISIBILITY, 600, 0)).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("invisibility", 0.7f, 1, 1, () -> MobEffects.INVISIBILITY).soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Levitation()); - registry.register(new SpellProjectile("force_orb", Tier.ADVANCED, Element.SORCERY, 20, 20, EntityForceOrb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellProjectile<>("force_orb", EntityForceOrb::new).addProperties(Spell.DAMAGE, Spell.BLAST_RADIUS).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new Transportation()); registry.register(new SpectralPathway()); registry.register(new PhaseStep()); registry.register(new VanishingBox()); registry.register(new GreaterHeal()); - registry.register(new SpellConstruct<>("healing_aura", Tier.ADVANCED, Element.HEALING, SpellType.CONSTRUCT, 35, 150, EnumAction.BOW, EntityHealAura::new, 600, null)); - registry.register(new SpellConstruct<>("forcefield", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 45, 200, EnumAction.BOW, EntityForcefield::new, 600, WizardrySounds.SPELL_CONJURATION_LARGE)); - registry.register(new SpellBuff("ironflesh", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 30, 100, WizardrySounds.SPELL_HEAL, 0.4f, 0.5f, 0.6f, Triple.of(MobEffects.RESISTANCE, 600, 2)).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellConstruct<>("healing_aura", EnumAction.BOW, EntityHealAura::new, false).addProperties(Spell.DAMAGE, Spell.HEALTH)); + registry.register(new Forcefield()); + registry.register(new SpellBuff("ironflesh", 0.4f, 0.5f, 0.6f, () -> MobEffects.RESISTANCE).soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Transience()); registry.register(new Meteor()); - registry.register(new Firestorm()); - registry.register(new SpellMinion<>("summon_phoenix", Tier.MASTER, Element.FIRE, 150, 400, EntityPhoenix::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.1f)); + registry.register(new FireBreath()); + registry.register(new SpellMinion<>("summon_phoenix", EntityPhoenix::new).flying(true).soundValues(1, 1.1f, 0.1f)); registry.register(new IceAge()); registry.register(new WallOfFrost()); - registry.register(new SpellMinion<>("summon_ice_giant", Tier.MASTER, Element.ICE, 100, 400, EntityIceGiant::new, 600, WizardrySounds.SPELL_ICE).soundValues(1, 0.15f, 0.1f)); + registry.register(new SpellMinion<>("summon_ice_giant", EntityIceGiant::new).soundValues(1, 0.15f, 0.1f)); registry.register(new Thunderstorm()); registry.register(new LightningHammer()); registry.register(new PlagueOfDarkness()); @@ -350,17 +349,17 @@ public final class Spells { registry.register(new SummonShadowWraith()); registry.register(new ForestsCurse()); registry.register(new Flight()); - registry.register(new SpellMinion<>("silverfish_swarm", Tier.MASTER, Element.EARTH, 80, 300, EntitySilverfishMinion::new, 600, SoundEvents.BLOCK_FIRE_EXTINGUISH).soundValues(1, 1.1f, 0.1f).quantity(20).range(3)); - registry.register(new SpellConstructRanged<>("black_hole", Tier.MASTER, Element.SORCERY, SpellType.CONSTRUCT, 150, 400, EntityBlackHole::new, 600, 10, SoundEvents.ENTITY_WITHER_SPAWN).soundValues(2, 0.7f, 0)); + registry.register(new SpellMinion<>("silverfish_swarm", EntitySilverfishMinion::new).soundValues(1, 1.1f, 0.1f)); + registry.register(new SpellConstructRanged<>("black_hole", EntityBlackHole::new, false).soundValues(2, 0.7f, 0)); registry.register(new Shockwave()); registry.register(new SummonIronGolem()); registry.register(new ArrowRain()); - registry.register(new SpellBuff("diamondflesh", Tier.MASTER, Element.HEALING, SpellType.DEFENCE, 100, 300, WizardrySounds.SPELL_HEAL, 0.1f, 0.7f, 1, Triple.of(MobEffects.RESISTANCE, 600, 5)).soundValues(0.7f, 1.2f, 0.4f)); - registry.register(new SpellBuff("font_of_vitality", Tier.MASTER, Element.HEALING, SpellType.DEFENCE, 75, 300, WizardrySounds.SPELL_HEAL, 1, 0.8f, 0.3f, Triple.of(MobEffects.ABSORPTION, 1200, 1), Triple.of(MobEffects.REGENERATION, 300, 1)).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("diamondflesh", 0.1f, 0.7f, 1, () -> MobEffects.RESISTANCE).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("font_of_vitality", 1, 0.8f, 0.3f, () -> MobEffects.ABSORPTION, () -> MobEffects.REGENERATION).soundValues(0.7f, 1.2f, 0.4f)); // Wizardry 1.1 spells - registry.register(new SpellProjectile("smoke_bomb", Tier.BASIC, Element.FIRE, 10, 20, EntitySmokeBomb::new, 1.5f, SoundEvents.ENTITY_SNOWBALL_THROW).soundValues(0.5f, 0.4f, 0.2f)); + registry.register(new SpellProjectile<>("smoke_bomb", EntitySmokeBomb::new).addProperties(Spell.BLAST_RADIUS, Spell.EFFECT_DURATION).soundValues(0.5f, 0.4f, 0.2f)); registry.register(new MindTrick()); registry.register(new Leap()); @@ -368,16 +367,16 @@ public final class Spells { registry.register(new Intimidate()); registry.register(new Banish()); registry.register(new SixthSense()); - registry.register(new SpellBuff("darkvision", Tier.APPRENTICE, Element.EARTH, SpellType.BUFF, 20, 40, WizardrySounds.SPELL_HEAL, 0, 0.4f, 0.7f, Triple.of(MobEffects.NIGHT_VISION, 900, 0)){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("darkvision", 0, 0.4f, 0.7f, () -> MobEffects.NIGHT_VISION){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f)); registry.register(new Clairvoyance()); registry.register(new PocketWorkbench()); registry.register(new ImbueWeapon()); registry.register(new InvigoratingPresence()); - registry.register(new SpellBuff("oakflesh", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 20, 50, WizardrySounds.SPELL_HEAL, 0.6f, 0.5f, 0.4f, Triple.of(MobEffects.RESISTANCE, 600, 1)).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("oakflesh", 0.6f, 0.5f, 0.4f, () -> MobEffects.RESISTANCE).soundValues(0.7f, 1.2f, 0.4f)); - registry.register(new GreaterFireball()); + registry.register(new SpellProjectile<>("greater_fireball", EntityLargeMagicFireball::new).addProperties(Spell.DAMAGE, EntityLargeMagicFireball.EXPLOSION_POWER));//new GreaterFireball()); registry.register(new FlamingWeapon()); - registry.register(new SpellArrow("ice_lance", Tier.ADVANCED, Element.ICE, 20, 20, EntityIceLance::new, 2, WizardrySounds.SPELL_ICE).soundValues(1, 1, 0.4f)); + registry.register(new SpellArrow<>("ice_lance", EntityIceLance::new).addProperties(Spell.DAMAGE, Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH).soundValues(1, 1, 0.4f)); registry.register(new FreezingWeapon()); registry.register(new IceSpikes()); registry.register(new LightningPulse()); @@ -390,9 +389,47 @@ public final class Spells { registry.register(new Hailstorm()); registry.register(new LightningWeb()); - registry.register(new SpellMinion<>("summon_storm_elemental", Tier.MASTER, Element.LIGHTNING, 100, 400, EntityStormElemental::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT).soundValues(1, 1.1f, 0.1f)); + registry.register(new SpellMinion<>("summon_storm_elemental", EntityStormElemental::new).soundValues(1, 1.1f, 0.1f)); registry.register(new Earthquake()); registry.register(new FontOfMana()); + + // Wizardry 4.2 spells + + registry.register(new Mine()); + registry.register(new ConjureBlock()); + registry.register(new SpellBuff("muffle", 0.3f, 0.4f, 0.8f, () -> WizardryPotions.muffle).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new SpellBuff("ward", 0.75f, 0.6f, 0.8f, () -> WizardryPotions.ward).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new Evade()); + + registry.register(new SpellProjectile<>("iceball", EntityIceball::new).addProperties(Spell.DAMAGE, Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH)); + registry.register(new Charge()); + registry.register(new Reversal()); + registry.register(new Grapple()); + registry.register(new Divination()); + registry.register(new EmpoweringPresence()); + + registry.register(new Disintegration()); + registry.register(new SpellConstructRanged<>("combustion_rune", EntityCombustionRune::new, true).floor(true).addProperties(Spell.BLAST_RADIUS)); + registry.register(new SpellBuff("frost_step", 0.3f, 0.4f, 0.8f, () -> WizardryPotions.frost_step).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new Paralysis()); + registry.register(new ShulkerBullet()); + registry.register(new CurseOfUndeath()); + registry.register(new DragonFireball()); + registry.register(new GreaterTelekinesis()); + registry.register(new SpellMinion<>("vex_swarm", EntityVexMinion::new).flying(true).soundValues(1, 1.1f, 0.1f)); + registry.register(new ArcaneLock()); + registry.register(new Containment()); + registry.register(new Satiety()); + registry.register(new SpellBuff("greater_ward", 0.75f, 0.6f, 0.8f, () -> WizardryPotions.ward).soundValues(0.7f, 1.2f, 0.4f)); + registry.register(new RayOfPurification()); + registry.register(new RemoveCurse()); + + registry.register(new Possession()); + registry.register(new CurseOfEnfeeblement()); + registry.register(new ForestOfThorns()); + registry.register(new SpeedTime()); + registry.register(new SlowTime()); + registry.register(new Resurrection()); } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryAdvancementTriggers.java b/src/main/java/electroblob/wizardry/registry/WizardryAdvancementTriggers.java index 5d50f2ba..f5cc4aef 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryAdvancementTriggers.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryAdvancementTriggers.java @@ -1,59 +1,48 @@ package electroblob.wizardry.registry; -import electroblob.wizardry.util.CustomAdvancementTrigger; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.advancement.*; import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.util.ResourceLocation; /** - * This class stores a collection of custom advancement triggers, for advancements that cannot be triggered - * from plain vanilla JSON definitions. It replaces the old WizardryAchievements class. + * Class responsible for defining, storing and registering all of wizardry's advancement triggers. As of wizardry 4.2, + * the 'dummy' advancement triggers are being phased out in favour of proper custom triggers with JSON parameters, or + * where possible, existing triggers in Minecraft. * - * @author 12foo + * @author 12foo, Electroblob * @since Wizardry 4.1.0 */ public final class WizardryAdvancementTriggers { - - public static final CustomAdvancementTrigger armour_set = new CustomAdvancementTrigger("trigger_armour_set"); - public static final CustomAdvancementTrigger jam_wizard = new CustomAdvancementTrigger("trigger_jam_wizard"); - public static final CustomAdvancementTrigger self_destruct = new CustomAdvancementTrigger("trigger_self_destruct"); - public static final CustomAdvancementTrigger all_spells = new CustomAdvancementTrigger("trigger_all_spells"); - public static final CustomAdvancementTrigger element_master = new CustomAdvancementTrigger("trigger_element_master"); - public static final CustomAdvancementTrigger identify_spell = new CustomAdvancementTrigger("trigger_identify_spell"); - public static final CustomAdvancementTrigger elemental = new CustomAdvancementTrigger("trigger_elemental"); + + private WizardryAdvancementTriggers(){} // No instances! + public static final CustomAdvancementTrigger legendary = new CustomAdvancementTrigger("trigger_legendary"); public static final CustomAdvancementTrigger max_out_wand = new CustomAdvancementTrigger("trigger_max_out_wand"); public static final CustomAdvancementTrigger special_upgrade = new CustomAdvancementTrigger("trigger_special_upgrade"); - public static final CustomAdvancementTrigger pig_tornado = new CustomAdvancementTrigger("trigger_pig_tornado"); - public static final CustomAdvancementTrigger master = new CustomAdvancementTrigger("trigger_master"); - public static final CustomAdvancementTrigger apprentice = new CustomAdvancementTrigger("trigger_apprentice"); public static final CustomAdvancementTrigger anger_wizard = new CustomAdvancementTrigger("trigger_anger_wizard"); public static final CustomAdvancementTrigger buy_master_spell = new CustomAdvancementTrigger("trigger_buy_master_spell"); - public static final CustomAdvancementTrigger wizard_trade = new CustomAdvancementTrigger("trigger_wizard_trade"); - public static final CustomAdvancementTrigger slime_skeleton = new CustomAdvancementTrigger("trigger_slime_skeleton"); - public static final CustomAdvancementTrigger freeze_blaze = new CustomAdvancementTrigger("trigger_freeze_blaze"); - public static final CustomAdvancementTrigger frankenstein = new CustomAdvancementTrigger("trigger_frankenstein"); - public static final CustomAdvancementTrigger charge_creeper = new CustomAdvancementTrigger("trigger_charge_creeper"); + public static final CustomAdvancementTrigger wizard_trade = new CustomAdvancementTrigger("trigger_wizard_trade"); + public static final CustomAdvancementTrigger spell_failure = new CustomAdvancementTrigger("trigger_spell_failure"); + + public static final StructureTrigger visit_structure = new StructureTrigger(new ResourceLocation(Wizardry.MODID, "visit_structure")); + public static final ArcaneWorkbenchTrigger arcane_workbench = new ArcaneWorkbenchTrigger(new ResourceLocation(Wizardry.MODID, "arcane_workbench")); + public static final SpellCastTrigger cast_spell = new SpellCastTrigger(new ResourceLocation(Wizardry.MODID, "cast_spell")); + public static final SpellDiscoveryTrigger discover_spell = new SpellDiscoveryTrigger(new ResourceLocation(Wizardry.MODID, "discover_spell")); public static void register(){ - - CriteriaTriggers.register(armour_set); - CriteriaTriggers.register(jam_wizard); - CriteriaTriggers.register(self_destruct); - CriteriaTriggers.register(all_spells); - CriteriaTriggers.register(element_master); - CriteriaTriggers.register(identify_spell); - CriteriaTriggers.register(elemental); + CriteriaTriggers.register(legendary); CriteriaTriggers.register(max_out_wand); CriteriaTriggers.register(special_upgrade); - CriteriaTriggers.register(pig_tornado); - CriteriaTriggers.register(master); - CriteriaTriggers.register(apprentice); CriteriaTriggers.register(anger_wizard); CriteriaTriggers.register(buy_master_spell); CriteriaTriggers.register(wizard_trade); - CriteriaTriggers.register(slime_skeleton); - CriteriaTriggers.register(freeze_blaze); - CriteriaTriggers.register(frankenstein); - CriteriaTriggers.register(charge_creeper); + CriteriaTriggers.register(spell_failure); + + CriteriaTriggers.register(visit_structure); + CriteriaTriggers.register(arcane_workbench); + CriteriaTriggers.register(cast_spell); + CriteriaTriggers.register(discover_spell); } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java b/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java index c1d79e48..8772e212 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryBlocks.java @@ -2,16 +2,22 @@ package electroblob.wizardry.registry; import electroblob.wizardry.Wizardry; import electroblob.wizardry.block.*; +import electroblob.wizardry.tileentity.*; import net.minecraft.block.Block; import net.minecraft.block.material.Material; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; import net.minecraftforge.registries.IForgeRegistry; +import javax.annotation.Nonnull; + /** - * Class responsible for defining, storing and registering all of wizardry's blocks. + * Class responsible for defining, storing and registering all of wizardry's blocks. Also handles registry of the + * tile entities. * * @author Electroblob * @since Wizardry 2.1 @@ -20,6 +26,8 @@ import net.minecraftforge.registries.IForgeRegistry; @Mod.EventBusSubscriber public final class WizardryBlocks { + private WizardryBlocks(){} // No instances! + // Found a very nice way of registering things using arrays, which might make @ObjectHolder actually useful. // http://www.minecraftforge.net/forum/topic/49497-1112-is-using-registryevent-this-way-ok/ @@ -27,29 +35,37 @@ public final class WizardryBlocks { // setSoundType should be public, but in this particular version it isn't... which is a bit of a pain. - public static final Block arcane_workbench = null; - public static final Block crystal_ore = null; - public static final Block petrified_stone = null; - public static final Block ice_statue = null; - public static final Block magic_light = null; - public static final Block crystal_flower = null; - public static final Block snare = null; - public static final Block transportation_stone = null; - public static final Block spectral_block = null; - public static final Block crystal_block = null; - public static final Block meteor = null; - public static final Block vanishing_cobweb = null; - public static final Block runestone = null; + @Nonnull + @SuppressWarnings("ConstantConditions") + private static T placeholder(){ return null; } + + public static final Block arcane_workbench = placeholder(); + public static final Block crystal_ore = placeholder(); + public static final Block petrified_stone = placeholder(); + public static final Block ice_statue = placeholder(); + public static final Block magic_light = placeholder(); + public static final Block crystal_flower = placeholder(); + public static final Block snare = placeholder(); + public static final Block transportation_stone = placeholder(); + public static final Block spectral_block = placeholder(); + public static final Block crystal_block = placeholder(); + public static final Block meteor = placeholder(); + public static final Block vanishing_cobweb = placeholder(); + public static final Block runestone = placeholder(); + public static final Block runestone_pedestal = placeholder(); + public static final Block thorns = placeholder(); + public static final Block obsidian_crust = placeholder(); + public static final Block dry_frosted_ice = placeholder(); /** * Sets both the registry and unlocalised names of the given block, then registers it with the given registry. Use - * this instead of {@link Block#setRegistryName(String)} and {@link Block#setUnlocalizedName(String)} during + * this instead of {@link Block#setRegistryName(String)} and {@link Block#setTranslationKey(String)} during * construction, for convenience and consistency. * * @param registry The registry to register the given block to. * @param name The name of the block, without the mod ID or the .name stuff. The registry name will be * {@code ebwizardry:[name]}. The unlocalised name will be {@code tile.ebwizardry:[name].name}. - * @param item The block to register. + * @param block The block to register. */ public static void registerBlock(IForgeRegistry registry, String name, Block block){ block.setRegistryName(Wizardry.MODID, name); @@ -62,19 +78,35 @@ public final class WizardryBlocks { IForgeRegistry registry = event.getRegistry(); - registerBlock(registry, "arcane_workbench", new BlockArcaneWorkbench().setHardness(1.0F).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "arcane_workbench", new BlockArcaneWorkbench().setHardness(1.0F).setCreativeTab(WizardryTabs.WIZARDRY)); registerBlock(registry, "crystal_ore", new BlockCrystalOre(Material.ROCK).setHardness(3.0F).setCreativeTab(WizardryTabs.WIZARDRY)); registerBlock(registry, "petrified_stone", new BlockStatue(Material.ROCK).setHardness(1.5F).setResistance(10.0F)); - registerBlock(registry, "ice_statue", new BlockStatue(Material.ICE).setHardness(0.5F).setLightOpacity(3)); + registerBlock(registry, "ice_statue", new BlockStatue(Material.ICE).setHardness(0.5F).setLightOpacity(3)); registerBlock(registry, "magic_light", new BlockMagicLight(Material.CIRCUITS)); - registerBlock(registry, "crystal_flower", new BlockCrystalFlower(Material.PLANTS).setHardness(0.0F).setCreativeTab(WizardryTabs.WIZARDRY)); - registerBlock(registry, "snare", new BlockSnare(Material.PLANTS).setHardness(0.0F)); - registerBlock(registry, "transportation_stone", new BlockTransportationStone(Material.ROCK).setHardness(0.3F).setLightLevel(0.5f).setLightOpacity(0).setCreativeTab(WizardryTabs.WIZARDRY)); - registerBlock(registry, "spectral_block", new BlockSpectral(Material.GLASS).setLightLevel(0.7f).setLightOpacity(0).setBlockUnbreakable().setResistance(6000000.0F)); - registerBlock(registry, "crystal_block", new BlockCrystal(Material.IRON).setHardness(5.0F).setResistance(10.0F).setCreativeTab(WizardryTabs.WIZARDRY)); - registerBlock(registry, "meteor", new Block(Material.ROCK).setLightLevel(1)); - registerBlock(registry, "vanishing_cobweb", new BlockVanishingCobweb(Material.WEB).setLightOpacity(1).setHardness(4.0F)); - registerBlock(registry, "runestone", new BlockRunestone(Material.ROCK)); + registerBlock(registry, "crystal_flower", new BlockCrystalFlower(Material.PLANTS).setHardness(0.0F).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "snare", new BlockSnare(Material.PLANTS).setHardness(0.0F)); + registerBlock(registry, "transportation_stone", new BlockTransportationStone(Material.ROCK).setHardness(0.3F).setLightLevel(0.5f).setLightOpacity(0).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "spectral_block", new BlockSpectral(Material.GLASS).setLightLevel(0.7f).setLightOpacity(0).setBlockUnbreakable().setResistance(6000000.0F)); + registerBlock(registry, "crystal_block", new BlockCrystal(Material.IRON).setHardness(5.0F).setResistance(10.0F).setCreativeTab(WizardryTabs.WIZARDRY)); + registerBlock(registry, "meteor", new Block(Material.ROCK).setLightLevel(1)); + registerBlock(registry, "vanishing_cobweb", new BlockVanishingCobweb(Material.WEB).setLightOpacity(1).setHardness(4.0F)); + registerBlock(registry, "runestone", new BlockRunestone(Material.ROCK)); + registerBlock(registry, "runestone_pedestal", new BlockPedestal(Material.ROCK)); + registerBlock(registry, "thorns", new BlockThorns()); + registerBlock(registry, "obsidian_crust", new BlockObsidianCrust()); + registerBlock(registry, "dry_frosted_ice", new BlockDryFrostedIce()); } + + /** Called from the preInit method in the main mod class to register all the tile entities. */ + public static void registerTileEntities(){ + // Nope, these still don't have their own registry... + GameRegistry.registerTileEntity(TileEntityArcaneWorkbench.class, new ResourceLocation(Wizardry.MODID, "arcane_workbench")); + GameRegistry.registerTileEntity(TileEntityStatue.class, new ResourceLocation(Wizardry.MODID, "petrified_stone")); + GameRegistry.registerTileEntity(TileEntityMagicLight.class, new ResourceLocation(Wizardry.MODID, "magic_light")); + GameRegistry.registerTileEntity(TileEntityTimer.class, new ResourceLocation(Wizardry.MODID, "timer")); + GameRegistry.registerTileEntity(TileEntityPlayerSave.class, new ResourceLocation(Wizardry.MODID, "player_save")); + GameRegistry.registerTileEntity(TileEntityPlayerSaveTimed.class, new ResourceLocation(Wizardry.MODID, "player_save_timed")); + GameRegistry.registerTileEntity(TileEntityShrineCore.class, new ResourceLocation(Wizardry.MODID, "shrine_core")); + } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java b/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java index 66c8789c..b8a767f2 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryEnchantments.java @@ -1,13 +1,17 @@ package electroblob.wizardry.registry; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.enchantment.EnchantmentMagicProtection; import electroblob.wizardry.enchantment.EnchantmentMagicSword; import electroblob.wizardry.enchantment.EnchantmentTimed; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.Enchantment; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import javax.annotation.Nonnull; + /** * Class responsible for defining, storing and registering all of wizardry's enchantments. * @@ -17,6 +21,8 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber public final class WizardryEnchantments { + private WizardryEnchantments(){} // No instances! + // At the moment these enchantments generate on books in dungeon chests due to a bad bit of code (EnchantRandomly:49). // No idea how to fix this because I have no way of hooking into that code... removing the enchantments from the // registry works, but breaks everything else! @@ -26,17 +32,31 @@ public final class WizardryEnchantments { // All of these have custom classes, so the unlocalised name (referred to simply as 'name' for enchantments) is // dealt with inside those classes. - public static final Enchantment magic_sword = null; - public static final Enchantment magic_bow = null; - public static final Enchantment flaming_weapon = null; - public static final Enchantment freezing_weapon = null; + + @Nonnull + @SuppressWarnings("ConstantConditions") + private static T placeholder(){ return null; } + + public static final Enchantment magic_sword = placeholder(); + public static final Enchantment magic_bow = placeholder(); + public static final Enchantment flaming_weapon = placeholder(); + public static final Enchantment freezing_weapon = placeholder(); + + public static final Enchantment magic_protection = placeholder(); + public static final Enchantment frost_protection = placeholder(); + public static final Enchantment shock_protection = placeholder(); @SubscribeEvent public static void register(RegistryEvent.Register event){ + event.getRegistry().register(new EnchantmentMagicSword().setRegistryName(Wizardry.MODID, "magic_sword")); event.getRegistry().register(new EnchantmentTimed().setRegistryName(Wizardry.MODID, "magic_bow")); event.getRegistry().register(new EnchantmentTimed().setRegistryName(Wizardry.MODID, "flaming_weapon")); event.getRegistry().register(new EnchantmentTimed().setRegistryName(Wizardry.MODID, "freezing_weapon")); + + event.getRegistry().register(new EnchantmentMagicProtection(Enchantment.Rarity.UNCOMMON, EnchantmentMagicProtection.Type.MAGIC, WizardryUtilities.ARMOUR_SLOTS).setRegistryName(Wizardry.MODID, "magic_protection")); + event.getRegistry().register(new EnchantmentMagicProtection(Enchantment.Rarity.RARE, EnchantmentMagicProtection.Type.FROST, WizardryUtilities.ARMOUR_SLOTS).setRegistryName(Wizardry.MODID, "frost_protection")); + event.getRegistry().register(new EnchantmentMagicProtection(Enchantment.Rarity.RARE, EnchantmentMagicProtection.Type.SHOCK, WizardryUtilities.ARMOUR_SLOTS).setRegistryName(Wizardry.MODID, "shock_protection")); } } diff --git a/src/main/java/electroblob/wizardry/registry/WizardryEntities.java b/src/main/java/electroblob/wizardry/registry/WizardryEntities.java new file mode 100644 index 00000000..b7bf9839 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryEntities.java @@ -0,0 +1,190 @@ +package electroblob.wizardry.registry; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.EntityLevitatingBlock; +import electroblob.wizardry.entity.EntityMeteor; +import electroblob.wizardry.entity.EntityShield; +import electroblob.wizardry.entity.construct.*; +import electroblob.wizardry.entity.living.*; +import electroblob.wizardry.entity.projectile.*; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.BiomeDictionary; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.EntityEntry; +import net.minecraftforge.fml.common.registry.EntityEntryBuilder; +import net.minecraftforge.fml.common.registry.ForgeRegistries; +import net.minecraftforge.registries.IForgeRegistry; + +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * Class responsible for registering all of wizardry's entities and their spawning conditions. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +@Mod.EventBusSubscriber +public class WizardryEntities { + + private WizardryEntities(){} // No instances! + + /** Most entity trackers fall into one of a few categories, so they are defined here for convenience. This + * generally follows the values used in vanilla for each entity type. */ + enum TrackingType { + + LIVING(80, 3, true), + PROJECTILE(64, 10, true), + CONSTRUCT(160, 10, false); + + int range; + int interval; + boolean trackVelocity; + + TrackingType(int range, int interval, boolean trackVelocity){ + this.range = range; + this.interval = interval; + this.trackVelocity = trackVelocity; + } + } + + /** Incrementing index for the mod-specific entity network ID. */ + private static int id = 0; + + @SubscribeEvent + public static void register(RegistryEvent.Register event){ + + IForgeRegistry registry = event.getRegistry(); + + // Vanilla summoned creatures + registry.register(createEntry(EntityZombieMinion.class, "zombie_minion", TrackingType.LIVING).build()); + registry.register(createEntry(EntityHuskMinion.class, "husk_minion", TrackingType.LIVING).build()); + registry.register(createEntry(EntitySkeletonMinion.class, "skeleton_minion", TrackingType.LIVING).build()); + registry.register(createEntry(EntityStrayMinion.class, "stray_minion", TrackingType.LIVING).build()); + registry.register(createEntry(EntitySpiderMinion.class, "spider_minion", TrackingType.LIVING).build()); + registry.register(createEntry(EntityBlazeMinion.class, "blaze_minion", TrackingType.LIVING).build()); + registry.register(createEntry(EntityWitherSkeletonMinion.class, "wither_skeleton_minion", TrackingType.LIVING).build()); + registry.register(createEntry(EntitySilverfishMinion.class, "silverfish_minion", TrackingType.LIVING).build()); + registry.register(createEntry(EntityVexMinion.class, "vex_minion", TrackingType.LIVING).build()); + + // Custom summoned creatures + registry.register(createEntry(EntityIceWraith.class, "ice_wraith", TrackingType.LIVING).egg(0xaafaff, 0x001ce1) + .spawn(EnumCreatureType.MONSTER, Wizardry.settings.iceWraithSpawnRate, 1, 1, ForgeRegistries.BIOMES.getValuesCollection().stream() + .filter(b -> !Arrays.asList(Wizardry.settings.mobSpawnBiomeBlacklist).contains(b.getRegistryName()) + && BiomeDictionary.hasType(b, BiomeDictionary.Type.SNOWY) + && !BiomeDictionary.hasType(b, BiomeDictionary.Type.FOREST)) + .collect(Collectors.toSet())).build()); + + registry.register(createEntry(EntityLightningWraith.class, "lightning_wraith", TrackingType.LIVING).egg(0x35424b, 0x27b9d9) + .spawn(EnumCreatureType.MONSTER, Wizardry.settings.lightningWraithSpawnRate, 1, 1, ForgeRegistries.BIOMES.getValuesCollection().stream() + .filter(b -> !Arrays.asList(Wizardry.settings.mobSpawnBiomeBlacklist).contains(b.getRegistryName())) + .collect(Collectors.toSet())).build()); + + registry.register(createEntry(EntitySpiritWolf.class, "spirit_wolf", TrackingType.LIVING).egg(0xbcc2e8, 0x5464c6).build()); + registry.register(createEntry(EntitySpiritHorse.class, "spirit_horse", TrackingType.LIVING).egg(0x5464c6, 0xbcc2e8).build()); + registry.register(createEntry(EntityPhoenix.class, "phoenix", TrackingType.LIVING).egg(0xff4900, 0xfde535).build()); + registry.register(createEntry(EntityIceGiant.class, "ice_giant", TrackingType.LIVING).egg(0x5bacd9, 0xeffaff).build()); + + registry.register(createEntry(EntityMagicSlime.class, "magic_slime", TrackingType.LIVING).build()); + registry.register(createEntry(EntityDecoy.class, "decoy", TrackingType.LIVING).build()); + + // These two are only made of particles, so we can afford a lower update frequency + registry.register(createEntry(EntityShadowWraith.class, "shadow_wraith") .tracker(80, 10, true).egg(0x11071c, 0x421384).build()); + registry.register(createEntry(EntityStormElemental.class, "storm_elemental") .tracker(80, 10, true).egg(0x162128, 0x135279).build()); + + // Other living entities + registry.register(createEntry(EntityWizard.class, "wizard", TrackingType.LIVING).egg(0x19295e, 0xee9312).build()); + registry.register(createEntry(EntityEvilWizard.class, "evil_wizard", TrackingType.LIVING).egg(0x290404, 0xee9312) + // For reference: 5, 1, 1 are the parameters for the witch in vanilla + .spawn(EnumCreatureType.MONSTER, Wizardry.settings.evilWizardSpawnRate, 1, 1, ForgeRegistries.BIOMES.getValuesCollection().stream() + .filter(b -> !Arrays.asList(Wizardry.settings.mobSpawnBiomeBlacklist).contains(b.getRegistryName())) + .collect(Collectors.toSet())).build()); + + // Directed projectiles + registry.register(createEntry(EntityMagicMissile.class, "magic_missile", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityIceShard.class, "ice_shard", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityLightningArrow.class, "lightning_arrow", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityForceArrow.class, "force_arrow", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityDart.class, "dart", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityIceLance.class, "ice_lance", TrackingType.PROJECTILE).build()); + + // Directionless projectiles + registry.register(createEntry(EntityFirebomb.class, "firebomb", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityPoisonBomb.class, "poison_bomb", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntitySparkBomb.class, "spark_bomb", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntitySmokeBomb.class, "smoke_bomb", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityIceCharge.class, "ice_charge", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityForceOrb.class, "force_orb", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntitySpark.class, "spark", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityDarknessOrb.class, "darkness_orb", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityFirebolt.class, "firebolt", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityThunderbolt.class, "thunderbolt", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityLightningDisc.class, "lightning_disc", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityEmber.class, "ember", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityMagicFireball.class, "magic_fireball", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityLargeMagicFireball.class, "large_magic_fireball", TrackingType.PROJECTILE).build()); + registry.register(createEntry(EntityIceball.class, "iceball", TrackingType.PROJECTILE).build()); + + // These are effectively projectiles, but since they're bigger and start high up they need updating from further away + registry.register(createEntry(EntityMeteor.class, "meteor") .tracker(160, 3, true).build()); + registry.register(createEntry(EntityHammer.class, "lightning_hammer") .tracker(160, 3, true).build()); + registry.register(createEntry(EntityLevitatingBlock.class, "levitating_block") .tracker(160, 3, true).build()); + + // Constructs + registry.register(createEntry(EntityBlackHole.class, "black_hole", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityBlizzard.class, "blizzard", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityForcefield.class, "forcefield", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityFireSigil.class, "fire_sigil", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityFrostSigil.class, "frost_sigil", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityLightningSigil.class, "lightning_sigil", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityCombustionRune.class, "combustion_rune", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityFireRing.class, "ring_of_fire", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityHealAura.class, "healing_aura", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityDecay.class, "decay", TrackingType.CONSTRUCT).build()); + + // These ones don't render, currently that makes no difference here but we might as well separate them + registry.register(createEntry(EntityArrowRain.class, "arrow_rain", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityEarthquake.class, "earthquake", TrackingType.CONSTRUCT).build()); + registry.register(createEntry(EntityHailstorm.class, "hailstorm", TrackingType.CONSTRUCT).build()); + + // These ones move, velocity updates are sent if that's not at constant velocity + registry.register(createEntry(EntityShield.class, "shield") .tracker(160, 10, true).build()); + registry.register(createEntry(EntityBubble.class, "bubble") .tracker(160, 3, false).build()); + registry.register(createEntry(EntityTornado.class, "tornado") .tracker(160, 3, false).build()); + registry.register(createEntry(EntityIceSpike.class, "ice_spike") .tracker(160, 1, true).build()); + + } + + /** + * Private helper method that simplifies the parts of an {@link EntityEntry} that are common to all entities. + * This automatically assigns a network id, and accepts a {@link TrackingType} for automatic tracker assignment. + * @param entityClass The entity class to use. + * @param name The name of the entity. This will form the path of a {@code ResourceLocation} with domain + * {@code ebwizardry}, which in turn will be used as both the registry name and the 'command' name. + * @param tracking The {@link TrackingType} to use for this entity. + * @param The type of entity. + * @return The (part-built) builder instance, allowing other builder methods to be added as necessary. + */ + private static EntityEntryBuilder createEntry(Class entityClass, String name, TrackingType tracking){ + return createEntry(entityClass, name).tracker(tracking.range, tracking.interval, tracking.trackVelocity); + } + + /** + * Private helper method that simplifies the parts of an {@link EntityEntry} that are common to all entities. + * This automatically assigns a network id. + * @param entityClass The entity class to use. + * @param name The name of the entity. This will form the path of a {@code ResourceLocation} with domain + * {@code ebwizardry}, which in turn will be used as both the registry name and the 'command' name. + * @param The type of entity. + * @return The (part-built) builder instance, allowing other builder methods to be added as necessary. + */ + private static EntityEntryBuilder createEntry(Class entityClass, String name){ + ResourceLocation registryName = new ResourceLocation(Wizardry.MODID, name); + return EntityEntryBuilder.create().entity(entityClass).id(registryName, id++).name(registryName.toString()); + } + +} diff --git a/src/main/java/electroblob/wizardry/registry/WizardryItems.java b/src/main/java/electroblob/wizardry/registry/WizardryItems.java index c43699a2..56777325 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryItems.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryItems.java @@ -1,47 +1,42 @@ package electroblob.wizardry.registry; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - -import com.google.common.collect.ImmutableMap; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.item.ItemArcaneTome; -import electroblob.wizardry.item.ItemArmourUpgrade; -import electroblob.wizardry.item.ItemBlankScroll; -import electroblob.wizardry.item.ItemFirebomb; -import electroblob.wizardry.item.ItemFlamingAxe; -import electroblob.wizardry.item.ItemFrostAxe; -import electroblob.wizardry.item.ItemIdentificationScroll; -import electroblob.wizardry.item.ItemPoisonBomb; -import electroblob.wizardry.item.ItemScroll; -import electroblob.wizardry.item.ItemSmokeBomb; -import electroblob.wizardry.item.ItemSpectralArmour; -import electroblob.wizardry.item.ItemSpectralBow; -import electroblob.wizardry.item.ItemSpectralPickaxe; -import electroblob.wizardry.item.ItemSpectralSword; -import electroblob.wizardry.item.ItemSpellBook; -import electroblob.wizardry.item.ItemWand; -import electroblob.wizardry.item.ItemWizardArmour; -import electroblob.wizardry.item.ItemWizardHandbook; +import electroblob.wizardry.entity.projectile.EntityFirebomb; +import electroblob.wizardry.entity.projectile.EntityPoisonBomb; +import electroblob.wizardry.entity.projectile.EntitySmokeBomb; +import electroblob.wizardry.entity.projectile.EntitySparkBomb; +import electroblob.wizardry.item.*; +import electroblob.wizardry.misc.BehaviourSpellDispense; +import electroblob.wizardry.registry.WizardryTabs.CreativeTabListed; +import electroblob.wizardry.registry.WizardryTabs.CreativeTabSorted; import net.minecraft.block.Block; -import net.minecraft.init.SoundEvents; +import net.minecraft.block.BlockDispenser; +import net.minecraft.dispenser.BehaviorProjectileDispense; +import net.minecraft.dispenser.IPosition; +import net.minecraft.entity.IProjectile; import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.inventory.EntityEquipmentSlot.Type; +import net.minecraft.item.EnumRarity; import net.minecraft.item.Item; import net.minecraft.item.Item.ToolMaterial; import net.minecraft.item.ItemArmor.ArmorMaterial; import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; import net.minecraftforge.common.util.EnumHelper; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; import net.minecraftforge.registries.IForgeRegistry; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.Map; /** * Class responsible for defining, storing and registering all of wizardry's items. Also registers the ItemBlocks for @@ -53,7 +48,9 @@ import net.minecraftforge.registries.IForgeRegistry; @ObjectHolder(Wizardry.MODID) @Mod.EventBusSubscriber public final class WizardryItems { - + + private WizardryItems(){} // No instances! + /** Keeping the material fields in here means {@code @ObjectHolder} ignores them. In actual fact, I could have just * made them private since wizardry only uses them within this class, but in case someone needs them elsewhere I've * used this trick instead to keep them public. */ @@ -62,223 +59,228 @@ public final class WizardryItems { public static final ToolMaterial MAGICAL = EnumHelper.addToolMaterial("MAGICAL", 3, 1000, 8.0f, 4.0f, 0); public static final ArmorMaterial SILK = EnumHelper.addArmorMaterial("SILK", "wizardry/textures/armour/wizard_armour", - 15, new int[]{0, 0, 0, 0}, 0, WizardrySounds.ITEM_ARMOUR_EQUIP_SILK, 0.0F); + 15, new int[]{0, 0, 0, 0}, 15, WizardrySounds.ITEM_ARMOUR_EQUIP_SILK, 0.0F); } + + @Nonnull + @SuppressWarnings("ConstantConditions") + private static T placeholder(){ return null; } // This is the most concise way I can think of to register the items. Really, I'd prefer it if there was only one // point where all the items were listed, but that's not possible within the current system unless you use an array, // which means you lose the individual fields... - public static final Item magic_crystal = null; + public static final Item magic_crystal = placeholder(); - public static final Item magic_wand = null; - public static final Item apprentice_wand = null; - public static final Item advanced_wand = null; - public static final Item master_wand = null; + public static final Item grand_crystal = placeholder(); + public static final Item crystal_shard = placeholder(); - public static final Item arcane_tome = null; - public static final Item wizard_handbook = null; - public static final Item spell_book = null; + public static final Item wizard_handbook = placeholder(); + public static final Item arcane_tome = placeholder(); + public static final Item spell_book = placeholder(); + public static final Item scroll = placeholder(); - public static final Item basic_fire_wand = null; - public static final Item basic_ice_wand = null; - public static final Item basic_lightning_wand = null; - public static final Item basic_necromancy_wand = null; - public static final Item basic_earth_wand = null; - public static final Item basic_sorcery_wand = null; - public static final Item basic_healing_wand = null; + public static final Item magic_wand = placeholder(); + public static final Item apprentice_wand = placeholder(); + public static final Item advanced_wand = placeholder(); + public static final Item master_wand = placeholder(); - public static final Item apprentice_fire_wand = null; - public static final Item apprentice_ice_wand = null; - public static final Item apprentice_lightning_wand = null; - public static final Item apprentice_necromancy_wand = null; - public static final Item apprentice_earth_wand = null; - public static final Item apprentice_sorcery_wand = null; - public static final Item apprentice_healing_wand = null; + public static final Item novice_fire_wand = placeholder(); + public static final Item novice_ice_wand = placeholder(); + public static final Item novice_lightning_wand = placeholder(); + public static final Item novice_necromancy_wand = placeholder(); + public static final Item novice_earth_wand = placeholder(); + public static final Item novice_sorcery_wand = placeholder(); + public static final Item novice_healing_wand = placeholder(); - public static final Item advanced_fire_wand = null; - public static final Item advanced_ice_wand = null; - public static final Item advanced_lightning_wand = null; - public static final Item advanced_necromancy_wand = null; - public static final Item advanced_earth_wand = null; - public static final Item advanced_sorcery_wand = null; - public static final Item advanced_healing_wand = null; + public static final Item apprentice_fire_wand = placeholder(); + public static final Item apprentice_ice_wand = placeholder(); + public static final Item apprentice_lightning_wand = placeholder(); + public static final Item apprentice_necromancy_wand = placeholder(); + public static final Item apprentice_earth_wand = placeholder(); + public static final Item apprentice_sorcery_wand = placeholder(); + public static final Item apprentice_healing_wand = placeholder(); - public static final Item master_fire_wand = null; - public static final Item master_ice_wand = null; - public static final Item master_lightning_wand = null; - public static final Item master_necromancy_wand = null; - public static final Item master_earth_wand = null; - public static final Item master_sorcery_wand = null; - public static final Item master_healing_wand = null; + public static final Item advanced_fire_wand = placeholder(); + public static final Item advanced_ice_wand = placeholder(); + public static final Item advanced_lightning_wand = placeholder(); + public static final Item advanced_necromancy_wand = placeholder(); + public static final Item advanced_earth_wand = placeholder(); + public static final Item advanced_sorcery_wand = placeholder(); + public static final Item advanced_healing_wand = placeholder(); - public static final Item spectral_sword = null; - public static final Item spectral_pickaxe = null; - public static final Item spectral_bow = null; + public static final Item master_fire_wand = placeholder(); + public static final Item master_ice_wand = placeholder(); + public static final Item master_lightning_wand = placeholder(); + public static final Item master_necromancy_wand = placeholder(); + public static final Item master_earth_wand = placeholder(); + public static final Item master_sorcery_wand = placeholder(); + public static final Item master_healing_wand = placeholder(); - public static final Item medium_mana_flask = null; + public static final Item spectral_sword = placeholder(); + public static final Item spectral_pickaxe = placeholder(); + public static final Item spectral_bow = placeholder(); - public static final Item storage_upgrade = null; - public static final Item siphon_upgrade = null; - public static final Item condenser_upgrade = null; - public static final Item range_upgrade = null; - public static final Item duration_upgrade = null; - public static final Item cooldown_upgrade = null; - public static final Item blast_upgrade = null; - public static final Item attunement_upgrade = null; + public static final Item blank_scroll = placeholder(); + public static final Item magic_silk = placeholder(); - public static final Item magic_silk = null; + public static final Item small_mana_flask = placeholder(); + public static final Item medium_mana_flask = placeholder(); + public static final Item large_mana_flask = placeholder(); - public static final Item flaming_axe = null; - public static final Item frost_axe = null; + public static final Item storage_upgrade = placeholder(); + public static final Item siphon_upgrade = placeholder(); + public static final Item condenser_upgrade = placeholder(); + public static final Item range_upgrade = placeholder(); + public static final Item duration_upgrade = placeholder(); + public static final Item cooldown_upgrade = placeholder(); + public static final Item blast_upgrade = placeholder(); + public static final Item attunement_upgrade = placeholder(); + public static final Item melee_upgrade = placeholder(); - public static final Item firebomb = null; - public static final Item poison_bomb = null; + public static final Item flaming_axe = placeholder(); + public static final Item frost_axe = placeholder(); - public static final Item blank_scroll = null; - public static final Item scroll = null; - - public static final Item armour_upgrade = null; - - public static final Item wizard_hat = null; - public static final Item wizard_robe = null; - public static final Item wizard_leggings = null; - public static final Item wizard_boots = null; + public static final Item identification_scroll = placeholder(); + public static final Item armour_upgrade = placeholder(); + public static final Item astral_diamond = placeholder(); + public static final Item purifying_elixir = placeholder(); - public static final Item wizard_hat_fire = null; - public static final Item wizard_robe_fire = null; - public static final Item wizard_leggings_fire = null; - public static final Item wizard_boots_fire = null; + public static final Item firebomb = placeholder(); + public static final Item poison_bomb = placeholder(); + public static final Item smoke_bomb = placeholder(); + public static final Item spark_bomb = placeholder(); - public static final Item wizard_hat_ice = null; - public static final Item wizard_robe_ice = null; - public static final Item wizard_leggings_ice = null; - public static final Item wizard_boots_ice = null; + public static final Item wizard_hat = placeholder(); + public static final Item wizard_robe = placeholder(); + public static final Item wizard_leggings = placeholder(); + public static final Item wizard_boots = placeholder(); - public static final Item wizard_hat_lightning = null; - public static final Item wizard_robe_lightning = null; - public static final Item wizard_leggings_lightning = null; - public static final Item wizard_boots_lightning = null; + public static final Item wizard_hat_fire = placeholder(); + public static final Item wizard_robe_fire = placeholder(); + public static final Item wizard_leggings_fire = placeholder(); + public static final Item wizard_boots_fire = placeholder(); - public static final Item wizard_hat_necromancy = null; - public static final Item wizard_robe_necromancy = null; - public static final Item wizard_leggings_necromancy = null; - public static final Item wizard_boots_necromancy = null; + public static final Item wizard_hat_ice = placeholder(); + public static final Item wizard_robe_ice = placeholder(); + public static final Item wizard_leggings_ice = placeholder(); + public static final Item wizard_boots_ice = placeholder(); - public static final Item wizard_hat_earth = null; - public static final Item wizard_robe_earth = null; - public static final Item wizard_leggings_earth = null; - public static final Item wizard_boots_earth = null; + public static final Item wizard_hat_lightning = placeholder(); + public static final Item wizard_robe_lightning = placeholder(); + public static final Item wizard_leggings_lightning = placeholder(); + public static final Item wizard_boots_lightning = placeholder(); - public static final Item wizard_hat_sorcery = null; - public static final Item wizard_robe_sorcery = null; - public static final Item wizard_leggings_sorcery = null; - public static final Item wizard_boots_sorcery = null; + public static final Item wizard_hat_necromancy = placeholder(); + public static final Item wizard_robe_necromancy = placeholder(); + public static final Item wizard_leggings_necromancy = placeholder(); + public static final Item wizard_boots_necromancy = placeholder(); - public static final Item wizard_hat_healing = null; - public static final Item wizard_robe_healing = null; - public static final Item wizard_leggings_healing = null; - public static final Item wizard_boots_healing = null; + public static final Item wizard_hat_earth = placeholder(); + public static final Item wizard_robe_earth = placeholder(); + public static final Item wizard_leggings_earth = placeholder(); + public static final Item wizard_boots_earth = placeholder(); - public static final Item spectral_helmet = null; - public static final Item spectral_chestplate = null; - public static final Item spectral_leggings = null; - public static final Item spectral_boots = null; - - public static final Item smoke_bomb = null; + public static final Item wizard_hat_sorcery = placeholder(); + public static final Item wizard_robe_sorcery = placeholder(); + public static final Item wizard_leggings_sorcery = placeholder(); + public static final Item wizard_boots_sorcery = placeholder(); - public static final Item identification_scroll = null; + public static final Item wizard_hat_healing = placeholder(); + public static final Item wizard_robe_healing = placeholder(); + public static final Item wizard_leggings_healing = placeholder(); + public static final Item wizard_boots_healing = placeholder(); + + public static final Item spectral_helmet = placeholder(); + public static final Item spectral_chestplate = placeholder(); + public static final Item spectral_leggings = placeholder(); + public static final Item spectral_boots = placeholder(); + + public static final Item lightning_hammer = placeholder(); + + public static final Item ring_condensing = placeholder(); + public static final Item ring_siphoning = placeholder(); + public static final Item ring_battlemage = placeholder(); + public static final Item ring_combustion = placeholder(); + public static final Item ring_fire_melee = placeholder(); + public static final Item ring_fire_biome = placeholder(); + public static final Item ring_disintegration = placeholder(); + public static final Item ring_ice_melee = placeholder(); + public static final Item ring_ice_biome = placeholder(); + public static final Item ring_arcane_frost = placeholder(); + public static final Item ring_shattering = placeholder(); + public static final Item ring_lightning_melee = placeholder(); + public static final Item ring_storm = placeholder(); + public static final Item ring_seeking = placeholder(); + public static final Item ring_hammer = placeholder(); + public static final Item ring_soulbinding = placeholder(); + public static final Item ring_leeching = placeholder(); + public static final Item ring_necromancy_melee = placeholder(); + public static final Item ring_mind_control = placeholder(); + public static final Item ring_poison = placeholder(); + public static final Item ring_earth_melee = placeholder(); + public static final Item ring_earth_biome = placeholder(); + public static final Item ring_full_moon = placeholder(); + public static final Item ring_extraction = placeholder(); + public static final Item ring_mana_return = placeholder(); + public static final Item ring_blockwrangler = placeholder(); + public static final Item ring_conjurer = placeholder(); + public static final Item ring_defender = placeholder(); + public static final Item ring_paladin = placeholder(); + public static final Item ring_interdiction = placeholder(); + + public static final Item amulet_arcane_defence = placeholder(); + public static final Item amulet_warding = placeholder(); + public static final Item amulet_wisdom = placeholder(); + public static final Item amulet_fire_protection = placeholder(); + public static final Item amulet_fire_cloaking = placeholder(); + public static final Item amulet_ice_immunity = placeholder(); + public static final Item amulet_ice_protection = placeholder(); + public static final Item amulet_potential = placeholder(); + public static final Item amulet_channeling = placeholder(); + public static final Item amulet_lich = placeholder(); + public static final Item amulet_wither_immunity = placeholder(); + public static final Item amulet_glide = placeholder(); + public static final Item amulet_banishing = placeholder(); + public static final Item amulet_anchoring = placeholder(); + public static final Item amulet_recovery = placeholder(); + public static final Item amulet_transience = placeholder(); + public static final Item amulet_resurrection = placeholder(); + public static final Item amulet_auto_shield = placeholder(); + + public static final Item charm_haggler = placeholder(); + public static final Item charm_experience_tome = placeholder(); + public static final Item charm_auto_smelt = placeholder(); + public static final Item charm_lava_walking = placeholder(); + public static final Item charm_storm = placeholder(); + public static final Item charm_minion_health = placeholder(); + public static final Item charm_minion_variants = placeholder(); + public static final Item charm_flight = placeholder(); + public static final Item charm_growth = placeholder(); + public static final Item charm_abseiling = placeholder(); + public static final Item charm_silk_touch = placeholder(); + public static final Item charm_stop_time = placeholder(); + public static final Item charm_light = placeholder(); + public static final Item charm_transportation = placeholder(); + public static final Item charm_feeding = placeholder(); private static final Map, Item> WAND_MAP = new HashMap<>(); private static final Map, Item> ARMOUR_MAP = new HashMap<>(); - static { - - WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.MAGIC), magic_wand); - WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.FIRE), basic_fire_wand); - WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.ICE), basic_ice_wand); - WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.LIGHTNING), basic_lightning_wand); - WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.NECROMANCY), basic_necromancy_wand); - WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.EARTH), basic_earth_wand); - WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.SORCERY), basic_sorcery_wand); - WAND_MAP.put(ImmutablePair.of(Tier.BASIC, Element.HEALING), basic_healing_wand); - WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.MAGIC), apprentice_wand); - WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.FIRE), apprentice_fire_wand); - WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.ICE), apprentice_ice_wand); - WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.LIGHTNING), apprentice_lightning_wand); - WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.NECROMANCY), apprentice_necromancy_wand); - WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.EARTH), apprentice_earth_wand); - WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.SORCERY), apprentice_sorcery_wand); - WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.HEALING), apprentice_healing_wand); - WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.MAGIC), advanced_wand); - WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.FIRE), advanced_fire_wand); - WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.ICE), advanced_ice_wand); - WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.LIGHTNING), advanced_lightning_wand); - WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.NECROMANCY), advanced_necromancy_wand); - WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.EARTH), advanced_earth_wand); - WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.SORCERY), advanced_sorcery_wand); - WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.HEALING), advanced_healing_wand); - WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.MAGIC), master_wand); - WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.FIRE), master_fire_wand); - WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.ICE), master_ice_wand); - WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.LIGHTNING), master_lightning_wand); - WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.NECROMANCY), master_necromancy_wand); - WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.EARTH), master_earth_wand); - WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.SORCERY), master_sorcery_wand); - WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.HEALING), master_healing_wand); - - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.MAGIC), wizard_hat); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.FIRE), wizard_hat_fire); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.ICE), wizard_hat_ice); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.LIGHTNING), wizard_hat_lightning); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.NECROMANCY), wizard_hat_necromancy); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.EARTH), wizard_hat_earth); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.SORCERY), wizard_hat_sorcery); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.HEALING), wizard_hat_healing); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.MAGIC), wizard_robe); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.FIRE), wizard_robe_fire); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.ICE), wizard_robe_ice); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.LIGHTNING), wizard_robe_lightning); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.NECROMANCY), wizard_robe_necromancy); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.EARTH), wizard_robe_earth); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.SORCERY), wizard_robe_sorcery); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.HEALING), wizard_robe_healing); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.MAGIC), wizard_leggings); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.FIRE), wizard_leggings_fire); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.ICE), wizard_leggings_ice); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.LIGHTNING), wizard_leggings_lightning); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.NECROMANCY), wizard_leggings_necromancy); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.EARTH), wizard_leggings_earth); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.SORCERY), wizard_leggings_sorcery); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.HEALING), wizard_leggings_healing); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.MAGIC), wizard_boots); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.FIRE), wizard_boots_fire); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.ICE), wizard_boots_ice); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.LIGHTNING), wizard_boots_lightning); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.NECROMANCY), wizard_boots_necromancy); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.EARTH), wizard_boots_earth); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.SORCERY), wizard_boots_sorcery); - ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.HEALING), wizard_boots_healing); - } - - // TODO: These methods need a rethink. What are we trying to achieve with them? Should each use case look in the - // same pool of items? For example, might we (or someone else) want to have a wand which can generate in chests, but - // is not used by wizards? - - // I reckon this should be strictly for cases where we only ever want the standard wand set, i.e. wizards' gear, - // etc. - /** * Helper method to return the appropriate wand based on tier and element. As of Wizardry 2.1, this uses the * immutable map stored in {@link WizardryItems#WAND_MAP}. Currently used for upgrading wands, for chest generation * and to iterate through wands for charging recipes. - * + * * @param tier The tier of the wand required. * @param element The element of the wand required. Null will be converted to {@link Element#MAGIC}. - * @return The wand item which corresponds to the given element and slot, or null if no such item exists. + * @return The wand item which corresponds to the given tier and element, or null if no such item exists. * @throws NullPointerException if the given tier is null. + * @deprecated This is being phased out; it is now only used for wizard gear and trades. To add an item to + * charging recipes, use {@link WizardryRecipes#addToManaFlaskCharging(Item)}. */ + @Deprecated public static Item getWand(Tier tier, Element element){ if(tier == null) throw new NullPointerException("The given tier cannot be null."); if(element == null) element = Element.MAGIC; @@ -289,26 +291,29 @@ public final class WizardryItems { * Helper method to return the appropriate armour item based on element and slot. As of Wizardry 2.1, this uses the * immutable map stored in {@link WizardryItems#ARMOUR_MAP}. Currently used to iterate through armour for * registering charging recipes and for chest generation. - * + * * @param element The EnumElement of the armour required. Null will be converted to {@link Element#MAGIC}. * @param slot EntityEquipmentSlot of the armour piece required * @return The armour item which corresponds to the given element and slot, or null if no such item exists. * @throws IllegalArgumentException if the given slot is not an armour slot. + * @deprecated This is being phased out; it is now only used for wizard gear and trades. To add an item to + * charging recipes, use {@link WizardryRecipes#addToManaFlaskCharging(Item)}. */ + @Deprecated public static Item getArmour(Element element, EntityEquipmentSlot slot){ if(slot == null || slot.getSlotType() != Type.ARMOR) throw new IllegalArgumentException("Must be a valid armour slot"); if(element == null) element = Element.MAGIC; return ARMOUR_MAP.get(ImmutablePair.of(slot, element)); } - + /** * Sets both the registry and unlocalised names of the given item, then registers it with the given registry. Use - * this instead of {@link Item#setRegistryName(String)} and {@link Item#setUnlocalizedName(String)} during + * this instead of {@link Item#setRegistryName(String)} and {@link Item#setTranslationKey(String)} during * construction, for convenience and consistency. As of wizardry 4.2, this also automatically adds it to the order * list for its creative tab if that tab is a {@link CreativeTabListed}, meaning the order can be defined simply * by the order in which the items are registered in this class. - * + * * @param registry The registry to register the given item to. * @param name The name of the item, without the mod ID or the .name stuff. The registry name will be * {@code ebwizardry:[name]}. The unlocalised name will be {@code item.ebwizardry:[name].name}. @@ -321,11 +326,11 @@ public final class WizardryItems { /** * Sets both the registry and unlocalised names of the given item, then registers it with the given registry. Use - * this instead of {@link Item#setRegistryName(String)} and {@link Item#setUnlocalizedName(String)} during + * this instead of {@link Item#setRegistryName(String)} and {@link Item#setTranslationKey(String)} during * construction, for convenience and consistency. As of wizardry 4.2, this also automatically adds it to the order * list for its creative tab if that tab is a {@link CreativeTabListed}, meaning the order can be defined simply * by the order in which the items are registered in this class. - * + * * @param registry The registry to register the given item to. * @param name The name of the item, without the mod ID or the .name stuff. The registry name will be * {@code ebwizardry:[name]}. The unlocalised name will be {@code item.ebwizardry:[name].name}. @@ -334,6 +339,7 @@ public final class WizardryItems { */ // It now makes sense to have the name first, since it's shorter than an entire item declaration. public static void registerItem(IForgeRegistry registry, String name, Item item, boolean setTabIcon){ + item.setRegistryName(Wizardry.MODID, name); item.setTranslationKey(item.getRegistryName().toString()); registry.register(item); @@ -341,7 +347,7 @@ public final class WizardryItems { if(setTabIcon && item.getCreativeTab() instanceof CreativeTabSorted){ ((CreativeTabSorted)item.getCreativeTab()).setIconItem(new ItemStack(item)); } - + if(item.getCreativeTab() instanceof CreativeTabListed){ ((CreativeTabListed)item.getCreativeTab()).order.add(item); } @@ -354,15 +360,26 @@ public final class WizardryItems { // We don't need to keep a reference to the ItemBlock Item itemblock = new ItemBlock(block).setRegistryName(block.getRegistryName()); registry.register(itemblock); - - if(block.getCreativeTabToDisplayOn() instanceof CreativeTabListed){ - ((CreativeTabListed)block.getCreativeTabToDisplayOn()).order.add(itemblock); + + if(block.getCreativeTab() instanceof CreativeTabListed){ + ((CreativeTabListed)block.getCreativeTab()).order.add(itemblock); } } + + private static void registerMultiTexturedItemBlock(IForgeRegistry registry, Block block, boolean separateNames){ + // We don't need to keep a reference to the ItemBlock + Item itemblock = new ItemBlockMultiTexturedElemental(block, separateNames).setRegistryName(block.getRegistryName()); + registry.register(itemblock); + + if(block.getCreativeTab() instanceof CreativeTabListed){ + ((CreativeTabListed)block.getCreativeTab()).order.add(itemblock); + } } + @SubscribeEvent public static void register(RegistryEvent.Register event){ + IForgeRegistry registry = event.getRegistry(); // ItemBlocks @@ -372,52 +389,58 @@ public final class WizardryItems { registerItemBlock(registry, WizardryBlocks.crystal_ore); registerItemBlock(registry, WizardryBlocks.crystal_flower); registerItemBlock(registry, WizardryBlocks.transportation_stone); - registerItemBlock(registry, WizardryBlocks.crystal_block); + registerMultiTexturedItemBlock(registry, WizardryBlocks.crystal_block, true); + registerMultiTexturedItemBlock(registry, WizardryBlocks.runestone, false); + registerMultiTexturedItemBlock(registry, WizardryBlocks.runestone_pedestal, false); // Items - + registerItem(registry, "magic_crystal", new ItemCrystal()); - registerItem(registry, "magic_wand", new ItemWand(Tier.BASIC, null)); + registerItem(registry, "crystal_shard", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "grand_crystal", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + + registerItem(registry, "wizard_handbook", new ItemWizardHandbook(), true); + registerItem(registry, "arcane_tome", new ItemArcaneTome()); + registerItem(registry, "spell_book", new ItemSpellBook(), true); + registerItem(registry, "scroll", new ItemScroll()); + + registerItem(registry, "magic_wand", new ItemWand(Tier.NOVICE, null)); registerItem(registry, "apprentice_wand", new ItemWand(Tier.APPRENTICE, null)); registerItem(registry, "advanced_wand", new ItemWand(Tier.ADVANCED, null)); registerItem(registry, "master_wand", new ItemWand(Tier.MASTER, null)); - registerItem(registry, "arcane_tome", new ItemArcaneTome()); - registerItem(registry, "wizard_handbook", new ItemWizardHandbook(), true); - registerItem(registry, "spell_book", new ItemSpellBook(), true); - - registerItem(registry, "basic_fire_wand", new ItemWand(Tier.BASIC, Element.FIRE)); + registerItem(registry, "novice_fire_wand", new ItemWand(Tier.NOVICE, Element.FIRE)); registerItem(registry, "apprentice_fire_wand", new ItemWand(Tier.APPRENTICE, Element.FIRE)); registerItem(registry, "advanced_fire_wand", new ItemWand(Tier.ADVANCED, Element.FIRE)); registerItem(registry, "master_fire_wand", new ItemWand(Tier.MASTER, Element.FIRE)); - - registerItem(registry, "basic_ice_wand", new ItemWand(Tier.BASIC, Element.ICE)); + + registerItem(registry, "novice_ice_wand", new ItemWand(Tier.NOVICE, Element.ICE)); registerItem(registry, "apprentice_ice_wand", new ItemWand(Tier.APPRENTICE, Element.ICE)); registerItem(registry, "advanced_ice_wand", new ItemWand(Tier.ADVANCED, Element.ICE)); registerItem(registry, "master_ice_wand", new ItemWand(Tier.MASTER, Element.ICE)); - - registerItem(registry, "basic_lightning_wand", new ItemWand(Tier.BASIC, Element.LIGHTNING)); + + registerItem(registry, "novice_lightning_wand", new ItemWand(Tier.NOVICE, Element.LIGHTNING)); registerItem(registry, "apprentice_lightning_wand", new ItemWand(Tier.APPRENTICE, Element.LIGHTNING)); registerItem(registry, "advanced_lightning_wand", new ItemWand(Tier.ADVANCED, Element.LIGHTNING)); registerItem(registry, "master_lightning_wand", new ItemWand(Tier.MASTER, Element.LIGHTNING)); - - registerItem(registry, "basic_necromancy_wand", new ItemWand(Tier.BASIC, Element.NECROMANCY)); + + registerItem(registry, "novice_necromancy_wand", new ItemWand(Tier.NOVICE, Element.NECROMANCY)); registerItem(registry, "apprentice_necromancy_wand", new ItemWand(Tier.APPRENTICE, Element.NECROMANCY)); registerItem(registry, "advanced_necromancy_wand", new ItemWand(Tier.ADVANCED, Element.NECROMANCY)); registerItem(registry, "master_necromancy_wand", new ItemWand(Tier.MASTER, Element.NECROMANCY)); - - registerItem(registry, "basic_earth_wand", new ItemWand(Tier.BASIC, Element.EARTH)); + + registerItem(registry, "novice_earth_wand", new ItemWand(Tier.NOVICE, Element.EARTH)); registerItem(registry, "apprentice_earth_wand", new ItemWand(Tier.APPRENTICE, Element.EARTH)); registerItem(registry, "advanced_earth_wand", new ItemWand(Tier.ADVANCED, Element.EARTH)); registerItem(registry, "master_earth_wand", new ItemWand(Tier.MASTER, Element.EARTH)); - - registerItem(registry, "basic_sorcery_wand", new ItemWand(Tier.BASIC, Element.SORCERY)); + + registerItem(registry, "novice_sorcery_wand", new ItemWand(Tier.NOVICE, Element.SORCERY)); registerItem(registry, "apprentice_sorcery_wand", new ItemWand(Tier.APPRENTICE, Element.SORCERY)); registerItem(registry, "advanced_sorcery_wand", new ItemWand(Tier.ADVANCED, Element.SORCERY)); registerItem(registry, "master_sorcery_wand", new ItemWand(Tier.MASTER, Element.SORCERY)); - - registerItem(registry, "basic_healing_wand", new ItemWand(Tier.BASIC, Element.HEALING)); + + registerItem(registry, "novice_healing_wand", new ItemWand(Tier.NOVICE, Element.HEALING)); registerItem(registry, "apprentice_healing_wand", new ItemWand(Tier.APPRENTICE, Element.HEALING)); registerItem(registry, "advanced_healing_wand", new ItemWand(Tier.ADVANCED, Element.HEALING)); registerItem(registry, "master_healing_wand", new ItemWand(Tier.MASTER, Element.HEALING)); @@ -426,31 +449,35 @@ public final class WizardryItems { registerItem(registry, "spectral_pickaxe", new ItemSpectralPickaxe(ToolMaterial.IRON)); registerItem(registry, "spectral_bow", new ItemSpectralBow()); - registerItem(registry, "medium_mana_flask", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - - registerItem(registry, "storage_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, "siphon_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, "condenser_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, "range_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, "duration_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, "cooldown_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, "blast_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - registerItem(registry, "attunement_upgrade", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); - + registerItem(registry, "blank_scroll", new ItemBlankScroll()); registerItem(registry, "magic_silk", new Item().setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "small_mana_flask", new ItemManaFlask(ItemManaFlask.Size.SMALL)); + registerItem(registry, "medium_mana_flask", new ItemManaFlask(ItemManaFlask.Size.MEDIUM)); + registerItem(registry, "large_mana_flask", new ItemManaFlask(ItemManaFlask.Size.LARGE)); + + registerItem(registry, "storage_upgrade", new ItemWandUpgrade()); + registerItem(registry, "siphon_upgrade", new ItemWandUpgrade()); + registerItem(registry, "condenser_upgrade", new ItemWandUpgrade()); + registerItem(registry, "range_upgrade", new ItemWandUpgrade()); + registerItem(registry, "duration_upgrade", new ItemWandUpgrade()); + registerItem(registry, "cooldown_upgrade", new ItemWandUpgrade()); + registerItem(registry, "blast_upgrade", new ItemWandUpgrade()); + registerItem(registry, "attunement_upgrade", new ItemWandUpgrade()); + registerItem(registry, "melee_upgrade", new ItemWandUpgrade()); + registerItem(registry, "flaming_axe", new ItemFlamingAxe(Materials.MAGICAL)); registerItem(registry, "frost_axe", new ItemFrostAxe(Materials.MAGICAL)); + registerItem(registry, "identification_scroll", new ItemIdentificationScroll()); + registerItem(registry, "armour_upgrade", new ItemArmourUpgrade()); + registerItem(registry, "astral_diamond", new Item(){ @Override public EnumRarity getRarity(ItemStack stack){ return EnumRarity.RARE; }}.setCreativeTab(WizardryTabs.WIZARDRY)); + registerItem(registry, "purifying_elixir", new ItemPurifyingElixir()); + registerItem(registry, "firebomb", new ItemFirebomb()); registerItem(registry, "poison_bomb", new ItemPoisonBomb()); - - registerItem(registry, "blank_scroll", new ItemBlankScroll()); - registerItem(registry, "scroll", new ItemScroll()); - - // The only way to get these is in dungeon chests (They are legendary, after all. Wizards don't just have them. - // Also if they were sold you could buy four from the same wizard - and that's no fun at all!) - registerItem(registry, "armour_upgrade", new ItemArmourUpgrade()); + registerItem(registry, "smoke_bomb", new ItemSmokeBomb()); + registerItem(registry, "spark_bomb", new ItemSparkBomb()); registerItem(registry, "wizard_hat", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, null), true); registerItem(registry, "wizard_robe", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, null)); @@ -496,13 +523,198 @@ public final class WizardryItems { registerItem(registry, "spectral_chestplate", new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.CHEST)); registerItem(registry, "spectral_leggings", new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.LEGS)); registerItem(registry, "spectral_boots", new ItemSpectralArmour(ArmorMaterial.IRON, 1, EntityEquipmentSlot.FEET)); - - registerItem(registry, "smoke_bomb", new ItemSmokeBomb()); - registerItem(registry, "identification_scroll", new ItemIdentificationScroll()); - - registerItem(registry, "test_artefact", new ItemArtefact(EnumRarity.UNCOMMON)); + registerItem(registry, "lightning_hammer", new ItemLightningHammer()); + + registerItem(registry, "ring_condensing", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_siphoning", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_battlemage", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_combustion", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.RING)); + registerItem(registry, "ring_fire_melee", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_fire_biome", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_disintegration", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_ice_melee", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_ice_biome", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_arcane_frost", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.RING)); + registerItem(registry, "ring_shattering", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_lightning_melee", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_storm", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_seeking", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.RING)); + registerItem(registry, "ring_hammer", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.RING)); + registerItem(registry, "ring_soulbinding", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.RING)); + registerItem(registry, "ring_leeching", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_necromancy_melee", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_mind_control", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_poison", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_earth_melee", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_earth_biome", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_full_moon", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_extraction", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_mana_return", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.RING)); + registerItem(registry, "ring_blockwrangler", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_conjurer", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_defender", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.RING)); + registerItem(registry, "ring_paladin", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.RING)); + registerItem(registry, "ring_interdiction", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.RING)); + + registerItem(registry, "amulet_arcane_defence", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_warding", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_wisdom", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_fire_protection", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_fire_cloaking", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_ice_immunity", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_ice_protection", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_potential", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_channeling", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_lich", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_wither_immunity", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_glide", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_banishing", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_anchoring", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_recovery", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_transience", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_resurrection", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.AMULET)); + registerItem(registry, "amulet_auto_shield", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.AMULET)); + + registerItem(registry, "charm_haggler", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_experience_tome", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_auto_smelt", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_lava_walking", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_storm", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_minion_health", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_minion_variants", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_flight", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_growth", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_abseiling", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_silk_touch", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_stop_time", new ItemArtefact(EnumRarity.EPIC, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_light", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_transportation", new ItemArtefact(EnumRarity.RARE, ItemArtefact.Type.CHARM)); + registerItem(registry, "charm_feeding", new ItemArtefact(EnumRarity.UNCOMMON, ItemArtefact.Type.CHARM)); + } + + /** Called from init() in the main mod class to register wizardry's dispenser behaviours. */ + public static void registerDispenseBehaviours(){ + + BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(firebomb, new BehaviorProjectileDispense(){ + + @Override + protected IProjectile getProjectileEntity(World world, IPosition position, ItemStack stack){ + EntityFirebomb entity = new EntityFirebomb(world); + entity.setPosition(position.getX(), position.getY(), position.getZ()); + return entity; + } + + }); + + BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(poison_bomb, new BehaviorProjectileDispense(){ + + @Override + protected IProjectile getProjectileEntity(World world, IPosition position, ItemStack stack){ + EntityPoisonBomb entity = new EntityPoisonBomb(world); + entity.setPosition(position.getX(), position.getY(), position.getZ()); + return entity; + } + + }); + + BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(smoke_bomb, new BehaviorProjectileDispense(){ + + @Override + protected IProjectile getProjectileEntity(World world, IPosition position, ItemStack stack){ + EntitySmokeBomb entity = new EntitySmokeBomb(world); + entity.setPosition(position.getX(), position.getY(), position.getZ()); + return entity; + } + + }); + + BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(spark_bomb, new BehaviorProjectileDispense(){ + + @Override + protected IProjectile getProjectileEntity(World world, IPosition position, ItemStack stack){ + EntitySparkBomb entity = new EntitySparkBomb(world); + entity.setPosition(position.getX(), position.getY(), position.getZ()); + return entity; + } + + }); + + BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(scroll, new BehaviourSpellDispense()); + + } + + public static void populateWandMap(){ + + WAND_MAP.put(ImmutablePair.of(Tier.NOVICE, Element.MAGIC), magic_wand); + WAND_MAP.put(ImmutablePair.of(Tier.NOVICE, Element.FIRE), novice_fire_wand); + WAND_MAP.put(ImmutablePair.of(Tier.NOVICE, Element.ICE), novice_ice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.NOVICE, Element.LIGHTNING), novice_lightning_wand); + WAND_MAP.put(ImmutablePair.of(Tier.NOVICE, Element.NECROMANCY), novice_necromancy_wand); + WAND_MAP.put(ImmutablePair.of(Tier.NOVICE, Element.EARTH), novice_earth_wand); + WAND_MAP.put(ImmutablePair.of(Tier.NOVICE, Element.SORCERY), novice_sorcery_wand); + WAND_MAP.put(ImmutablePair.of(Tier.NOVICE, Element.HEALING), novice_healing_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.MAGIC), apprentice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.FIRE), apprentice_fire_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.ICE), apprentice_ice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.LIGHTNING), apprentice_lightning_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.NECROMANCY), apprentice_necromancy_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.EARTH), apprentice_earth_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.SORCERY), apprentice_sorcery_wand); + WAND_MAP.put(ImmutablePair.of(Tier.APPRENTICE, Element.HEALING), apprentice_healing_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.MAGIC), advanced_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.FIRE), advanced_fire_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.ICE), advanced_ice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.LIGHTNING), advanced_lightning_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.NECROMANCY), advanced_necromancy_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.EARTH), advanced_earth_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.SORCERY), advanced_sorcery_wand); + WAND_MAP.put(ImmutablePair.of(Tier.ADVANCED, Element.HEALING), advanced_healing_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.MAGIC), master_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.FIRE), master_fire_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.ICE), master_ice_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.LIGHTNING), master_lightning_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.NECROMANCY), master_necromancy_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.EARTH), master_earth_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.SORCERY), master_sorcery_wand); + WAND_MAP.put(ImmutablePair.of(Tier.MASTER, Element.HEALING), master_healing_wand); + } + + public static void populateArmourMap(){ + + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.MAGIC), wizard_hat); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.FIRE), wizard_hat_fire); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.ICE), wizard_hat_ice); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.LIGHTNING), wizard_hat_lightning); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.NECROMANCY), wizard_hat_necromancy); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.EARTH), wizard_hat_earth); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.SORCERY), wizard_hat_sorcery); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.HEAD, Element.HEALING), wizard_hat_healing); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.MAGIC), wizard_robe); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.FIRE), wizard_robe_fire); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.ICE), wizard_robe_ice); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.LIGHTNING), wizard_robe_lightning); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.NECROMANCY), wizard_robe_necromancy); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.EARTH), wizard_robe_earth); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.SORCERY), wizard_robe_sorcery); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.CHEST, Element.HEALING), wizard_robe_healing); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.MAGIC), wizard_leggings); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.FIRE), wizard_leggings_fire); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.ICE), wizard_leggings_ice); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.LIGHTNING), wizard_leggings_lightning); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.NECROMANCY), wizard_leggings_necromancy); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.EARTH), wizard_leggings_earth); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.SORCERY), wizard_leggings_sorcery); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.LEGS, Element.HEALING), wizard_leggings_healing); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.MAGIC), wizard_boots); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.FIRE), wizard_boots_fire); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.ICE), wizard_boots_ice); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.LIGHTNING), wizard_boots_lightning); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.NECROMANCY), wizard_boots_necromancy); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.EARTH), wizard_boots_earth); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.SORCERY), wizard_boots_sorcery); + ARMOUR_MAP.put(ImmutablePair.of(EntityEquipmentSlot.FEET, Element.HEALING), wizard_boots_healing); } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryLoot.java b/src/main/java/electroblob/wizardry/registry/WizardryLoot.java new file mode 100644 index 00000000..551e11e0 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryLoot.java @@ -0,0 +1,156 @@ +package electroblob.wizardry.registry; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.loot.RandomSpell; +import electroblob.wizardry.loot.WizardSpell; +import electroblob.wizardry.spell.Spell; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.*; +import net.minecraft.world.storage.loot.conditions.LootCondition; +import net.minecraft.world.storage.loot.functions.LootFunctionManager; +import net.minecraftforge.event.LootTableLoadEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.EntityEntry; +import net.minecraftforge.fml.common.registry.ForgeRegistries; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.function.Predicate; + +/** + * Class responsible for registering wizardry's loot functions and loot tables. Also handles loot injection and the + * standard weighting. + * + * @author Electroblob + * @since Wizardry 1.0 + */ +@Mod.EventBusSubscriber +public final class WizardryLoot { + + //public static final String FROM_SPAWNER_NBT_FLAG = "fromSpawner"; + + private WizardryLoot(){} // No instances! + + /** Called from the preInit method in the main mod class to register the custom dungeon loot. */ + public static void register(){ + + /* Loot tables work as follows: Minecraft goes through each pool in turn. For each pool, it does a certain + * number of rolls, which can either be set to always be one number or a random number from a range. Each roll, + * it generates one stack of a single random entry in that pool, weighted according to the weights of the + * entries. Functions allow properties of that stack (stack size, damage, nbt) to be set, and even allow it to + * be replaced dynamically with a completely different item (though there's very little point in doing that as + * it could be achieved just as easily with more entries, which makes me think it would be bad practice). You + * can also use conditions to control whether an entry or pool is used at all, which is mostly for mob drops + * under specific conditions, but one of them is simply a random chance, meaning you could use it to make a pool + * that only gets rolled sometimes. All in all, this can get rather confusing, because stackable items can have + * 5 stages of randomness applied to them at once: a random chance for the pool, a random number of rolls for + * the pool, the weighted random chance of choosing that particular entry, a random chance for that entry, and a + * random stack size, and that's before you take functions into account. + * + * ...oh, and entries can be entire loot tables in themselves, allowing for potentially infinite levels of + * randomness. Yeah. */ + + // Always registers the loot tables, but only injects the additions into vanilla if the appropriate option is + // enabled in the config (see WizardryEventHandler). + LootFunctionManager.registerFunction(new RandomSpell.Serializer()); + LootFunctionManager.registerFunction(new WizardSpell.Serializer()); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/wizard_tower")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/obelisk")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/shrine")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/dungeon_additions")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/jungle_dispenser_additions")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/elemental_crystals")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/wizard_armour")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/arcane_tomes")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/wand_upgrades")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "entities/evil_wizard")); + LootTableList.register(new ResourceLocation(Wizardry.MODID, "entities/mob_additions")); + + } + + /** + * Helper method which gets a spell id according to the standard weighting. The tier is a weighted random value; the + * actual spell within that tier is completely random. Will not return the id of a spell which has been disabled in + * the config. This is for simple stuff like chests and drops; more complex generators like wizard trades don't use + * this method. + *

    + * For reference, the standard weighting is as follows: Novice: 60%, Apprentice: 25%, Advanced: 10%, Master: 5% + * + * @param random An instance of {@link Random} to use for RNG + * @param filter A {@link Predicate} specifying any requirements the chosen spell must fulfil + * @return A random spell id number, or -1 if no spell exists that satisfies the given filter + * @deprecated Everything uses loot tables now, I may remove this as some point + */ + @Deprecated + public static int getStandardWeightedRandomSpellId(Random random, Predicate filter){ + + Tier tier = Tier.getWeightedRandomTier(random); + + List spells = Spell.getSpells(new Spell.TierElementFilter(tier, null)); + spells.removeIf(filter.negate()); + + // Ensures the tier chosen actually has spells in it, and if not uses NOVICE instead. + if(spells.isEmpty()){ + spells = Spell.getSpells(new Spell.TierElementFilter(Tier.NOVICE, null)); + spells.removeIf(filter.negate()); + } + + if(spells.isEmpty()) return -1; + + // Finds a random spell in the list and returns its id. + return spells.get(random.nextInt(spells.size())).metadata(); + } + + @SubscribeEvent + public static void onLootTableLoadEvent(LootTableLoadEvent event){ + // General dungeon loot + if(Arrays.asList(Wizardry.settings.lootInjectionLocations).contains(event.getName())){ + event.getTable().addPool(getAdditive(Wizardry.MODID + ":chests/dungeon_additions", Wizardry.MODID + "_additional_dungeon_loot")); + } + // Jungle temple dispensers + if(event.getName().toString().matches("minecraft:chests/jungle_temple_dispenser")){ + event.getTable().addPool(getAdditive(Wizardry.MODID + ":chests/jungle_dispenser_additions", Wizardry.MODID + "_additional_dispenser_loot")); + } + // Mob drops + // Let's hope mods will play nice and store their entity loot tables under 'entities' or 'entity' + // If not, packmakers will have to sort it out themselves using the whitelist/blacklist + if(Arrays.asList(Wizardry.settings.mobLootTableWhitelist).contains(event.getName())){ + event.getTable().addPool(getAdditive(Wizardry.MODID + ":entities/mob_additions", Wizardry.MODID + "_additional_mob_drops")); + + }else if(!Arrays.asList(Wizardry.settings.mobLootTableBlacklist).contains(event.getName()) + && event.getName().getPath().contains("entities") || event.getName().getPath().contains("entity")){ + // Get the filename of the loot table json, for well-behaved mods this will be the entity name + String[] split = event.getName().getPath().split("/"); + String entityName = split[split.length - 1]; + + EntityEntry entry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(entityName)); + if(entry == null) return; // If this is true it didn't work :( + Class entityClass = entry.getEntityClass(); + + if(EnumCreatureType.MONSTER.getCreatureClass().isAssignableFrom(entityClass)){ + event.getTable().addPool(getAdditive(Wizardry.MODID + ":entities/mob_additions", Wizardry.MODID + "_additional_mob_drops")); + } + } + } + + private static LootPool getAdditive(String entryName, String poolName){ + return new LootPool(new LootEntry[]{getAdditiveEntry(entryName, 1)}, new LootCondition[0], + new RandomValueRange(1), new RandomValueRange(0, 1), Wizardry.MODID + "_" + poolName); + } + + private static LootEntryTable getAdditiveEntry(String name, int weight){ + return new LootEntryTable(new ResourceLocation(name), weight, 0, new LootCondition[0], + Wizardry.MODID + "_additive_entry"); + } + +// @SubscribeEvent +// public static void onLivingSpawnEvent(LivingSpawnEvent.SpecialSpawn event){ +// if(event.getSpawner() != null) event.getEntityLiving().getEntityData().setBoolean(FROM_SPAWNER_NBT_FLAG, true); +// } + +} diff --git a/src/main/java/electroblob/wizardry/registry/WizardryPotions.java b/src/main/java/electroblob/wizardry/registry/WizardryPotions.java index a39a99d7..3f799f6a 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryPotions.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryPotions.java @@ -5,7 +5,6 @@ import electroblob.wizardry.potion.*; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.ai.attributes.AbstractAttributeMap; import net.minecraft.potion.Potion; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; @@ -16,6 +15,8 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; import net.minecraftforge.registries.IForgeRegistry; +import javax.annotation.Nonnull; + /** * Class responsible for defining, storing and registering all of wizardry's potion effects. * @@ -26,23 +27,34 @@ import net.minecraftforge.registries.IForgeRegistry; @Mod.EventBusSubscriber public final class WizardryPotions { - public static final Potion frost = null; - public static final Potion transience = null; - public static final Potion fireskin = null; - public static final Potion ice_shroud = null; - public static final Potion static_aura = null; - public static final Potion decay = null; - public static final Potion sixth_sense = null; - public static final Potion arcane_jammer = null; - public static final Potion mind_trick = null; - public static final Potion mind_control = null; - public static final Potion font_of_mana = null; - public static final Potion fear = null; - public static final Potion curse_of_soulbinding = null; - public static final Potion paralysis = null; - public static final Potion muffle = null; - public static final Potion ward = null; - public static final Potion slow_time = null; + private WizardryPotions(){} // No instances! + + @Nonnull + @SuppressWarnings("ConstantConditions") + private static T placeholder(){ return null; } + + public static final Potion frost = placeholder(); + public static final Potion transience = placeholder(); + public static final Potion fireskin = placeholder(); + public static final Potion ice_shroud = placeholder(); + public static final Potion static_aura = placeholder(); + public static final Potion decay = placeholder(); + public static final Potion sixth_sense = placeholder(); + public static final Potion arcane_jammer = placeholder(); + public static final Potion mind_trick = placeholder(); + public static final Potion mind_control = placeholder(); + public static final Potion font_of_mana = placeholder(); + public static final Potion fear = placeholder(); + public static final Potion curse_of_soulbinding = placeholder(); + public static final Potion paralysis = placeholder(); + public static final Potion muffle = placeholder(); + public static final Potion ward = placeholder(); + public static final Potion slow_time = placeholder(); + public static final Potion empowerment = placeholder(); + public static final Potion curse_of_enfeeblement = placeholder(); + public static final Potion curse_of_undeath = placeholder(); + public static final Potion containment = placeholder(); + public static final Potion frost_step = placeholder(); /** * Sets both the registry and unlocalised names of the given potion, then registers it with the given registry. Use @@ -71,7 +83,7 @@ public final class WizardryPotions { registerPotion(registry, "frost", new PotionFrost(true, 0)); // Colour was 0x38ddec (was arbitrary anyway) registerPotion(registry, "transience", new PotionMagicEffectParticles(false, 0, - new ResourceLocation(Wizardry.MODID, "potion_icon_transience")){ + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_transience.png")){ @Override public void spawnCustomParticle(World world, double x, double y, double z){ ParticleBuilder.create(Type.DUST).pos(x, y, z).clr(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); @@ -79,7 +91,7 @@ public final class WizardryPotions { }.setBeneficial()); // 0xffe89b registerPotion(registry, "fireskin", new PotionMagicEffectParticles(false, 0, - new ResourceLocation(Wizardry.MODID, "potion_icon_fireskin")){ + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_fireskin.png")){ @Override public void spawnCustomParticle(World world, double x, double y, double z){ world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0); @@ -89,11 +101,11 @@ public final class WizardryPotions { public void performEffect(EntityLivingBase entitylivingbase, int strength){ entitylivingbase.extinguish(); // Stops melee mobs that are on fire from setting the player on fire, // without allowing the player to actually stand in fire or swim in lava without taking damage. - }; + } }.setBeneficial()); // 0xff2f02 registerPotion(registry, "ice_shroud", new PotionMagicEffectParticles(false, 0, - new ResourceLocation(Wizardry.MODID, "potion_icon_ice_shroud")){ + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_ice_shroud.png")){ @Override public void spawnCustomParticle(World world, double x, double y, double z){ float brightness = 0.5f + (world.rand.nextFloat() / 2); @@ -103,7 +115,7 @@ public final class WizardryPotions { }.setBeneficial()); // 0x52f1ff registerPotion(registry, "static_aura", new PotionMagicEffectParticles(false, 0, - new ResourceLocation(Wizardry.MODID, "potion_icon_static_aura")){ + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_static_aura.png")){ @Override public void spawnCustomParticle(World world, double x, double y, double z){ ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); @@ -113,33 +125,35 @@ public final class WizardryPotions { registerPotion(registry, "decay", new PotionDecay(true, 0x3c006c)); registerPotion(registry, "sixth_sense", new PotionMagicEffect(false, 0xc6ff01, - new ResourceLocation(Wizardry.MODID, "potion_icon_sixth_sense")){ + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_sixth_sense.png")){ @Override - public void removeAttributesModifiersFromEntity(EntityLivingBase target, AbstractAttributeMap attributeMapIn, int amplifier){ - // Reset the shader - if(target.world.isRemote && target == net.minecraft.client.Minecraft.getMinecraft().player){ + public void performEffect(EntityLivingBase target, int strength){ + // Reset the shader (a bit dirty but both the potion expiry hooks are only fired server-side, and + // there's no point sending packets unnecessarily if we can just do this instead) + if(target.getActivePotionEffect(this).getDuration() <= 1 && target.world.isRemote + && target == net.minecraft.client.Minecraft.getMinecraft().player){ net.minecraft.client.Minecraft.getMinecraft().entityRenderer.stopUseShader(); } } }.setBeneficial()); registerPotion(registry, "arcane_jammer", new PotionMagicEffect(true, 0xcf4aa2, - new ResourceLocation(Wizardry.MODID, "potion_icon_arcane_jammer"))); + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_arcane_jammer.png"))); registerPotion(registry, "mind_trick", new PotionMagicEffect(true, 0x601683, - new ResourceLocation(Wizardry.MODID, "potion_icon_mind_trick"))); + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_mind_trick.png"))); registerPotion(registry, "mind_control", new PotionMagicEffect(true, 0x320b44, - new ResourceLocation(Wizardry.MODID, "potion_icon_mind_control"))); + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_mind_control.png"))); registerPotion(registry, "font_of_mana", new PotionMagicEffect(false, 0xffe5bb, - new ResourceLocation(Wizardry.MODID, "potion_icon_font_of_mana")).setBeneficial()); + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_font_of_mana.png")).setBeneficial()); registerPotion(registry, "fear", new PotionMagicEffect(true, 0xbd0100, - new ResourceLocation(Wizardry.MODID, "potion_icon_fear"))); + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_fear.png"))); registerPotion(registry, "curse_of_soulbinding", new Curse(true, 0x0f000f, - new ResourceLocation(Wizardry.MODID, "potion_icon_curse_of_soulbinding")){ + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_curse_of_soulbinding.png")){ @Override // We're not removing any attributes, but it's called when we want it to be so... public void removeAttributesModifiersFromEntity(EntityLivingBase entity, net.minecraft.entity.ai.attributes.AbstractAttributeMap attributeMapIn, int amplifier){ // TODO: Hmmmm... @@ -147,7 +161,7 @@ public final class WizardryPotions { }); registerPotion(registry, "paralysis", new PotionMagicEffectParticles(true, 0, - new ResourceLocation(Wizardry.MODID, "potion_icon_paralysis")){ + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_paralysis.png")){ @Override public void spawnCustomParticle(World world, double x, double y, double z){ ParticleBuilder.create(Type.SPARK).pos(x, y, z).spawn(world); @@ -155,12 +169,24 @@ public final class WizardryPotions { }); registerPotion(registry, "muffle", new PotionMagicEffect(false, 0x4464d9, - new ResourceLocation(Wizardry.MODID, "potion_icon_muffle")).setBeneficial()); + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_muffle.png")).setBeneficial()); registerPotion(registry, "ward", new PotionMagicEffect(false, 0xc991d0, - new ResourceLocation(Wizardry.MODID, "potion_icon_ward")).setBeneficial()); + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_ward.png")).setBeneficial()); registerPotion(registry, "slow_time", new PotionSlowTime(false, 0x5be3bb).setBeneficial()); + + registerPotion(registry, "empowerment", new PotionMagicEffect(false, 0x8367bd, + new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_empowerment.png")).setBeneficial()); + + registerPotion(registry, "curse_of_enfeeblement", new CurseEnfeeblement(true, 0x36000b)); + + registerPotion(registry, "curse_of_undeath", new CurseUndeath(true, 0x685c00)); + + registerPotion(registry, "containment", new PotionContainment(true, 0x7988cc)); + + registerPotion(registry, "frost_step", new PotionFrostStep(false, 0).setBeneficial()); + } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryRecipes.java b/src/main/java/electroblob/wizardry/registry/WizardryRecipes.java new file mode 100644 index 00000000..f2691884 --- /dev/null +++ b/src/main/java/electroblob/wizardry/registry/WizardryRecipes.java @@ -0,0 +1,137 @@ +package electroblob.wizardry.registry; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.IManaStoringItem; +import electroblob.wizardry.item.ItemManaFlask; +import net.minecraft.inventory.ContainerPlayer; +import net.minecraft.inventory.ContainerWorkbench; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.oredict.OreDictionary; +import net.minecraftforge.oredict.ShapelessOreRecipe; +import net.minecraftforge.registries.IForgeRegistry; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Class responsible for defining and registering wizardry's non-JSON recipes (i.e. smelting recipes and dynamic + * crafting recipes). Also handles dynamic recipe display and usage. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +@Mod.EventBusSubscriber +public final class WizardryRecipes { + + private WizardryRecipes(){} // No instances! + + private static final Queue chargingRecipeQueue = new LinkedList<>(); + + /** Adds the given item to the list of items that can be charged using mana flasks. Dynamic charging recipes + * will be added for these items during {@code RegistryEvent.Register}. The item must implement + * {@link IManaStoringItem} for the recipes to work correctly. This method should be called from the item's + * constructor. */ + public static void addToManaFlaskCharging(Item item){ + chargingRecipeQueue.offer(item); + } + + /** Now only deals with the dynamic crafting recipes and the smelting recipes. */ + @SubscribeEvent + public static void registerRecipes(RegistryEvent.Register event){ + + IForgeRegistry registry = event.getRegistry(); + + FurnaceRecipes.instance().addSmeltingRecipeForBlock(WizardryBlocks.crystal_ore, new ItemStack(WizardryItems.magic_crystal), 0.5f); + + // Mana flask recipes + + ItemStack smallFlaskStack = new ItemStack(WizardryItems.small_mana_flask); + ItemStack mediumFlaskStack = new ItemStack(WizardryItems.medium_mana_flask); + ItemStack largeFlaskStack = new ItemStack(WizardryItems.large_mana_flask); + + ItemStack chargeable; + + while(!chargingRecipeQueue.isEmpty()){ + // Use remove() and not poll() because the queue shouldn't be empty in here + chargeable = new ItemStack(chargingRecipeQueue.remove(), 1, OreDictionary.WILDCARD_VALUE); + + registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, smallFlaskStack){ + @Override public boolean isDynamic(){ return true; } // Stops it appearing in the recipe book + }.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/small_flask_" + chargeable.getItem().getRegistryName().getPath()))); + + registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, mediumFlaskStack){ + @Override public boolean isDynamic(){ return true; } + }.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/medium_flask_" + chargeable.getItem().getRegistryName().getPath()))); + + registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, largeFlaskStack){ + @Override public boolean isDynamic(){ return true; } + }.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/large_flask_" + chargeable.getItem().getRegistryName().getPath()))); + + } + } + + @SubscribeEvent + public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){ + + if(event.phase == TickEvent.Phase.START){ + + if(event.player.openContainer instanceof ContainerWorkbench){ + + IInventory craftMatrix = ((ContainerWorkbench)event.player.openContainer).craftMatrix; + ItemStack output = ((ContainerWorkbench)event.player.openContainer).craftResult.getStackInSlot(0); + processManaFlaskCrafting(craftMatrix, output); + + }else if(event.player.openContainer instanceof ContainerPlayer){ + + IInventory craftMatrix = ((ContainerPlayer)event.player.openContainer).craftMatrix; + ItemStack output = ((ContainerPlayer)event.player.openContainer).craftResult.getStackInSlot(0); + // Unfortunately I have no choice but to call this method every tick when the player isn't using another + // inventory, since the only thing tracking whether the player is looking at their inventory is the GUI + // itself, which is client-side only. + processManaFlaskCrafting(craftMatrix, output); + } + } + } + + private static void processManaFlaskCrafting(IInventory craftMatrix, ItemStack output){ + + // Charges wand using mana flask + + ItemManaFlask flask = null; + ItemStack input = ItemStack.EMPTY; + + for(int i = 0; i < craftMatrix.getSizeInventory(); i++){ + + ItemStack stack = craftMatrix.getStackInSlot(i); + + if(stack.getItem() instanceof ItemManaFlask){ + flask = (ItemManaFlask)stack.getItem(); + } + + if(stack.getItem() instanceof IManaStoringItem){ + input = stack; + } + } + + if(flask == null) return; + + if(output.getItem() instanceof IManaStoringItem && !input.isEmpty()){ + + output.setTagCompound((input.getTagCompound())); + + int currentMana = ((IManaStoringItem)input.getItem()).getMana(input); + + ((IManaStoringItem)output.getItem()).setMana(output, Math.min(currentMana + flask.size.capacity, + ((IManaStoringItem)input.getItem()).getManaCapacity(input))); + } + } +} diff --git a/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java b/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java deleted file mode 100644 index 6b150adc..00000000 --- a/src/main/java/electroblob/wizardry/registry/WizardryRegistry.java +++ /dev/null @@ -1,225 +0,0 @@ -package electroblob.wizardry.registry; - -import com.google.common.collect.Lists; -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.EntityArc; -import electroblob.wizardry.entity.EntityMeteor; -import electroblob.wizardry.entity.EntityShield; -import electroblob.wizardry.entity.construct.*; -import electroblob.wizardry.entity.living.*; -import electroblob.wizardry.entity.projectile.*; -import electroblob.wizardry.loot.RandomSpell; -import electroblob.wizardry.loot.WizardSpell; -import electroblob.wizardry.tileentity.*; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EnumCreatureType; -import net.minecraft.init.Biomes; -import net.minecraft.inventory.EntityEquipmentSlot; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.FurnaceRecipes; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.storage.loot.LootTableList; -import net.minecraft.world.storage.loot.functions.LootFunctionManager; -import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.registry.EntityRegistry; -import net.minecraftforge.fml.common.registry.ForgeRegistries; -import net.minecraftforge.fml.common.registry.GameRegistry; -import net.minecraftforge.oredict.OreDictionary; -import net.minecraftforge.oredict.ShapelessOreRecipe; -import net.minecraftforge.registries.IForgeRegistry; - -import java.util.List; - -/** - * Class responsible for registering all the things that don't have (or need) instances: entities, loot tables, recipes, - * etc. - * - * @author Electroblob - * @since Wizardry 1.0 - */ -@Mod.EventBusSubscriber -public final class WizardryRegistry { - - /** Called from the preInit method in the main mod class to register the custom dungeon loot. */ - public static void registerLoot(){ - - /* Loot tables work as follows: Minecraft goes through each pool in turn. For each pool, it does a certain - * number of rolls, which can either be set to always be one number or a random number from a range. Each roll, - * it generates one stack of a single random entry in that pool, weighted according to the weights of the - * entries. Functions allow properties of that stack (stack size, damage, nbt) to be set, and even allow it to - * be replaced dynamically with a completely different item (though there's very little point in doing that as - * it could be achieved just as easily with more entries, which makes me think it would be bad practice). You - * can also use conditions to control whether an entry or pool is used at all, which is mostly for mob drops - * under specific conditions, but one of them is simply a random chance, meaning you could use it to make a pool - * that only gets rolled sometimes. All in all, this can get rather confusing, because stackable items can have - * 5 stages of randomness applied to them at once: a random chance for the pool, a random number of rolls for - * the pool, the weighted random chance of choosing that particular entry, a random chance for that entry, and a - * random stack size, and that's before you take functions into account. - * - * ...oh, and entries can be entire loot tables in themselves, allowing for potentially infinite levels of - * randomness. Yeah. */ - - // Always registers the loot tables, but only injects the additions into vanilla if the appropriate option is - // enabled in the config (see WizardryEventHandler). - LootFunctionManager.registerFunction(new RandomSpell.Serializer()); - LootFunctionManager.registerFunction(new WizardSpell.Serializer()); - LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/wizard_tower")); - LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/dungeon_additions")); - LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/novice_wands")); - LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/wizard_armour")); - LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/arcane_tomes")); - LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/wand_upgrades")); - LootTableList.register(new ResourceLocation(Wizardry.MODID, "entities/evil_wizard")); - // TODO: At the moment this is not used anywhere because I can't find a way to add it to all mobs. - // LootTableList.register(new ResourceLocation(Wizardry.MODID, "entities/mob_additions")); - - } - - /** Called from the preInit method in the main mod class to register all the tile entities. */ - public static void registerTileEntities(){ - - GameRegistry.registerTileEntity(TileEntityArcaneWorkbench.class, Wizardry.MODID + "ArcaneWorkbenchTileEntity"); - GameRegistry.registerTileEntity(TileEntityStatue.class, Wizardry.MODID + "PetrifiedStoneTileEntity"); - GameRegistry.registerTileEntity(TileEntityMagicLight.class, Wizardry.MODID + "MagicLightTileEntity"); - GameRegistry.registerTileEntity(TileEntityTimer.class, Wizardry.MODID + "TimerTileEntity"); - GameRegistry.registerTileEntity(TileEntityPlayerSave.class, Wizardry.MODID + "TileEntityPlayerSave"); - } - - /** Not actually the frequency at all; smaller numbers are more frequent. Vanilla uses 3 I think. */ - private static final int LIVING_UPDATE_INTERVAL = 3; - /** Not actually the frequency at all; smaller numbers are more frequent. */ - private static final int PROJECTILE_UPDATE_INTERVAL = 10; - - /** Called from the preInit method in the main mod class to register all the entities. */ - public static void registerEntities(){ - - int id = 0; // Incrementable index for the mod specific entity id. - - registerEntity(EntityZombieMinion.class, "zombie_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityMagicMissile.class, "magic_missile", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - // TODO: This should be a particle - registerEntity(EntityArc.class, "arc", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntitySkeletonMinion.class, "skeleton_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntitySparkBomb.class, "spark_bomb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntitySpiritWolf.class, "spirit_wolf", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityIceShard.class, "ice_shard", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityBlazeMinion.class, "blaze_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityIceWraith.class, "ice_wraith", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityLightningWraith.class, "lightning_wraith", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityBlackHole.class, "black_hole", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityShield.class, "shield", id++, 128, 1, true); - registerEntity(EntityMeteor.class, "meteor", id++, 128, 5, true); - registerEntity(EntityBlizzard.class, "blizzard", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntityAndEgg(EntityWizard.class, "wizard", id++, 128, LIVING_UPDATE_INTERVAL, true, 0x19295e, 0xee9312); - registerEntity(EntityBubble.class, "bubble", id++, 128, 3, false); - registerEntity(EntityTornado.class, "tornado", id++, 128, 1, false); - registerEntity(EntityHammer.class, "lightning_hammer", id++, 128, 1, true); - registerEntity(EntityFirebomb.class, "firebomb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityForceOrb.class, "force_orb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityArrowRain.class, "arrow_rain", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntitySpark.class, "spark", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityShadowWraith.class, "shadow_wraith", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityDarknessOrb.class, "darkness_orb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntitySpiderMinion.class, "spider_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityHealAura.class, "healing_aura", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityFireSigil.class, "fire_sigil", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityFrostSigil.class, "frost_sigil", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityLightningSigil.class, "lightning_sigil", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityLightningArrow.class, "lightning_arrow", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityFirebolt.class, "firebolt", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityPoisonBomb.class, "poison_bomb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityIceCharge.class, "ice_charge", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityForceArrow.class, "force_arrow", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityDart.class, "dart", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityMagicSlime.class, "magic_slime", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityForcefield.class, "forcefield", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityFireRing.class, "ring_of_fire", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityLightningDisc.class, "lightning_disc", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityThunderbolt.class, "thunderbolt", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityIceGiant.class, "ice_giant", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntitySpiritHorse.class, "spirit_horse", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityPhoenix.class, "phoenix", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntitySilverfishMinion.class, "silverfish_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityDecay.class, "decay", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityStormElemental.class, "storm_elemental", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityEarthquake.class, "earthquake", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityIceLance.class, "ice_lance", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntity(EntityHailstorm.class, "hailstorm", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntitySmokeBomb.class, "smoke_bomb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); - registerEntityAndEgg(EntityEvilWizard.class, "evil_wizard", id++, 128, LIVING_UPDATE_INTERVAL, true, 0x290404, 0xee9312); - registerEntity(EntityDecoy.class, "decoy", id++, 128, LIVING_UPDATE_INTERVAL, true); - registerEntity(EntityIceSpike.class, "ice_spike", id++, 128, 1, true); - // TODO: This should be a particle. - registerEntity(EntityLightningPulse.class, "lightning_pulse", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); - registerEntity(EntityWitherSkeletonMinion.class, "wither_skeleton_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); - - // TODO: May need fixing - List biomes = Lists.newArrayList(); - for (Biome biome : ForgeRegistries.BIOMES.getValuesCollection()) { - biomes.add(biome); - } - biomes.remove(Biomes.MUSHROOM_ISLAND); - biomes.remove(Biomes.MUSHROOM_ISLAND_SHORE); - // For reference: 5, 1, 1 are the parameters for the witch in vanilla. - EntityRegistry.addSpawn(EntityEvilWizard.class, 3, 1, 1, EnumCreatureType.MONSTER, biomes.toArray(new Biome[biomes.size()])); - - } - - /** Private helper method for registering entities; keeps things neater. For some reason, Forge 1.11.2 wants a - * ResourceLocation and a string name... probably because it's transitioning to the registry system. */ - private static void registerEntity(Class entityClass, String name, int id, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates){ - ResourceLocation registryName = new ResourceLocation(Wizardry.MODID, name); - EntityRegistry.registerModEntity(registryName, entityClass, registryName.toString(), id, Wizardry.instance, trackingRange, updateFrequency, sendsVelocityUpdates); - } - - /** Private helper method for registering entities with eggs; keeps things neater. For some reason, Forge 1.11.2 - * wants a ResourceLocation and a string name... probably because it's transitioning to the registry system. */ - private static void registerEntityAndEgg(Class entityClass, String name, int id, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates, int eggColour, int spotColour){ - ResourceLocation registryName = new ResourceLocation(Wizardry.MODID, name); - EntityRegistry.registerModEntity(registryName, entityClass, registryName.toString(), id, Wizardry.instance, trackingRange, updateFrequency, sendsVelocityUpdates); - EntityRegistry.registerEgg(registryName, eggColour, spotColour); - } - - /** Now only deals with the dynamic crafting recipes and the smelting recipes. */ - @SubscribeEvent - public static void registerRecipes(RegistryEvent.Register event){ - - IForgeRegistry registry = event.getRegistry(); - - FurnaceRecipes.instance().addSmeltingRecipeForBlock(WizardryBlocks.crystal_ore, new ItemStack(WizardryItems.magic_crystal), 0.5f); - - // Mana flask recipes - - ItemStack manaFlaskStack = new ItemStack(WizardryItems.mana_flask); - - ItemStack miscWandStack; - - for(Element element : Element.values()){ - for(Tier tier : Tier.values()){ - miscWandStack = new ItemStack(WizardryUtilities.getWand(tier, element), 1, OreDictionary.WILDCARD_VALUE); - registry.register(new ShapelessOreRecipe(null, miscWandStack, miscWandStack, manaFlaskStack){ - @Override public boolean isDynamic(){ return true; } // Stops it appearing in the recipe book - }.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/flask_wand_" + element.getUnlocalisedName() + "_" + tier.getUnlocalisedName()))); - } - } - - ItemStack miscArmourStack; - - for(Element element : Element.values()){ - for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ - miscArmourStack = new ItemStack(WizardryUtilities.getArmour(element, slot), 1, OreDictionary.WILDCARD_VALUE); - registry.register(new ShapelessOreRecipe(null, miscArmourStack, miscArmourStack, manaFlaskStack){ - @Override public boolean isDynamic(){ return true; } // Stops it appearing in the recipe book - }.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/flask_armour_" + element.getUnlocalisedName() + "_" + slot.getName()))); - } - } - } - -} diff --git a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java index e472c4c5..97f9f25e 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java +++ b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java @@ -1,7 +1,10 @@ package electroblob.wizardry.registry; import electroblob.wizardry.Wizardry; +import electroblob.wizardry.misc.Forfeit; +import electroblob.wizardry.spell.Spell; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; @@ -16,27 +19,118 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber public final class WizardrySounds { - // Anything with LOOP in its name is intended to be played in a continuous loop. - public static final SoundEvent SPELL_SPARK = createSound("arc"); - public static final SoundEvent SPELL_CONJURATION = createSound("aura"); - public static final SoundEvent SPELL_SHOCKWAVE = createSound("boom"); - public static final SoundEvent SPELL_LOOP_CRACKLE = createSound("crackle"); - public static final SoundEvent SPELL_SUMMONING = createSound("darkaura"); - public static final SoundEvent SPELL_DEFLECTION = createSound("effect"); - public static final SoundEvent SPELL_LIGHTNING = createSound("electricitya"); - public static final SoundEvent SPELL_LOOP_LIGHTNING = createSound("electricityb"); - public static final SoundEvent SPELL_LOOP_FIRE = createSound("flameray"); - public static final SoundEvent SPELL_FREEZE = createSound("freeze"); - public static final SoundEvent SPELL_LOOP_ICE = createSound("frostray"); - public static final SoundEvent SPELL_HEAL = createSound("heal"); - public static final SoundEvent SPELL_ICE = createSound("ice"); - public static final SoundEvent SPELL_CONJURATION_LARGE = createSound("largeaura"); - public static final SoundEvent SPELL_MAGIC = createSound("magic"); - public static final SoundEvent SPELL_LOOP_SPARKLE = createSound("sparkle"); - public static final SoundEvent SPELL_LOOP_WIND = createSound("wind"); - public static final SoundEvent SPELL_EARTHQUAKE = createSound("rumble"); - public static final SoundEvent SPELL_FORCE = createSound("force"); - public static final SoundEvent SELECT_SPELL = createSound("select"); + private WizardrySounds(){} // No instances! + + /** Sound category for all spell-related sounds. This includes inanimate magical entities, but not minions. + * @see electroblob.wizardry.util.CustomSoundCategory */ + public static SoundCategory SPELLS; + + public static final SoundEvent BLOCK_ARCANE_WORKBENCH_SPELLBIND = createSound("block.arcane_workbench.bind_spell"); + public static final SoundEvent BLOCK_PEDESTAL_ACTIVATE = createSound("block.pedestal.activate"); + public static final SoundEvent BLOCK_PEDESTAL_CONQUER = createSound("block.pedestal.conquer"); + + public static final SoundEvent ITEM_WAND_SWITCH_SPELL = createSound("item.wand.switch_spell"); + public static final SoundEvent ITEM_WAND_LEVELUP = createSound("item.wand.levelup"); + public static final SoundEvent ITEM_WAND_MELEE = createSound("item.wand.melee"); + public static final SoundEvent ITEM_ARMOUR_EQUIP_SILK = createSound("item.armour.equip_silk"); + public static final SoundEvent ITEM_PURIFYING_ELIXIR_DRINK = createSound("item.purifying_elixir.drink"); + + public static final SoundEvent ENTITY_BLACK_HOLE_AMBIENT = createSound("entity.black_hole.ambient"); + public static final SoundEvent ENTITY_BLACK_HOLE_VANISH = createSound("entity.black_hole.vanish"); + public static final SoundEvent ENTITY_BUBBLE_POP = createSound("entity.bubble.pop"); + public static final SoundEvent ENTITY_BLIZZARD_AMBIENT = createSound("entity.blizzard.ambient"); + public static final SoundEvent ENTITY_DECAY_AMBIENT = createSound("entity.decay.ambient"); + public static final SoundEvent ENTITY_ENTRAPMENT_AMBIENT = createSound("entity.entrapment.ambient"); + public static final SoundEvent ENTITY_ENTRAPMENT_VANISH = createSound("entity.entrapment.vanish"); + public static final SoundEvent ENTITY_FIRE_RING_AMBIENT = createSound("entity.fire_ring.ambient"); + public static final SoundEvent ENTITY_FIRE_SIGIL_TRIGGER = createSound("entity.fire_sigil.trigger"); + public static final SoundEvent ENTITY_FORCEFIELD_DEFLECT = createSound("entity.forcefield.deflect"); + public static final SoundEvent ENTITY_FROST_SIGIL_TRIGGER = createSound("entity.frost_sigil.trigger"); + public static final SoundEvent ENTITY_HAMMER_ATTACK = createSound("entity.hammer.attack"); + public static final SoundEvent ENTITY_HAMMER_EXPLODE = createSound("entity.hammer.explode"); + public static final SoundEvent ENTITY_HAMMER_THROW = createSound("entity.hammer.throw"); + public static final SoundEvent ENTITY_HAMMER_LAND = createSound("entity.hammer.land"); + public static final SoundEvent ENTITY_HEAL_AURA_AMBIENT = createSound("entity.heal_aura.ambient"); + public static final SoundEvent ENTITY_ICE_SPIKE_EXTEND = createSound("entity.ice_spike.extend"); + public static final SoundEvent ENTITY_LIGHTNING_SIGIL_TRIGGER = createSound("entity.lightning_sigil.trigger"); + public static final SoundEvent ENTITY_METEOR_FALLING = createSound("entity.meteor.falling"); + public static final SoundEvent ENTITY_SHIELD_DEFLECT = createSound("entity.shield.deflect"); + public static final SoundEvent ENTITY_TORNADO_AMBIENT = createSound("entity.tornado.ambient"); + + public static final SoundEvent ENTITY_EVIL_WIZARD_AMBIENT = createSound("entity.evil_wizard.ambient"); + public static final SoundEvent ENTITY_EVIL_WIZARD_HURT = createSound("entity.evil_wizard.hurt"); + public static final SoundEvent ENTITY_EVIL_WIZARD_DEATH = createSound("entity.evil_wizard.death"); + public static final SoundEvent ENTITY_ICE_GIANT_ATTACK = createSound("entity.ice_giant.attack"); + public static final SoundEvent ENTITY_ICE_GIANT_DESPAWN = createSound("entity.ice_giant.despawn"); + public static final SoundEvent ENTITY_ICE_WRAITH_AMBIENT = createSound("entity.ice_wraith.ambient"); + public static final SoundEvent ENTITY_MAGIC_SLIME_ATTACK = createSound("entity.magic_slime.attack"); + public static final SoundEvent ENTITY_MAGIC_SLIME_EXPLODE = createSound("entity.magic_slime.explode"); + public static final SoundEvent ENTITY_MAGIC_SLIME_SPLAT = createSound("entity.magic_slime.splat"); + public static final SoundEvent ENTITY_PHOENIX_AMBIENT = createSound("entity.phoenix.ambient"); + public static final SoundEvent ENTITY_PHOENIX_BURN = createSound("entity.phoenix.burn"); + public static final SoundEvent ENTITY_PHOENIX_FLAP = createSound("entity.phoenix.flap"); + public static final SoundEvent ENTITY_PHOENIX_HURT = createSound("entity.phoenix.hurt"); + public static final SoundEvent ENTITY_PHOENIX_DEATH = createSound("entity.phoenix.death"); + public static final SoundEvent ENTITY_SHADOW_WRAITH_AMBIENT = createSound("entity.shadow_wraith.ambient"); + public static final SoundEvent ENTITY_SHADOW_WRAITH_NOISE = createSound("entity.shadow_wraith.noise"); + public static final SoundEvent ENTITY_SHADOW_WRAITH_HURT = createSound("entity.shadow_wraith.hurt"); + public static final SoundEvent ENTITY_SHADOW_WRAITH_DEATH = createSound("entity.shadow_wraith.death"); + public static final SoundEvent ENTITY_SPIRIT_HORSE_VANISH = createSound("entity.spirit_horse.vanish"); + public static final SoundEvent ENTITY_SPIRIT_WOLF_VANISH = createSound("entity.spirit_wolf.vanish"); + public static final SoundEvent ENTITY_STORM_ELEMENTAL_AMBIENT = createSound("entity.storm_elemental.ambient"); + public static final SoundEvent ENTITY_STORM_ELEMENTAL_BURN = createSound("entity.storm_elemental.burn"); + public static final SoundEvent ENTITY_STORM_ELEMENTAL_WIND = createSound("entity.storm_elemental.wind"); + public static final SoundEvent ENTITY_STORM_ELEMENTAL_HURT = createSound("entity.storm_elemental.hurt"); + public static final SoundEvent ENTITY_STORM_ELEMENTAL_DEATH = createSound("entity.storm_elemental.death"); + public static final SoundEvent ENTITY_WIZARD_YES = createSound("entity.wizard.yes"); + public static final SoundEvent ENTITY_WIZARD_NO = createSound("entity.wizard.no"); + public static final SoundEvent ENTITY_WIZARD_AMBIENT = createSound("entity.wizard.ambient"); + public static final SoundEvent ENTITY_WIZARD_TRADING = createSound("entity.wizard.trading"); + public static final SoundEvent ENTITY_WIZARD_HURT = createSound("entity.wizard.hurt"); + public static final SoundEvent ENTITY_WIZARD_DEATH = createSound("entity.wizard.death"); + + public static final SoundEvent ENTITY_DARKNESS_ORB_HIT = createSound("entity.darkness_orb.hit"); + public static final SoundEvent ENTITY_DART_HIT = createSound("entity.dart.hit"); + public static final SoundEvent ENTITY_DART_HIT_BLOCK = createSound("entity.dart.hit_block"); + public static final SoundEvent ENTITY_FIREBOLT_HIT = createSound("entity.firebolt.hit"); + public static final SoundEvent ENTITY_FIREBOMB_THROW = createSound("entity.firebomb.throw"); + public static final SoundEvent ENTITY_FIREBOMB_SMASH = createSound("entity.firebomb.smash"); + public static final SoundEvent ENTITY_FIREBOMB_FIRE = createSound("entity.firebomb.fire"); + public static final SoundEvent ENTITY_FORCE_ARROW_HIT = createSound("entity.force_arrow.hit"); + public static final SoundEvent ENTITY_FORCE_ORB_HIT = createSound("entity.force_orb.hit"); + public static final SoundEvent ENTITY_FORCE_ORB_HIT_BLOCK = createSound("entity.force_orb.hit_block"); + public static final SoundEvent ENTITY_ICEBALL_HIT = createSound("entity.iceball.hit"); + public static final SoundEvent ENTITY_ICE_CHARGE_SMASH = createSound("entity.ice_charge.smash"); + public static final SoundEvent ENTITY_ICE_CHARGE_ICE = createSound("entity.ice_charge.ice"); + public static final SoundEvent ENTITY_ICE_LANCE_SMASH = createSound("entity.ice_lance.smash"); + public static final SoundEvent ENTITY_ICE_LANCE_HIT = createSound("entity.ice_lance.hit"); + public static final SoundEvent ENTITY_ICE_SHARD_SMASH = createSound("entity.ice_shard.smash"); + public static final SoundEvent ENTITY_ICE_SHARD_HIT = createSound("entity.ice_shard.hit"); + public static final SoundEvent ENTITY_LIGHTNING_ARROW_HIT = createSound("entity.lightning_arrow.hit"); + public static final SoundEvent ENTITY_LIGHTNING_DISC_HIT = createSound("entity.lightning_disc.hit"); +// public static final SoundEvent ENTITY_MAGIC_FIREBALL_HIT = createSound("entity.magic_fireball.hit"); + public static final SoundEvent ENTITY_MAGIC_MISSILE_HIT = createSound("entity.magic_missile.hit"); + public static final SoundEvent ENTITY_POISON_BOMB_THROW = createSound("entity.poison_bomb.throw"); + public static final SoundEvent ENTITY_POISON_BOMB_SMASH = createSound("entity.poison_bomb.smash"); + public static final SoundEvent ENTITY_POISON_BOMB_POISON = createSound("entity.poison_bomb.poison"); + public static final SoundEvent ENTITY_SMOKE_BOMB_THROW = createSound("entity.smoke_bomb.throw"); + public static final SoundEvent ENTITY_SMOKE_BOMB_SMASH = createSound("entity.smoke_bomb.smash"); + public static final SoundEvent ENTITY_SMOKE_BOMB_SMOKE = createSound("entity.smoke_bomb.smoke"); + public static final SoundEvent ENTITY_HOMING_SPARK_HIT = createSound("entity.homing_spark.hit"); + public static final SoundEvent ENTITY_SPARK_BOMB_THROW = createSound("entity.spark_bomb.throw"); + public static final SoundEvent ENTITY_SPARK_BOMB_HIT = createSound("entity.spark_bomb.hit"); + public static final SoundEvent ENTITY_SPARK_BOMB_HIT_BLOCK = createSound("entity.spark_bomb.hit_block"); + public static final SoundEvent ENTITY_SPARK_BOMB_CHAIN = createSound("entity.spark_bomb.chain"); + public static final SoundEvent ENTITY_THUNDERBOLT_HIT = createSound("entity.thunderbolt.hit"); + + public static final SoundEvent SPELL_STATIC_AURA_RETALIATE = createSound("spell.static_aura.retaliate"); + public static final SoundEvent SPELL_CURSE_OF_SOULBINDING_RETALIATE = createSound("spell.curse_of_soulbinding.retaliate"); + public static final SoundEvent SPELL_TRANSPORTATION_TRAVEL = createSound("spell.transportation.travel"); + + public static final SoundEvent MISC_DISCOVER_SPELL = createSound("misc.discover_spell"); + public static final SoundEvent MISC_BOOK_OPEN = createSound("misc.book_open"); + public static final SoundEvent MISC_PAGE_TURN = createSound("misc.page_turn"); + public static final SoundEvent MISC_FREEZE = createSound("misc.freeze"); /** Trick borrowed from the Twilight Forest, makes things neater. */ public static SoundEvent createSound(String name){ @@ -44,27 +138,124 @@ public final class WizardrySounds { return new SoundEvent(new ResourceLocation(Wizardry.MODID, name)).setRegistryName(name); } + // For some reason, sound events seem to work even when they aren't registered, without even so much as a warning. + @SubscribeEvent public static void register(RegistryEvent.Register event){ - event.getRegistry().register(SPELL_SPARK); - event.getRegistry().register(SPELL_CONJURATION); - event.getRegistry().register(SPELL_SHOCKWAVE); - event.getRegistry().register(SPELL_LOOP_CRACKLE); - event.getRegistry().register(SPELL_SUMMONING); - event.getRegistry().register(SPELL_DEFLECTION); - event.getRegistry().register(SPELL_LIGHTNING); - event.getRegistry().register(SPELL_LOOP_LIGHTNING); - event.getRegistry().register(SPELL_LOOP_FIRE); - event.getRegistry().register(SPELL_FREEZE); - event.getRegistry().register(SPELL_LOOP_ICE); - event.getRegistry().register(SPELL_HEAL); - event.getRegistry().register(SPELL_ICE); - event.getRegistry().register(SPELL_CONJURATION_LARGE); - event.getRegistry().register(SPELL_MAGIC); - event.getRegistry().register(SPELL_LOOP_SPARKLE); - event.getRegistry().register(SPELL_LOOP_WIND); - event.getRegistry().register(SPELL_EARTHQUAKE); - event.getRegistry().register(SPELL_FORCE); - event.getRegistry().register(SELECT_SPELL); + + event.getRegistry().register(BLOCK_ARCANE_WORKBENCH_SPELLBIND); + event.getRegistry().register(BLOCK_PEDESTAL_ACTIVATE); + event.getRegistry().register(BLOCK_PEDESTAL_CONQUER); + + event.getRegistry().register(ITEM_WAND_SWITCH_SPELL); + event.getRegistry().register(ITEM_WAND_LEVELUP); + event.getRegistry().register(ITEM_WAND_MELEE); + event.getRegistry().register(ITEM_ARMOUR_EQUIP_SILK); + event.getRegistry().register(ITEM_PURIFYING_ELIXIR_DRINK); + + event.getRegistry().register(ENTITY_BLACK_HOLE_AMBIENT); + event.getRegistry().register(ENTITY_BLACK_HOLE_VANISH); + event.getRegistry().register(ENTITY_BUBBLE_POP); + event.getRegistry().register(ENTITY_BLIZZARD_AMBIENT); + event.getRegistry().register(ENTITY_DECAY_AMBIENT); + event.getRegistry().register(ENTITY_ENTRAPMENT_AMBIENT); + event.getRegistry().register(ENTITY_ENTRAPMENT_VANISH); + event.getRegistry().register(ENTITY_FIRE_RING_AMBIENT); + event.getRegistry().register(ENTITY_FIRE_SIGIL_TRIGGER); + event.getRegistry().register(ENTITY_FORCEFIELD_DEFLECT); + event.getRegistry().register(ENTITY_FROST_SIGIL_TRIGGER); + event.getRegistry().register(ENTITY_HAMMER_ATTACK); + event.getRegistry().register(ENTITY_HAMMER_EXPLODE); + event.getRegistry().register(ENTITY_HAMMER_THROW); + event.getRegistry().register(ENTITY_HAMMER_LAND); + event.getRegistry().register(ENTITY_HEAL_AURA_AMBIENT); + event.getRegistry().register(ENTITY_ICE_SPIKE_EXTEND); + event.getRegistry().register(ENTITY_LIGHTNING_SIGIL_TRIGGER); + event.getRegistry().register(ENTITY_METEOR_FALLING); + event.getRegistry().register(ENTITY_SHIELD_DEFLECT); + event.getRegistry().register(ENTITY_TORNADO_AMBIENT); + + event.getRegistry().register(ENTITY_EVIL_WIZARD_AMBIENT); + event.getRegistry().register(ENTITY_EVIL_WIZARD_HURT); + event.getRegistry().register(ENTITY_EVIL_WIZARD_DEATH); + event.getRegistry().register(ENTITY_ICE_GIANT_ATTACK); + event.getRegistry().register(ENTITY_ICE_GIANT_DESPAWN); + event.getRegistry().register(ENTITY_ICE_WRAITH_AMBIENT); + event.getRegistry().register(ENTITY_MAGIC_SLIME_ATTACK); + event.getRegistry().register(ENTITY_MAGIC_SLIME_EXPLODE); + event.getRegistry().register(ENTITY_MAGIC_SLIME_SPLAT); + event.getRegistry().register(ENTITY_PHOENIX_AMBIENT); + event.getRegistry().register(ENTITY_PHOENIX_BURN); + event.getRegistry().register(ENTITY_PHOENIX_FLAP); + event.getRegistry().register(ENTITY_PHOENIX_HURT); + event.getRegistry().register(ENTITY_PHOENIX_DEATH); + event.getRegistry().register(ENTITY_SHADOW_WRAITH_AMBIENT); + event.getRegistry().register(ENTITY_SHADOW_WRAITH_NOISE); + event.getRegistry().register(ENTITY_SHADOW_WRAITH_HURT); + event.getRegistry().register(ENTITY_SHADOW_WRAITH_DEATH); + event.getRegistry().register(ENTITY_SPIRIT_HORSE_VANISH); + event.getRegistry().register(ENTITY_SPIRIT_WOLF_VANISH); + event.getRegistry().register(ENTITY_STORM_ELEMENTAL_AMBIENT); + event.getRegistry().register(ENTITY_STORM_ELEMENTAL_BURN); + event.getRegistry().register(ENTITY_STORM_ELEMENTAL_WIND); + event.getRegistry().register(ENTITY_STORM_ELEMENTAL_HURT); + event.getRegistry().register(ENTITY_STORM_ELEMENTAL_DEATH); + event.getRegistry().register(ENTITY_WIZARD_YES); + event.getRegistry().register(ENTITY_WIZARD_NO); + event.getRegistry().register(ENTITY_WIZARD_AMBIENT); + event.getRegistry().register(ENTITY_WIZARD_TRADING); + event.getRegistry().register(ENTITY_WIZARD_HURT); + event.getRegistry().register(ENTITY_WIZARD_DEATH); + + event.getRegistry().register(ENTITY_DARKNESS_ORB_HIT); + event.getRegistry().register(ENTITY_DART_HIT); + event.getRegistry().register(ENTITY_DART_HIT_BLOCK); + event.getRegistry().register(ENTITY_FIREBOLT_HIT); + event.getRegistry().register(ENTITY_FIREBOMB_THROW); + event.getRegistry().register(ENTITY_FIREBOMB_SMASH); + event.getRegistry().register(ENTITY_FIREBOMB_FIRE); + event.getRegistry().register(ENTITY_FORCE_ARROW_HIT); + event.getRegistry().register(ENTITY_FORCE_ORB_HIT); + event.getRegistry().register(ENTITY_FORCE_ORB_HIT_BLOCK); + event.getRegistry().register(ENTITY_ICEBALL_HIT); + event.getRegistry().register(ENTITY_ICE_CHARGE_SMASH); + event.getRegistry().register(ENTITY_ICE_CHARGE_ICE); + event.getRegistry().register(ENTITY_ICE_LANCE_SMASH); + event.getRegistry().register(ENTITY_ICE_LANCE_HIT); + event.getRegistry().register(ENTITY_ICE_SHARD_SMASH); + event.getRegistry().register(ENTITY_ICE_SHARD_HIT); + event.getRegistry().register(ENTITY_LIGHTNING_ARROW_HIT); + event.getRegistry().register(ENTITY_LIGHTNING_DISC_HIT); +// event.getRegistry().register(ENTITY_MAGIC_FIREBALL_HIT); + event.getRegistry().register(ENTITY_MAGIC_MISSILE_HIT); + event.getRegistry().register(ENTITY_POISON_BOMB_THROW); + event.getRegistry().register(ENTITY_POISON_BOMB_SMASH); + event.getRegistry().register(ENTITY_POISON_BOMB_POISON); + event.getRegistry().register(ENTITY_SMOKE_BOMB_THROW); + event.getRegistry().register(ENTITY_SMOKE_BOMB_SMASH); + event.getRegistry().register(ENTITY_SMOKE_BOMB_SMOKE); + event.getRegistry().register(ENTITY_HOMING_SPARK_HIT); + event.getRegistry().register(ENTITY_SPARK_BOMB_THROW); + event.getRegistry().register(ENTITY_SPARK_BOMB_HIT); + event.getRegistry().register(ENTITY_SPARK_BOMB_HIT_BLOCK); + event.getRegistry().register(ENTITY_SPARK_BOMB_CHAIN); + event.getRegistry().register(ENTITY_THUNDERBOLT_HIT); + + event.getRegistry().register(SPELL_STATIC_AURA_RETALIATE); + event.getRegistry().register(SPELL_CURSE_OF_SOULBINDING_RETALIATE); + event.getRegistry().register(SPELL_TRANSPORTATION_TRAVEL); + + event.getRegistry().register(MISC_DISCOVER_SPELL); + event.getRegistry().register(MISC_BOOK_OPEN); + event.getRegistry().register(MISC_PAGE_TURN); + event.getRegistry().register(MISC_FREEZE); + + for(Spell spell : Spell.getSpells(Spell.allSpells)){ + event.getRegistry().registerAll(spell.getSounds()); + } + + for(Forfeit forfeit : Forfeit.getForfeits()){ + event.getRegistry().register(forfeit.getSound()); + } } } \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/registry/WizardryTabs.java b/src/main/java/electroblob/wizardry/registry/WizardryTabs.java index 6858715f..3e830707 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryTabs.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryTabs.java @@ -1,10 +1,5 @@ package electroblob.wizardry.registry; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - import electroblob.wizardry.item.ItemScroll; import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.spell.Spell; @@ -15,6 +10,10 @@ import net.minecraft.util.NonNullList; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + /** * Class responsible for defining and storing all of wizardry's creative tabs. Also handles sorting of the items. * @@ -23,111 +22,100 @@ import net.minecraftforge.fml.relauncher.SideOnly; */ public final class WizardryTabs { - private static Comparator itemSorter; - private static Comparator spellItemSorter; + private WizardryTabs(){} // No instances! - // Creative Tabs - public static final CreativeTabs WIZARDRY = new CreativeTabs("ebwizardry"){ + public static final CreativeTabs WIZARDRY = new CreativeTabListed("ebwizardry"); + public static final CreativeTabs GEAR = new CreativeTabListed("ebwizardrygear"); + public static final CreativeTabs SPELLS = new CreativeTabSorted("ebwizardryspells", + + (stack1, stack2) -> { - @Override - @SideOnly(Side.CLIENT) - public ItemStack createIcon(){ - return new ItemStack(WizardryItems.wizard_handbook); - } + if((stack1.getItem() instanceof ItemSpellBook && stack2.getItem() instanceof ItemSpellBook) + || (stack1.getItem() instanceof ItemScroll && stack2.getItem() instanceof ItemScroll)){ - @Override - @SideOnly(Side.CLIENT) - public void displayAllRelevantItems(NonNullList items){ - super.displayAllRelevantItems(items); - Collections.sort(items, itemSorter); - } - }; + Spell spell1 = Spell.byMetadata(stack1.getItemDamage()); + Spell spell2 = Spell.byMetadata(stack2.getItemDamage()); + + return spell1.compareTo(spell2); + + }else if(stack1.getItem() instanceof ItemScroll){ + return 1; + }else if(stack2.getItem() instanceof ItemScroll){ + return -1; + } + return 0; + }, + + true); - public static final CreativeTabs SPELLS = new CreativeTabs("ebwizardryspells"){ + public static class CreativeTabSorted extends CreativeTabs { + + private ItemStack iconItem; + private final Comparator sorter; + private final boolean searchable; + + public CreativeTabSorted(String label, Comparator sorter){ + this(label, sorter, false); + } + + public CreativeTabSorted(String label, Comparator sorter, boolean searchable){ + super(label); + this.sorter = sorter; + this.searchable = searchable; + } @Override @SideOnly(Side.CLIENT) public ItemStack createIcon(){ - return new ItemStack(WizardryItems.spell_book); + return iconItem; + } + + public void setIconItem(ItemStack iconItem){ + this.iconItem = iconItem; } @Override @SideOnly(Side.CLIENT) public void displayAllRelevantItems(NonNullList items){ super.displayAllRelevantItems(items); - Collections.sort(items, spellItemSorter); + items.sort(sorter); } @Override public boolean hasSearchBar(){ - return true; + return searchable; } @Override @SideOnly(Side.CLIENT) public String getBackgroundImageName(){ - return "item_search.png"; + return searchable ? "item_search.png" : super.getBackgroundImageName(); } - }; + } + + public static class CreativeTabListed extends CreativeTabSorted { - /** Initialises the item sorters for the creative tabs. */ - public static void sort(){ + public final List order; - List orderedItemList = Arrays.asList( - - Item.getItemFromBlock(WizardryBlocks.arcane_workbench), - Item.getItemFromBlock(WizardryBlocks.crystal_ore), Item.getItemFromBlock(WizardryBlocks.crystal_block), - Item.getItemFromBlock(WizardryBlocks.crystal_flower), - Item.getItemFromBlock(WizardryBlocks.transportation_stone), WizardryItems.magic_crystal, - WizardryItems.magic_wand, WizardryItems.apprentice_wand, WizardryItems.advanced_wand, - WizardryItems.master_wand, WizardryItems.arcane_tome, WizardryItems.wizard_handbook, - WizardryItems.basic_fire_wand, WizardryItems.basic_ice_wand, WizardryItems.basic_lightning_wand, - WizardryItems.basic_necromancy_wand, WizardryItems.basic_earth_wand, WizardryItems.basic_sorcery_wand, - WizardryItems.basic_healing_wand, WizardryItems.smoke_bomb, WizardryItems.firebomb, - WizardryItems.poison_bomb, WizardryItems.blank_scroll, WizardryItems.identification_scroll, - WizardryItems.mana_flask, WizardryItems.storage_upgrade, WizardryItems.siphon_upgrade, - WizardryItems.condenser_upgrade, WizardryItems.range_upgrade, WizardryItems.duration_upgrade, - WizardryItems.cooldown_upgrade, WizardryItems.blast_upgrade, WizardryItems.attunement_upgrade, - WizardryItems.magic_silk, WizardryItems.armour_upgrade, WizardryItems.wizard_hat, - WizardryItems.wizard_robe, WizardryItems.wizard_leggings, WizardryItems.wizard_boots, - WizardryItems.wizard_hat_fire, WizardryItems.wizard_robe_fire, WizardryItems.wizard_leggings_fire, - WizardryItems.wizard_boots_fire, WizardryItems.wizard_hat_ice, WizardryItems.wizard_robe_ice, - WizardryItems.wizard_leggings_ice, WizardryItems.wizard_boots_ice, WizardryItems.wizard_hat_lightning, - WizardryItems.wizard_robe_lightning, WizardryItems.wizard_leggings_lightning, - WizardryItems.wizard_boots_lightning, WizardryItems.wizard_hat_necromancy, - WizardryItems.wizard_robe_necromancy, WizardryItems.wizard_leggings_necromancy, - WizardryItems.wizard_boots_necromancy, WizardryItems.wizard_hat_earth, WizardryItems.wizard_robe_earth, - WizardryItems.wizard_leggings_earth, WizardryItems.wizard_boots_earth, WizardryItems.wizard_hat_sorcery, - WizardryItems.wizard_robe_sorcery, WizardryItems.wizard_leggings_sorcery, - WizardryItems.wizard_boots_sorcery, WizardryItems.wizard_hat_healing, WizardryItems.wizard_robe_healing, - WizardryItems.wizard_leggings_healing, WizardryItems.wizard_boots_healing); - - itemSorter = (stack1, stack2) -> { - // Neither stack is in the creative tab - if(!orderedItemList.contains(stack1.getItem()) && !orderedItemList.contains(stack2.getItem())) return 0; - if(!orderedItemList.contains(stack1.getItem())) return 1; // Only stack 2 is in the creative tab - if(!orderedItemList.contains(stack2.getItem())) return -1; // Only stack 1 is in the creative tab - // Both stacks are in the creative tab - return orderedItemList.indexOf(stack1.getItem()) - orderedItemList.indexOf(stack2.getItem()); - }; - - spellItemSorter = (stack1, stack2) -> { - - if((stack1.getItem() instanceof ItemSpellBook && stack2.getItem() instanceof ItemSpellBook) - || (stack1.getItem() instanceof ItemScroll && stack2.getItem() instanceof ItemScroll)){ - - Spell spell1 = Spell.get(stack1.getItemDamage()); - Spell spell2 = Spell.get(stack2.getItemDamage()); - - return spell1.compareTo(spell2); - - }else if(stack1.getItem() instanceof ItemScroll){ - return 1; - }else if(stack2.getItem() instanceof ItemScroll){ - return -1; - } - return 0; - }; + public CreativeTabListed(String label){ + // Can't accomplish this in a single constructor... just a quirk of the java compiler! + this(label, new ArrayList<>()); + } + + // Hey, maybe someone might want to keep a reference to the list, or pass in a different one. + public CreativeTabListed(String label, List order){ + + super(label, (stack1, stack2) -> { + // Neither stack is in the creative tab + if(!order.contains(stack1.getItem()) && !order.contains(stack2.getItem())) return 0; + if(!order.contains(stack1.getItem())) return 1; // Only stack 2 is in the creative tab + if(!order.contains(stack2.getItem())) return -1; // Only stack 1 is in the creative tab + // Both stacks are in the creative tab + return order.indexOf(stack1.getItem()) - order.indexOf(stack2.getItem()); + }); + + this.order = order; + } } } diff --git a/src/main/java/electroblob/wizardry/spell/Arc.java b/src/main/java/electroblob/wizardry/spell/Arc.java index 4da75483..adfe2670 100644 --- a/src/main/java/electroblob/wizardry/spell/Arc.java +++ b/src/main/java/electroblob/wizardry/spell/Arc.java @@ -1,32 +1,32 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.EntityArc; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class Arc extends SpellRay { - - private static final float BASE_DAMAGE = 3; public Arc(){ - super("arc", Tier.BASIC, Element.LIGHTNING, SpellType.ATTACK, 5, 15, false, 8, null); + super("arc", false, EnumAction.NONE); + this.aimAssist(0.6f); + this.soundValues(1, 1.7f, 0.2f); + this.addProperties(DAMAGE); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ @@ -44,11 +44,9 @@ public class Arc extends SpellRay { target.getName(), this.getNameForTranslationFormatted()), true); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); } - - // TODO: Does this mean that players hit by the spell hear no sound? - target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, world.rand.nextFloat() * 0.4F + 1.5F); + return true; } @@ -56,12 +54,12 @@ public class Arc extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java index 099943c5..7f4be44a 100644 --- a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java +++ b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java @@ -1,47 +1,43 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityWizard; import electroblob.wizardry.event.SpellCastEvent; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.monster.EntitySpellcasterIllager; +import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber public class ArcaneJammer extends SpellRay { public ArcaneJammer(){ - super("arcane_jammer", Tier.ADVANCED, Element.HEALING, SpellType.ATTACK, 30, 50, false, 10, WizardrySounds.SPELL_DEFLECTION); + super("arcane_jammer", false, EnumAction.NONE); this.soundValues(0.7f, 1, 0.4f); + this.addProperties(EFFECT_DURATION); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ - if(target instanceof EntityWizard && caster instanceof EntityPlayer) - WizardryAdvancementTriggers.jam_wizard.triggerFor((EntityPlayer)caster); - if(!world.isRemote){ ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.arcane_jammer, - (int)(300 * modifiers.get(WizardryItems.duration_upgrade)), 0)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), 0)); } } @@ -49,12 +45,12 @@ public class ArcaneJammer extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } @@ -64,10 +60,18 @@ public class ArcaneJammer extends SpellRay { .spawn(world); } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.HIGHEST) // Prevents all spells so it comes before everything else public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ // Arcane jammer prevents spell casting. if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.arcane_jammer)) event.setCanceled(true); } + @SubscribeEvent + public static void onLivingUpdateEvent(LivingEvent.LivingUpdateEvent event){ + if(event.getEntity() instanceof EntitySpellcasterIllager + && event.getEntityLiving().isPotionActive(WizardryPotions.arcane_jammer)){ + ((EntitySpellcasterIllager)event.getEntity()).setSpellType(EntitySpellcasterIllager.SpellType.NONE); + } + } + } diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneLock.java b/src/main/java/electroblob/wizardry/spell/ArcaneLock.java new file mode 100644 index 00000000..38930604 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ArcaneLock.java @@ -0,0 +1,133 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.util.AllyDesignationSystem; +import electroblob.wizardry.util.NBTExtras; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.world.ExplosionEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +@Mod.EventBusSubscriber +public class ArcaneLock extends SpellRay { + + /** The NBT tag name for storing the owner's UUID in the tile entity data. */ + public static final String NBT_KEY = "arcaneLockOwner"; + + public ArcaneLock(){ + super("arcane_lock", false, EnumAction.NONE); + } + + @Override public boolean requiresPacket(){ return true; } + + @Override public boolean canBeCastByDispensers(){ return false; } + + @Override public boolean canBeCastByNPCs(){ return false; } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(caster instanceof EntityPlayer){ + + TileEntity tileentity = world.getTileEntity(pos); + + if(tileentity != null){ + + if(tileentity.getTileData().hasUniqueId(NBT_KEY)){ + // Unlocking + if(world.getPlayerEntityByUUID(tileentity.getTileData().getUniqueId(NBT_KEY)) == caster){ + NBTExtras.removeUniqueId(tileentity.getTileData(), NBT_KEY); + return true; + } + }else{ + // Locking + tileentity.getTileData().setUniqueId(NBT_KEY, caster.getUniqueID()); + return true; + } + } + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @SubscribeEvent + public static void onLeftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event){ + + if(!canBypassLocks(event.getEntityPlayer())){ + + TileEntity tileentity = event.getWorld().getTileEntity(event.getPos()); + + // Prevents arcane-locked containers from being broken + // Need to check if it has the unique id first because if it is absent getUniqueId will return the nil UUID + if(tileentity != null && tileentity.getTileData().hasUniqueId(ArcaneLock.NBT_KEY)){ + // Only the player that owns the lock may break the container + // If nobody owns it (i.e. it's part of a shrine), player will be null + // Why is getUniqueId marked @Nullable? It literally creates a UUID and returns it! + if(event.getEntityPlayer().getUniqueID() != tileentity.getTileData().getUniqueId(ArcaneLock.NBT_KEY)){ + event.setCanceled(true); + } + } + } + } + + @SubscribeEvent + public static void onRightClickBlockEvent(PlayerInteractEvent.RightClickBlock event){ + + if(!canBypassLocks(event.getEntityPlayer())){ + + TileEntity tileentity = event.getWorld().getTileEntity(event.getPos()); + + // Prevents arcane-locked containers from being opened + // Need to check if it has the unique id first because if it is absent getUniqueId will return the nil UUID + if(tileentity != null && tileentity.getTileData().hasUniqueId(ArcaneLock.NBT_KEY)){ + // Why is getUniqueId marked @Nullable? It literally creates a UUID and returns it! + EntityPlayer owner = event.getWorld().getPlayerEntityByUUID(tileentity.getTileData().getUniqueId(ArcaneLock.NBT_KEY)); + // Only the player that owns the lock or an ally of that player may open the container + // If nobody owns it (i.e. it's part of a shrine, or the owner logged out), player will be null + // Unfortunately we can't get the owner's allies if the owner is offline + // Perhaps if this crops up again we can store inverted 'ally of' maps as well? + if(owner == null || (owner != event.getEntityPlayer() && !AllyDesignationSystem.isPlayerAlly(owner, event.getEntityPlayer()))){ + event.setCanceled(true); + } + } + } + } + + private static boolean canBypassLocks(EntityPlayer player){ + + if(!player.isCreative()) return false; + if(Wizardry.settings.creativeBypassesArcaneLock) return true; + MinecraftServer server = player.world.getMinecraftServer(); + return server != null && WizardryUtilities.isPlayerOp(player, server); + } + + @SubscribeEvent + public static void onExplosionEvent(ExplosionEvent.Detonate event){ + // Prevents arcane-locked containers from being exploded + event.getAffectedBlocks().removeIf(pos -> event.getWorld().getTileEntity(pos) != null + && event.getWorld().getTileEntity(pos).getTileData().hasUniqueId(NBT_KEY)); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ArrowRain.java b/src/main/java/electroblob/wizardry/spell/ArrowRain.java index 796641fd..11f598ae 100644 --- a/src/main/java/electroblob/wizardry/spell/ArrowRain.java +++ b/src/main/java/electroblob/wizardry/spell/ArrowRain.java @@ -1,23 +1,20 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityArrowRain; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; import net.minecraft.world.World; public class ArrowRain extends SpellConstructRanged { public ArrowRain(){ - super("arrow_rain", Tier.MASTER, Element.SORCERY, SpellType.ATTACK, 75, 300, EntityArrowRain::new, 120, 20, WizardrySounds.SPELL_SUMMONING); + super("arrow_rain", EntityArrowRain::new, false); this.floor(true); } @Override - protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ // Moves the entity back towards the caster a bit, so the area of effect is better centred on the position. // 3 is the distance to move the entity back towards the caster. @@ -29,11 +26,11 @@ public class ArrowRain extends SpellConstructRanged { // Moves the entity up 5 blocks so that it is above mobs' heads. y += 5; - return super.spawnConstruct(world, x, y, z, caster, modifiers); + return super.spawnConstruct(world, x, y, z, side, caster, modifiers); } @Override - protected void addConstructExtras(EntityArrowRain construct, EntityLivingBase caster, SpellModifiers modifiers){ + protected void addConstructExtras(EntityArrowRain construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ // Makes the arrows shoot in the direction the caster was looking when they cast the spell. construct.rotationYaw = caster.rotationYawHead; } diff --git a/src/main/java/electroblob/wizardry/spell/Banish.java b/src/main/java/electroblob/wizardry/spell/Banish.java index f1523866..9777892f 100644 --- a/src/main/java/electroblob/wizardry/spell/Banish.java +++ b/src/main/java/electroblob/wizardry/spell/Banish.java @@ -1,8 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; @@ -10,79 +7,48 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Banish extends SpellRay { + public static final String MINIMUM_TELEPORT_DISTANCE = "minimum_teleport_distance"; + public static final String MAXIMUM_TELEPORT_DISTANCE = "maximum_teleport_distance"; + public Banish(){ - super("banish", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 15, 40, false, 10, SoundEvents.ENTITY_ENDERMEN_TELEPORT); + super("banish", false, EnumAction.NONE); + this.addProperties(MINIMUM_TELEPORT_DISTANCE, MAXIMUM_TELEPORT_DISTANCE); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(target instanceof EntityLivingBase){ EntityLivingBase entity = (EntityLivingBase)target; - double radius = (8 + world.rand.nextDouble() * 8) * modifiers.get(WizardryItems.range_upgrade); - double angle = world.rand.nextDouble() * Math.PI * 2; + double minRadius = getProperty(MINIMUM_TELEPORT_DISTANCE).doubleValue(); + double maxRadius = getProperty(MAXIMUM_TELEPORT_DISTANCE).doubleValue(); + double radius = (minRadius + world.rand.nextDouble() * maxRadius-minRadius) * modifiers.get(WizardryItems.blast_upgrade); - int x = MathHelper.floor(entity.posX + Math.sin(angle) * radius); - int z = MathHelper.floor(entity.posZ - Math.cos(angle) * radius); - int y = WizardryUtilities.getNearestFloorLevel(world, - new BlockPos(x, (int)caster.getEntityBoundingBox().minY, z), (int)radius); - - if(world.isRemote){ - for(int i=0; i<10; i++){ - double dx1 = entity.posX; - double dy1 = entity.getEntityBoundingBox().minY + entity.height * world.rand.nextFloat(); - double dz1 = entity.posZ; - world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, - world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); - } - - // Can't be bothered to route this through the proxies! - if(entity == net.minecraft.client.Minecraft.getMinecraft().player) - electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); - } - - if(y > -1){ - - // This means stuff like snow layers is ignored, meaning when on snow-covered ground the target does - // not teleport 1 block above the ground. - if(!world.getBlockState(new BlockPos(x, y, z)).getMaterial().blocksMovement()){ - y--; - } - - if(world.getBlockState(new BlockPos(x, y + 1, z)).getMaterial().blocksMovement() - || world.getBlockState(new BlockPos(x, y + 2, z)).getMaterial().blocksMovement()){ - return false; - } - - if(!world.isRemote){ - entity.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); - } - - entity.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); - } + teleport(entity, world, radius); } return true; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } @@ -92,4 +58,52 @@ public class Banish extends SpellRay { ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.2f, 0, 0.2f).spawn(world); } + // Extracted as a separate method for external use + public boolean teleport(EntityLivingBase entity, World world, double radius){ + + float angle = world.rand.nextFloat() * (float)Math.PI * 2; + + int x = MathHelper.floor(entity.posX + MathHelper.sin(angle) * radius); + int z = MathHelper.floor(entity.posZ - MathHelper.cos(angle) * radius); + Integer y = WizardryUtilities.getNearestFloor(world, + new BlockPos(x, (int)entity.getEntityBoundingBox().minY, z), (int)radius); + + if(world.isRemote){ + + for(int i=0; i<10; i++){ + double dx1 = entity.posX; + double dy1 = entity.getEntityBoundingBox().minY + entity.height * world.rand.nextFloat(); + double dz1 = entity.posZ; + world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, + world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); + } + + // Can't be bothered to route this through the proxies! + if(entity == net.minecraft.client.Minecraft.getMinecraft().player) + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); + } + + if(y != null){ + + // This means stuff like snow layers is ignored, meaning when on snow-covered ground the target does + // not teleport 1 block above the ground. + if(!world.getBlockState(new BlockPos(x, y, z)).getMaterial().blocksMovement()){ + y--; + } + + if(world.getBlockState(new BlockPos(x, y + 1, z)).getMaterial().blocksMovement() + || world.getBlockState(new BlockPos(x, y + 2, z)).getMaterial().blocksMovement()){ + return false; + } + + if(!world.isRemote){ + entity.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); + } + + this.playSound(world, entity, 0, -1, new SpellModifiers()); + } + + return true; + } + } diff --git a/src/main/java/electroblob/wizardry/spell/Blink.java b/src/main/java/electroblob/wizardry/spell/Blink.java index 8aacc347..f6adf784 100644 --- a/src/main/java/electroblob/wizardry/spell/Blink.java +++ b/src/main/java/electroblob/wizardry/spell/Blink.java @@ -1,15 +1,12 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; @@ -22,14 +19,15 @@ import net.minecraft.world.World; public class Blink extends Spell { public Blink(){ - super("blink", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 15, 25, EnumAction.NONE, false); + super("blink", EnumAction.NONE, false); + addProperties(RANGE); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - RayTraceResult rayTrace = WizardryUtilities.standardBlockRayTrace(world, caster, - 25 * modifiers.get(WizardryItems.range_upgrade), false); + RayTraceResult rayTrace = RayTracer.standardBlockRayTrace(world, caster, + getProperty(RANGE).doubleValue() * modifiers.get(WizardryItems.range_upgrade), false); // It's worth noting that on the client side, the cast() method only gets called if the server side // cast method succeeded, so you need not check any conditions for spawning particles. @@ -52,8 +50,8 @@ public class Blink extends Spell { BlockPos pos = rayTrace.getBlockPos(); - // Can't teleport onto the ceiling. - if(rayTrace.sideHit == EnumFacing.DOWN) return false; + // Leave space for the player's head + if(rayTrace.sideHit == EnumFacing.DOWN) pos = pos.down(); // This means stuff like snow layers is ignored, meaning when on snow-covered ground the player does // not teleport 1 block above the ground. @@ -61,7 +59,7 @@ public class Blink extends Spell { pos = pos.down(); } - pos = rayTrace.getBlockPos().offset(rayTrace.sideHit); + pos = pos.offset(rayTrace.sideHit); // Prevents the player from teleporting into blocks and suffocating. if(world.getBlockState(pos).getMaterial().blocksMovement() @@ -70,11 +68,11 @@ public class Blink extends Spell { } // Plays before and after so it is heard from both positions - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); if(!world.isRemote) caster.setPositionAndUpdate(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); caster.swingArm(hand); return true; } @@ -86,14 +84,14 @@ public class Blink extends Spell { public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - double angle = Math.atan2(target.posZ - caster.posZ, target.posX - caster.posX) - + world.rand.nextDouble() * Math.PI; + float angle = (float)(Math.atan2(target.posZ - caster.posZ, target.posX - caster.posX) + + world.rand.nextDouble() * Math.PI); double radius = caster.getDistance(target.posX, target.getEntityBoundingBox().minY, target.posZ) + world.rand.nextDouble() * 3.0d; - int x = MathHelper.floor(target.posX + Math.sin(angle) * radius); - int z = MathHelper.floor(target.posZ - Math.cos(angle) * radius); - int y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(caster), (int)radius); + int x = MathHelper.floor(target.posX + MathHelper.sin(angle) * radius); + int z = MathHelper.floor(target.posZ - MathHelper.cos(angle) * radius); + Integer y = WizardryUtilities.getNearestFloor(world, new BlockPos(caster), (int)radius); // It's worth noting that on the client side, the cast() method only gets called if the server side // cast method succeeded, so you need not check any conditions for spawning particles. @@ -109,7 +107,7 @@ public class Blink extends Spell { } } - if(y > -1){ + if(y != null){ // This means stuff like snow layers is ignored, meaning when on snow-covered ground the caster does // not teleport 1 block above the ground. @@ -123,13 +121,13 @@ public class Blink extends Spell { } // Plays before and after so it is heard from both positions - caster.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); if(!world.isRemote){ caster.setPositionAndUpdate(x + 0.5, y + 1, z + 0.5); } - caster.playSound(SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); caster.swingArm(hand); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Bubble.java b/src/main/java/electroblob/wizardry/spell/Bubble.java index 34b1698f..2ac47406 100644 --- a/src/main/java/electroblob/wizardry/spell/Bubble.java +++ b/src/main/java/electroblob/wizardry/spell/Bubble.java @@ -1,11 +1,7 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityBubble; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -13,40 +9,30 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Bubble extends SpellRay { public Bubble(){ - super("bubble", Tier.APPRENTICE, Element.EARTH, SpellType.ATTACK, 15, 20, false, 10, WizardrySounds.SPELL_ICE); + super("bubble", false, EnumAction.NONE); this.soundValues(0.5f, 1.1f, 0.2f); + addProperties(DURATION); } - + @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // This spell uses more than one sound, so this is required... - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_GENERIC_SWIM, 1, 1 + 0.2f * world.rand.nextFloat()); - return flag; + protected SoundEvent[] createSounds(){ + return this.createSoundsWithSuffixes("shoot", "splash"); } - + @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag) caster.playSound(SoundEvents.ENTITY_GENERIC_SWIM, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); - return flag; - } - - @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ @@ -57,7 +43,7 @@ public class Bubble extends SpellRay { EntityBubble bubble = new EntityBubble(world); bubble.setPosition(target.posX, target.posY, target.posZ); bubble.setCaster(caster); - bubble.lifetime = ((int)(200 * modifiers.get(WizardryItems.duration_upgrade))); + bubble.lifetime = ((int)(getProperty(DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); bubble.isDarkOrb = false; bubble.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); @@ -70,12 +56,12 @@ public class Bubble extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/ChainLightning.java b/src/main/java/electroblob/wizardry/spell/ChainLightning.java index 36bfa78d..83b3df2f 100644 --- a/src/main/java/electroblob/wizardry/spell/ChainLightning.java +++ b/src/main/java/electroblob/wizardry/spell/ChainLightning.java @@ -1,79 +1,81 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.EntityArc; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; +import java.util.List; + public class ChainLightning extends SpellRay { - private static final float PRIMARY_DAMAGE = 10; - private static final float SECONDARY_DAMAGE = 8; - private static final float TERTIARY_DAMAGE = 6; + public static final String PRIMARY_DAMAGE = "primary_damage"; + public static final String SECONDARY_DAMAGE = "secondary_damage"; + public static final String TERTIARY_DAMAGE = "tertiary_damage"; - private static final double PRIMARY_RANGE = 10; - private static final double SECONDARY_RANGE = 5; - private static final double TERTIARY_RANGE = 5; + public static final String SECONDARY_RANGE = "secondary_range"; + public static final String TERTIARY_RANGE = "tertiary_range"; - private static final int SECONDARY_MAX_TARGETS = 5; - private static final int TERTIARY_MAX_TARGETS = 2; // This is per secondary target, giving 10 in total + public static final String SECONDARY_MAX_TARGETS = "secondary_max_targets"; + public static final String TERTIARY_MAX_TARGETS = "tertiary_max_targets"; // This is per secondary target public ChainLightning(){ - super("chain_lightning", Tier.ADVANCED, Element.LIGHTNING, SpellType.ATTACK, 25, 50, false, PRIMARY_RANGE, null); + super("chain_lightning", false, EnumAction.NONE); + this.aimAssist(0.6f); + this.soundValues(1, 1.7f, 0.2f); + addProperties(PRIMARY_DAMAGE, SECONDARY_DAMAGE, TERTIARY_DAMAGE, SECONDARY_RANGE, TERTIARY_RANGE, + SECONDARY_MAX_TARGETS, TERTIARY_MAX_TARGETS); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ // Anything can be attacked with the initial arc, because the player has control over where it goes. If they // hit a minion or an ally, it's their problem! if(WizardryUtilities.isLiving(target)){ - electrocute(world, caster, caster, target, PRIMARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + electrocute(world, caster, origin, target, getProperty(PRIMARY_DAMAGE).floatValue() + * modifiers.get(SpellModifiers.POTENCY)); // Secondary chaining effect - List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(SECONDARY_RANGE, - target.posX, target.posY + target.height / 2, target.posZ, world); + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius( + getProperty(SECONDARY_RANGE).doubleValue(), target.posX, target.posY + target.height / 2, target.posZ, world); secondaryTargets.remove(target); secondaryTargets.removeIf(e -> !WizardryUtilities.isLiving(e)); - secondaryTargets.removeIf(e -> !WizardryUtilities.isValidTarget(caster, e)); - if(secondaryTargets.size() > SECONDARY_MAX_TARGETS) secondaryTargets = secondaryTargets.subList(0, SECONDARY_MAX_TARGETS); + secondaryTargets.removeIf(e -> !AllyDesignationSystem.isValidTarget(caster, e)); + if(secondaryTargets.size() > getProperty(SECONDARY_MAX_TARGETS).intValue()) + secondaryTargets = secondaryTargets.subList(0, getProperty(SECONDARY_MAX_TARGETS).intValue()); for(EntityLivingBase secondaryTarget : secondaryTargets){ - electrocute(world, caster, target, secondaryTarget, - SECONDARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + electrocute(world, caster, target.getPositionVector().add(0, target.height/2, 0), secondaryTarget, + getProperty(SECONDARY_DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); // Tertiary chaining effect - List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(TERTIARY_RANGE, - secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, - secondaryTarget.posZ, world); + List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius( + getProperty(TERTIARY_RANGE).doubleValue(), secondaryTarget.posX, + secondaryTarget.posY + secondaryTarget.height / 2, secondaryTarget.posZ, world); tertiaryTargets.remove(target); tertiaryTargets.removeAll(secondaryTargets); tertiaryTargets.removeIf(e -> !WizardryUtilities.isLiving(e)); - tertiaryTargets.removeIf(e -> !WizardryUtilities.isValidTarget(caster, e)); - if(tertiaryTargets.size() > TERTIARY_MAX_TARGETS) tertiaryTargets = tertiaryTargets.subList(0, TERTIARY_MAX_TARGETS); + tertiaryTargets.removeIf(e -> !AllyDesignationSystem.isValidTarget(caster, e)); + if(tertiaryTargets.size() > getProperty(TERTIARY_MAX_TARGETS).intValue()) + tertiaryTargets = tertiaryTargets.subList(0, getProperty(TERTIARY_MAX_TARGETS).intValue()); for(EntityLivingBase tertiaryTarget : tertiaryTargets){ - electrocute(world, caster, secondaryTarget, tertiaryTarget, - TERTIARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + electrocute(world, caster, secondaryTarget.getPositionVector().add(0, secondaryTarget.height/2, 0), + tertiaryTarget, getProperty(TERTIARY_DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); } } @@ -84,16 +86,16 @@ public class ChainLightning extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } - private void electrocute(World world, Entity caster, Entity origin, Entity target, float damage){ + private void electrocute(World world, Entity caster, Vec3d origin, Entity target, float damage){ if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( @@ -111,7 +113,7 @@ public class ChainLightning extends SpellRay { ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); } - target.playSound(WizardrySounds.SPELL_SPARK, 1, 1.5f + 0.4f * world.rand.nextFloat()); + //target.playSound(WizardrySounds.SPELL_SPARK, 1, 1.5f + 0.4f * world.rand.nextFloat()); } } diff --git a/src/main/java/electroblob/wizardry/spell/Charge.java b/src/main/java/electroblob/wizardry/spell/Charge.java new file mode 100644 index 00000000..d6e9a4df --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Charge.java @@ -0,0 +1,125 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.data.IVariable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.living.LivingAttackEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.List; + +@Mod.EventBusSubscriber +public class Charge extends Spell { + + public static final IVariable CHARGE_TIME = new IVariable.Variable(Persistence.NEVER).withTicker(Charge::update); + public static final IVariable CHARGE_MODIFIERS = new IVariable.Variable<>(Persistence.NEVER); + + public static final String CHARGE_SPEED = "charge_speed"; + public static final String KNOCKBACK_STRENGTH = "knockback_strength"; + + private static final double EXTRA_HIT_MARGIN = 1; + + public Charge(){ + super("charge", EnumAction.NONE, false); + addProperties(CHARGE_SPEED, DURATION, DAMAGE, KNOCKBACK_STRENGTH); + this.soundValues(0.6f, 1, 0); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + WizardData.get(caster).setVariable(CHARGE_TIME, (int)(getProperty(DURATION).floatValue() + * modifiers.get(WizardryItems.duration_upgrade))); + + WizardData.get(caster).setVariable(CHARGE_MODIFIERS, modifiers); + + if(world.isRemote) world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX, caster.posY + caster.height/2, caster.posZ, 0, 0, 0); + + this.playSound(world, caster, ticksInUse, -1, modifiers); + + return true; + } + + private static int update(EntityPlayer player, Integer chargeTime){ + + if(chargeTime == null) chargeTime = 0; + + if(chargeTime > 0){ + + SpellModifiers modifiers = WizardData.get(player).getVariable(CHARGE_MODIFIERS); + if(modifiers == null) modifiers = new SpellModifiers(); + + Vec3d look = player.getLookVec(); + + float speed = Spells.charge.getProperty(Charge.CHARGE_SPEED).floatValue() * modifiers.get(WizardryItems.range_upgrade); + + player.motionX = look.x * speed; + player.motionZ = look.z * speed; + + if(player.world.isRemote){ + for(int i = 0; i < 5; i++){ + ParticleBuilder.create(Type.SPARK, player).spawn(player.world); + } + } + + List collided = player.world.getEntitiesWithinAABB(EntityLivingBase.class, player.getEntityBoundingBox().grow(EXTRA_HIT_MARGIN)); + + collided.remove(player); + + float damage = Spells.charge.getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY); + float knockback = Spells.charge.getProperty(KNOCKBACK_STRENGTH).floatValue(); + + collided.forEach(e -> e.attackEntityFrom(MagicDamage.causeDirectMagicDamage(player, MagicDamage.DamageType.SHOCK), damage)); + collided.forEach(e -> e.addVelocity(player.motionX * knockback, player.motionY * knockback + 0.3f, player.motionZ * knockback)); + + if(player.world.isRemote) player.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, + player.posX + player.motionX, player.posY + player.height/2, player.posZ + player.motionZ, 0, 0, 0); + + if(collided.isEmpty()) chargeTime--; + else{ + WizardryUtilities.playSoundAtPlayer(player, SoundEvents.ENTITY_GENERIC_HURT, 1, 1); + chargeTime = 0; + } + } + + return chargeTime; + } + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void onLivingAttackEvent(LivingAttackEvent event){ + // Players are immune to melee damage while charging + if(event.getEntity() instanceof EntityPlayer && event.getSource().getTrueSource() instanceof EntityLivingBase){ + + EntityPlayer player = (EntityPlayer)event.getEntity(); + EntityLivingBase attacker = (EntityLivingBase)event.getSource().getTrueSource(); + + if(WizardData.get(player) != null){ + + Integer chargeTime = WizardData.get(player).getVariable(CHARGE_TIME); + + if(chargeTime != null && chargeTime > 0 + && player.getEntityBoundingBox().grow(EXTRA_HIT_MARGIN).intersects(attacker.getEntityBoundingBox())){ + event.setCanceled(true); + } + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java index 870f994a..0e638ceb 100644 --- a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java +++ b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java @@ -1,21 +1,17 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.item.ItemWand; +import electroblob.wizardry.data.IStoredVariable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.misc.WizardryPathFinder; import electroblob.wizardry.packet.PacketClairvoyance; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WandHelper; -import electroblob.wizardry.util.WizardryPathFinder; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.player.EntityPlayer; @@ -39,23 +35,30 @@ public class Clairvoyance extends Spell { /** The number of ticks it takes each path particle to move from one path point to the next. */ public static final int PARTICLE_MOVEMENT_INTERVAL = 45; + public static final IStoredVariable LOCATION_KEY = IStoredVariable.StoredVariable.ofBlockPos("clairvoyancePos", Persistence.ALWAYS); + public static final IStoredVariable DIMENSION_KEY = IStoredVariable.StoredVariable.ofInt("clairvoyanceDimension", Persistence.ALWAYS); + public Clairvoyance(){ - super("clairvoyance", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 20, 100, EnumAction.BOW, false); + super("clairvoyance", EnumAction.BOW, false); + addProperties(RANGE, DURATION); + WizardData.registerStoredVariables(LOCATION_KEY, DIMENSION_KEY); } - @Override - public boolean doesSpellRequirePacket(){ - return false; - } + @Override public boolean canBeCastByNPCs() { return false; } + @Override public boolean canBeCastByDispensers() { return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - WizardData properties = WizardData.get(caster); + WizardData data = WizardData.get(caster); - if(properties != null && !caster.isSneaking()){ - if(caster.dimension == properties.getClairvoyanceDimension()){ - if(properties.getClairvoyanceLocation() != null){ + if(data != null && !caster.isSneaking()){ + + Integer dimension = data.getVariable(DIMENSION_KEY); + BlockPos location = data.getVariable(LOCATION_KEY); + + if(dimension != null && caster.dimension == dimension){ + if(location != null){ if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".searching"), true); @@ -66,16 +69,15 @@ public class Clairvoyance extends Spell { } }; arbitraryZombie.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE) - .setBaseValue(256 * modifiers.get(WizardryItems.range_upgrade)); + .setBaseValue(getProperty(RANGE).doubleValue() * modifiers.get(WizardryItems.range_upgrade)); arbitraryZombie.setPosition(caster.posX, caster.posY, caster.posZ); arbitraryZombie.setPathPriority(PathNodeType.WATER, 0.0F); arbitraryZombie.onGround = true; - BlockPos destination = properties.getClairvoyanceLocation(); - WizardryPathFinder pathfinder = new WizardryPathFinder(arbitraryZombie.getNavigator().getNodeProcessor()); - Path path = pathfinder.findPath(world, arbitraryZombie, destination, 256 * modifiers.get(WizardryItems.range_upgrade)); + Path path = pathfinder.findPath(world, arbitraryZombie, location, + getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade)); if(path != null && path.getFinalPathPoint() != null){ @@ -83,9 +85,9 @@ public class Clairvoyance extends Spell { int y = path.getFinalPathPoint().y; int z = path.getFinalPathPoint().z; - if(x == destination.getX() && y == destination.getY() && z == destination.getZ()){ + if(x == location.getX() && y == location.getY() && z == location.getZ()){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); if(!world.isRemote && caster instanceof EntityPlayerMP){ WizardryPacketHandler.net.sendTo(new PacketClairvoyance.Message(path, modifiers.get(WizardryItems.duration_upgrade)), @@ -107,13 +109,16 @@ public class Clairvoyance extends Spell { } // Fixes the problem with the sound not playing for the client of the caster. - if(world.isRemote) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + if(world.isRemote) this.playSound(world, caster, ticksInUse, -1, modifiers); return false; } public static void spawnPathPaticles(World world, Path path, float durationMultiplier){ + // A bit annoying that we have to use the reference here but there's no easy way around it + float duration = Spells.clairvoyance.getProperty(DURATION).floatValue(); + PathPoint point, nextPoint; while(!path.isFinished()){ @@ -127,7 +132,7 @@ public class Clairvoyance extends Spell { (nextPoint.x - point.x) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.y - point.y) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.z - point.z) / (float)PARTICLE_MOVEMENT_INTERVAL) - .time((int)(1800 * durationMultiplier)).clr(0, 1, 0.3f).spawn(world); + .time((int)(duration * durationMultiplier)).clr(0, 1, 0.3f).spawn(world); path.incrementPathIndex(); path.incrementPathIndex(); @@ -136,7 +141,7 @@ public class Clairvoyance extends Spell { point = path.getFinalPathPoint(); ParticleBuilder.create(Type.PATH).pos(point.x + 0.5, point.y + 0.5, point.z + 0.5) - .time((int)(1800 * durationMultiplier)).clr(1, 1, 1).spawn(world); + .time((int)(duration * durationMultiplier)).clr(1f, 1f, 1f).spawn(world); } @SubscribeEvent @@ -145,17 +150,19 @@ public class Clairvoyance extends Spell { if(event.getEntityPlayer().isSneaking()){ // The event now has an ItemStack, which greatly simplifies hand-related stuff. - ItemStack wand = event.getItemStack(); + ItemStack stack = event.getItemStack(); - if(wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Clairvoyance){ + if(stack.getItem() instanceof ISpellCastingItem + && ((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack) instanceof Clairvoyance){ - WizardData properties = WizardData.get(event.getEntityPlayer()); + WizardData data = WizardData.get(event.getEntityPlayer()); + + if(data != null){ - if(properties != null){ - // THIS is why BlockPos is a thing - in 1.7.10 this requires a clumsy switch statement. BlockPos pos = event.getPos().offset(event.getFace()); - properties.setClairvoyancePoint(pos, event.getWorld().provider.getDimension()); + data.setVariable(LOCATION_KEY, pos); + data.setVariable(DIMENSION_KEY, event.getWorld().provider.getDimension()); if(!event.getWorld().isRemote){ event.getEntityPlayer().sendStatusMessage( diff --git a/src/main/java/electroblob/wizardry/spell/Cobwebs.java b/src/main/java/electroblob/wizardry/spell/Cobwebs.java index 1e78ac2d..9d2367a1 100644 --- a/src/main/java/electroblob/wizardry/spell/Cobwebs.java +++ b/src/main/java/electroblob/wizardry/spell/Cobwebs.java @@ -1,63 +1,58 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.constants.Constants; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.tileentity.TileEntityTimer; import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import java.util.List; + public class Cobwebs extends SpellRay { - private static final int BASE_DURATION = 400; - public Cobwebs(){ - super("cobwebs", Tier.ADVANCED, Element.EARTH, SpellType.ATTACK, 30, 70, false, 12, SoundEvents.BLOCK_LAVA_EXTINGUISH); - this.ignoreEntities(true); + super("cobwebs", false, EnumAction.NONE); + this.ignoreLivingEntities(true); + addProperties(EFFECT_RADIUS, DURATION); } - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ boolean flag = false; pos = pos.offset(side); - if(world.isAirBlock(pos)){ - if(!world.isRemote){ - world.setBlockState(pos, WizardryBlocks.vanishing_cobweb.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityTimer){ - ((TileEntityTimer)world.getTileEntity(pos)) - .setLifetime((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); - } - } - flag = true; - } + int blastUpgradeCount = (int)((modifiers.get(WizardryItems.blast_upgrade) - 1) / Constants.RANGE_INCREASE_PER_LEVEL + 0.5f); - for(EnumFacing facing : EnumFacing.values()){ + float radius = getProperty(EFFECT_RADIUS).floatValue() + 0.73f * blastUpgradeCount; - BlockPos pos1 = pos.offset(facing); + List sphere = WizardryUtilities.getBlockSphere(pos, radius * modifiers.get(WizardryItems.blast_upgrade)); + + for(BlockPos pos1 : sphere){ if(world.isAirBlock(pos1)){ if(!world.isRemote){ world.setBlockState(pos1, WizardryBlocks.vanishing_cobweb.getDefaultState()); if(world.getTileEntity(pos1) instanceof TileEntityTimer){ ((TileEntityTimer)world.getTileEntity(pos1)) - .setLifetime((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); + .setLifetime((int)(getProperty(DURATION).doubleValue() + * modifiers.get(WizardryItems.duration_upgrade))); } } flag = true; @@ -68,7 +63,7 @@ public class Cobwebs extends SpellRay { } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/ConjureArmour.java b/src/main/java/electroblob/wizardry/spell/ConjureArmour.java index 9ae9ce91..ff2294a2 100644 --- a/src/main/java/electroblob/wizardry/spell/ConjureArmour.java +++ b/src/main/java/electroblob/wizardry/spell/ConjureArmour.java @@ -1,22 +1,28 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import com.google.common.collect.ImmutableMap; import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagList; +import java.util.Map; + public class ConjureArmour extends SpellConjuration { + + private static final Map SPECTRAL_ARMOUR_MAP = ImmutableMap.of( + EntityEquipmentSlot.HEAD, WizardryItems.spectral_helmet, + EntityEquipmentSlot.CHEST, WizardryItems.spectral_chestplate, + EntityEquipmentSlot.LEGS, WizardryItems.spectral_leggings, + EntityEquipmentSlot.FEET, WizardryItems.spectral_boots); public ConjureArmour(){ - super("conjure_armour", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 45, 50, null, WizardrySounds.SPELL_CONJURATION); + super("conjure_armour", null); } @Override @@ -29,9 +35,9 @@ public class ConjureArmour extends SpellConjuration { for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ if(caster.getItemStackFromSlot(slot).isEmpty() && - !WizardryUtilities.doesPlayerHaveItem(caster, WizardryItems.SPECTRAL_ARMOUR_MAP.get(slot))){ + !WizardryUtilities.doesPlayerHaveItem(caster, SPECTRAL_ARMOUR_MAP.get(slot))){ - armour = new ItemStack(WizardryItems.SPECTRAL_ARMOUR_MAP.get(slot)); + armour = new ItemStack(SPECTRAL_ARMOUR_MAP.get(slot)); IConjuredItem.setDurationMultiplier(armour, modifiers.get(WizardryItems.duration_upgrade)); // Sets a blank "ench" tag to trick the renderer into showing the enchantment effect on the armour model armour.getTagCompound().setTag("ench", new NBTTagList()); diff --git a/src/main/java/electroblob/wizardry/spell/ConjureBlock.java b/src/main/java/electroblob/wizardry/spell/ConjureBlock.java new file mode 100644 index 00000000..23250b49 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ConjureBlock.java @@ -0,0 +1,79 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.tileentity.TileEntityTimer; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class ConjureBlock extends SpellRay { + + private static final String BLOCK_LIFETIME = "block_lifetime"; + + public ConjureBlock(){ + super("conjure_block", false, EnumAction.NONE); + this.ignoreLivingEntities(true); + addProperties(BLOCK_LIFETIME); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(world.getBlockState(pos).getBlock() == WizardryBlocks.spectral_block){ + + if(!world.isRemote){ + // Dispelling of blocks + world.setBlockToAir(pos); + }else{ + ParticleBuilder.create(Type.FLASH).pos(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5).scale(3) + .clr(0.75f, 1, 0.85f).spawn(world); + } + + return true; + } + + pos = pos.offset(side); + + if(world.isRemote){ + ParticleBuilder.create(Type.FLASH).pos(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5).scale(3) + .clr(0.75f, 1, 0.85f).spawn(world); + } + + if(WizardryUtilities.canBlockBeReplaced(world, pos)){ + + if(!world.isRemote){ + + world.setBlockState(pos, WizardryBlocks.spectral_block.getDefaultState()); + + if(world.getTileEntity(pos) instanceof TileEntityTimer){ + ((TileEntityTimer)world.getTileEntity(pos)).setLifetime((int)(getProperty(BLOCK_LIFETIME).floatValue() + * modifiers.get(WizardryItems.duration_upgrade))); + } + } + + return true; + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Containment.java b/src/main/java/electroblob/wizardry/spell/Containment.java new file mode 100644 index 00000000..cc9c0b71 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Containment.java @@ -0,0 +1,54 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class Containment extends SpellRay { + + public Containment(){ + super("containment", false, EnumAction.NONE); + this.soundValues(1, 1, 0.2f); + addProperties(EFFECT_DURATION, EFFECT_STRENGTH); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.containment, + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)))); + } + + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.PATH).pos(x, y, z).clr(0x7988cc).time(20 + world.rand.nextInt(8)).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(1f, 1f, 1f).spawn(world); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/CureEffects.java b/src/main/java/electroblob/wizardry/spell/CureEffects.java index d0f4a372..6be6e69a 100644 --- a/src/main/java/electroblob/wizardry/spell/CureEffects.java +++ b/src/main/java/electroblob/wizardry/spell/CureEffects.java @@ -1,25 +1,36 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; public class CureEffects extends SpellBuff { public CureEffects(){ - super("cure_effects", Tier.APPRENTICE, Element.HEALING, SpellType.DEFENCE, 25, 40, WizardrySounds.SPELL_HEAL, 0.8f, 0.8f, 1); + super("cure_effects", 0.8f, 0.8f, 1); this.soundValues(0.7f, 1.2f, 0.4f); } @Override protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ - + if(!caster.getActivePotionEffects().isEmpty()){ - caster.clearActivePotions(); - return true; + + ItemStack milk = new ItemStack(Items.MILK_BUCKET); + + boolean flag = false; + + for(PotionEffect effect : caster.getActivePotionEffects()){ + // The PotionEffect version (as opposed to Potion) does not call cleanup callbacks + if(effect.isCurativeItem(milk)){ + caster.removePotionEffect(effect.getPotion()); + flag = true; + } + } + + return flag; } return false; diff --git a/src/main/java/electroblob/wizardry/spell/CurseOfEnfeeblement.java b/src/main/java/electroblob/wizardry/spell/CurseOfEnfeeblement.java new file mode 100644 index 00000000..a6a5f2e1 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/CurseOfEnfeeblement.java @@ -0,0 +1,60 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class CurseOfEnfeeblement extends SpellRay { + + public CurseOfEnfeeblement(){ + super("curse_of_enfeeblement", false, EnumAction.NONE); + this.soundValues(1, 1.1f, 0.2f); + addProperties(EFFECT_STRENGTH); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + // This will actually run out in the end, but only if you leave Minecraft running for 3.4 years + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_enfeeblement, + Integer.MAX_VALUE, getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)))); + // Reduce the target's health to its new max health if necessary + if(((EntityLivingBase)target).getHealth() > ((EntityLivingBase)target).getMaxHealth()){ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, MagicDamage.DamageType.WITHER), + ((EntityLivingBase)target).getHealth() - ((EntityLivingBase)target).getMaxHealth()); + } + } + + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.2f, 0, 0.3f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.1f, 0, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(0.4f, 0, 0).spawn(world); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java index 76797c44..c7721ba5 100644 --- a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java +++ b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java @@ -1,54 +1,80 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.util.IElementalDamage; -import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.data.IStoredVariable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.integration.DamageSafetyChecker; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + @Mod.EventBusSubscriber public class CurseOfSoulbinding extends SpellRay { + public static final IStoredVariable> TARGETS_KEY = new IStoredVariable.StoredVariable<>("soulboundCreatures", + s -> NBTExtras.listToNBT(s, NBTUtil::createUUIDTag), + // For some reason gradle screams at me unless I explicitly declare the type of t here, despite IntelliJ being fine without it + (NBTTagList t) -> new HashSet<>(NBTExtras.NBTToList(t, NBTUtil::getUUIDFromTag)), + // Curse of soulbinding is lifted when the caster dies, but not when they switch dimensions. + Persistence.DIMENSION_CHANGE); + public CurseOfSoulbinding(){ - super("curse_of_soulbinding", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 35, 100, false, 10, SoundEvents.ENTITY_WITHER_SPAWN); + super("curse_of_soulbinding", false, EnumAction.NONE); this.soundValues(1, 1.1f, 0.2f); + WizardData.registerStoredVariables(TARGETS_KEY); } - + @Override public boolean canBeCastByNPCs() { return false; } + // You can't damage a dispenser so this would be nonsense! + @Override public boolean canBeCastByDispensers() { return false; } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ - if(WizardryUtilities.isLiving(target) && caster instanceof EntityPlayer - && WizardData.get((EntityPlayer)caster) != null){ - // Return false if soulbinding failed (e.g. if the target is already soulbound) - if(!WizardData.get((EntityPlayer)caster).soulbind((EntityLivingBase)target)) return false; + if(WizardryUtilities.isLiving(target) && caster instanceof EntityPlayer){ + WizardData data = WizardData.get((EntityPlayer)caster); + if(data != null){ + // Return false if soulbinding failed (e.g. if the target is already soulbound) + if(getSoulboundCreatures(data).add(target.getUniqueID())){ + // This will actually run out in the end, but only if you leave Minecraft running for 3.4 years + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_soulbinding, Integer.MAX_VALUE)); + }else{ + return false; + } + } } return true; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } @@ -65,11 +91,41 @@ public class CurseOfSoulbinding extends SpellRay { if(!event.getEntity().world.isRemote && event.getEntityLiving() instanceof EntityPlayer && !event.getSource().isUnblockable() && !(event.getSource() instanceof IElementalDamage && ((IElementalDamage)event.getSource()).isRetaliatory())){ - WizardData data = WizardData.get((EntityPlayer)event.getEntityLiving()); + + EntityPlayer player = (EntityPlayer)event.getEntityLiving(); + WizardData data = WizardData.get(player); + if(data != null){ - data.damageAllSoulboundCreatures(event.getAmount(), event.getSource().getDamageType()); + + for(Iterator iterator = getSoulboundCreatures(data).iterator(); iterator.hasNext();){ + + Entity entity = WizardryUtilities.getEntityByUUID(player.world, iterator.next()); + + if(entity == null) iterator.remove(); + + if(entity instanceof EntityLivingBase){ + // Retaliatory effect + if(DamageSafetyChecker.attackEntitySafely(entity, MagicDamage.causeDirectMagicDamage(player, + MagicDamage.DamageType.MAGIC, true), event.getAmount(), event.getSource().getDamageType(), + DamageSource.MAGIC, false)){ + // Sound only plays if the damage succeeds + entity.playSound(WizardrySounds.SPELL_CURSE_OF_SOULBINDING_RETALIATE, 1.0F, player.world.rand.nextFloat() * 0.2F + 1.0F); + } + } + } + } } } + public static Set getSoulboundCreatures(WizardData data){ + + if(data.getVariable(TARGETS_KEY) == null){ + Set result = new HashSet<>(); + data.setVariable(TARGETS_KEY, result); + return result; + + }else return data.getVariable(TARGETS_KEY); + } + } diff --git a/src/main/java/electroblob/wizardry/spell/CurseOfUndeath.java b/src/main/java/electroblob/wizardry/spell/CurseOfUndeath.java new file mode 100644 index 00000000..f97e1148 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/CurseOfUndeath.java @@ -0,0 +1,55 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class CurseOfUndeath extends SpellRay { + + public CurseOfUndeath(){ + super("curse_of_undeath", false, EnumAction.NONE); + this.soundValues(1, 1.1f, 0.2f); + addProperties(EFFECT_STRENGTH); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + // This will actually run out in the end, but only if you leave Minecraft running for 3.4 years + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_undeath, Integer.MAX_VALUE, + getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)))); + } + + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0x686c00).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0x251609).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(0xe6e592).spawn(world); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Decay.java b/src/main/java/electroblob/wizardry/spell/Decay.java index 598a09c6..dc6e9f41 100644 --- a/src/main/java/electroblob/wizardry/spell/Decay.java +++ b/src/main/java/electroblob/wizardry/spell/Decay.java @@ -1,43 +1,43 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityDecay; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class Decay extends SpellConstructRanged { - - private static final int BASE_SPAWN_COUNT = 5; + + public static final String DECAY_PATCHES_SPAWNED = "decay_patches_spawned"; public Decay(){ - super("decay", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 50, 200, EntityDecay::new, 400, 12, SoundEvents.ENTITY_WITHER_SHOOT); + super("decay", EntityDecay::new, false); this.soundValues(1, 1.1f, 0.1f); this.floor(true); this.overlap(true); + addProperties(DECAY_PATCHES_SPAWNED, EFFECT_DURATION); } @Override - protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ if(world.getBlockState(new BlockPos(x, y, z)).isNormalCube()) return false; - super.spawnConstruct(world, x, y, z, caster, modifiers); - - int quantity = (int)(BASE_SPAWN_COUNT * modifiers.get(WizardryItems.blast_upgrade)); - int horizontalRange = (int)(2 * modifiers.get(WizardryItems.blast_upgrade)); + super.spawnConstruct(world, x, y, z, side, caster, modifiers); + + float decayCount = getProperty(DECAY_PATCHES_SPAWNED).floatValue(); + int quantity = (int)(decayCount * modifiers.get(WizardryItems.blast_upgrade)); + // If there are more decay patches, they need more space to spawn in + int horizontalRange = (int)(0.4 * decayCount * modifiers.get(WizardryItems.blast_upgrade)); int verticalRange = (int)(6 * modifiers.get(WizardryItems.blast_upgrade)); for(int i=0; i targets = WizardryUtilities.getEntitiesWithinRadius( - BASE_RADIUS * modifiers.get(WizardryItems.blast_upgrade), pos.getX(), pos.getY(), pos.getZ(), world); + List targets = WizardryUtilities.getEntitiesWithinRadius(getProperty(BLAST_RADIUS).doubleValue() + * modifiers.get(WizardryItems.blast_upgrade), pos.getX(), pos.getY(), pos.getZ(), world); for(EntityLivingBase target : targets){ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST), // Damage decreases with distance but cannot be less than 0, naturally. - Math.max(12.0f - (float)target.getDistance(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5) - * 4, 0) * modifiers.get(SpellModifiers.POTENCY)); + Math.max(getProperty(MAX_DAMAGE).floatValue() - (float)target.getDistance(pos.getX() + 0.5, + pos.getY() + 0.5, pos.getZ() + 0.5) * 4, 0) * modifiers.get(SpellModifiers.POTENCY)); } }else{ @@ -56,7 +56,7 @@ public class Detonate extends SpellRay { } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Disintegration.java b/src/main/java/electroblob/wizardry/spell/Disintegration.java new file mode 100644 index 00000000..0dda0a58 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Disintegration.java @@ -0,0 +1,97 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.entity.projectile.EntityEmber; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class Disintegration extends SpellRay { + + public static final String EMBER_COUNT = "ember_count"; + public static final String EMBER_LIFETIME = "ember_lifetime"; + + public Disintegration(){ + super("disintegration", false, EnumAction.NONE); + addProperties(DAMAGE, BURN_DURATION, EMBER_LIFETIME, EMBER_COUNT); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); + }else{ + + target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); + WizardryUtilities.attackEntityWithoutKnockback(target, caster == null ? DamageSource.MAGIC : + MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + + if(!world.isRemote && target instanceof EntityLivingBase && ((EntityLivingBase)target).getHealth() <= 0){ + spawnEmbers(world, caster, target, getProperty(EMBER_COUNT).intValue()); + } + } + + return true; + } + + public static void spawnEmbers(World world, EntityLivingBase caster, Entity target, int count){ + + for(int i = 0; i < count; i++){ + EntityEmber ember = new EntityEmber(world, caster); + double x = (world.rand.nextDouble() - 0.5) * target.width; + double y = world.rand.nextDouble() * target.height; + double z = (world.rand.nextDouble() - 0.5) * target.width; + ember.setPosition(target.posX + x, target.posY + y, target.posZ + z); + float speed = 0.2f; + ember.setVelocity(x * speed, y * 0.5f * speed, z * speed); + world.spawnEntity(ember); + } + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(world.isRemote){ + + for(int i = 0; i < 8; i++){ + world.spawnParticle(EnumParticleTypes.LAVA, hit.x, hit.y, hit.z, 0, 0, 0); + } + + if(world.getBlockState(pos).getMaterial().isSolid()){ + Vec3d vec = hit.add(new Vec3d(side.getDirectionVec()).scale(WizardryUtilities.ANTI_Z_FIGHTING_OFFSET)); + ParticleBuilder.create(Type.SCORCH).pos(vec).face(side).clr(1, 0.2f, 0).spawn(world); + } + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticleRay(World world, Vec3d origin, Vec3d direction, EntityLivingBase caster, double distance){ + Vec3d endpoint = origin.add(direction.scale(distance)); + ParticleBuilder.create(Type.BEAM).clr(1, 0.4f, 0).fade(1, 0.1f, 0).time(4).pos(origin).target(endpoint).spawn(world); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Divination.java b/src/main/java/electroblob/wizardry/spell/Divination.java new file mode 100644 index 00000000..f4ed42b6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Divination.java @@ -0,0 +1,149 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockCrystalOre; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.RelativeFacing; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.Block; +import net.minecraft.block.BlockOre; +import net.minecraft.block.BlockRedstoneOre; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +public class Divination extends Spell { + + private static final float NUDGE_SPEED = 0.2f; + + public Divination(){ + super("divination", EnumAction.NONE, false); + addProperties(RANGE); + } + + /** A set of constants representing the different 'signal strengths' for the divination spell. In practical + * terms, this means different chat readouts and effects. */ + protected enum Strength { + + NOTHING("nothing", -1), + WEAK("weak", 0), + MODERATE("moderate", 0.25f), + STRONG("strong", 0.5f), + VERY_STRONG("very_strong", 0.75f); + + String key; + float minWeight; + + Strength(String key, float minWeight){ + this.key = key; + this.minWeight = minWeight; + } + + protected static Strength forWeight(float weight){ + return Arrays.stream(values()).filter(s -> s.minWeight < weight).max(Comparator.naturalOrder()).orElse(NOTHING); + } + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + double range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + + List sphere = WizardryUtilities.getBlockSphere(caster.getPosition(), range); + + sphere.removeIf(b -> !(world.getBlockState(b).getBlock() instanceof BlockOre + || world.getBlockState(b).getBlock() instanceof BlockRedstoneOre + || world.getBlockState(b).getBlock() instanceof BlockCrystalOre + || Arrays.asList(Wizardry.settings.divinationOreWhitelist) + .contains(world.getBlockState(b).getBlock().getRegistryName()))); + + Strength strength = Strength.NOTHING; + + EnumFacing direction = EnumFacing.DOWN; // Doesn't matter what this is + + if(!sphere.isEmpty()){ + + // Sorts the positions based on weight (see below), in ascending order + sphere.sort(Comparator.comparingDouble(b -> calculateWeight(world, caster, b, range, modifiers))); + + // The weights are sorted in ascending order, so this must be the largest + BlockPos target = sphere.get(sphere.size() - 1); + + direction = EnumFacing.getFacingFromVector((float)(target.getX() + 0.5 - caster.posX), + (float)(target.getY() + 0.5 - (caster.getEntityBoundingBox().minY + caster.getEyeHeight())), + (float)(target.getZ() + 0.5 - caster.posZ)); + + if(world.isRemote) ParticleBuilder.create(ParticleBuilder.Type.SPARKLE).pos(target.getX() + 0.5, + target.getY() + 1.5, target.getZ() + 0.5).spawn(world); + + strength = Strength.forWeight(calculateWeight(world, caster, target, range, modifiers)); + } + + if(!world.isRemote){ + caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + "." + + strength.key, new TextComponentTranslation("spell." + this.getUnlocalisedName() + "." + + RelativeFacing.relativise(direction, caster).name)), false); + }else{ + switch(strength){ + case NOTHING: break; + case WEAK: break; + case MODERATE: + spawnHintParticles(world, caster, 3, direction); + break; + case STRONG: + spawnHintParticles(world, caster, 8, direction); + break; + case VERY_STRONG: + spawnHintParticles(world, caster, 12, direction); + caster.addVelocity(direction.getXOffset() * NUDGE_SPEED, direction.getYOffset() * NUDGE_SPEED, + direction.getZOffset() * NUDGE_SPEED); + break; + } + } + + return true; + } + + private static void spawnHintParticles(World world, Entity caster, int count, EnumFacing direction){ + + Vec3d vec = new Vec3d(caster.getPosition().offset(EnumFacing.UP).offset(direction, 2)).add(0.5, 0.5, 0.5); + + for(int i=0; i { + public class Earthquake extends SpellConstruct { + + public static final String SPREAD_SPEED = "spread_speed"; public Earthquake(){ - super("earthquake", Tier.MASTER, Element.EARTH, SpellType.ATTACK, 75, 250, EnumAction.NONE, EntityEarthquake::new, -1, WizardrySounds.SPELL_EARTHQUAKE); + super("earthquake", EnumAction.NONE, EntityEarthquake::new, true); this.soundValues(2, 1, 0); this.overlap(true); this.floor(true); + addProperties(EFFECT_RADIUS, SPREAD_SPEED); } // This one spawns particles - @Override public boolean doesSpellRequirePacket(){ return true; } + @Override public boolean requiresPacket(){ return true; } @Override - protected void addConstructExtras(EntityEarthquake construct, EntityLivingBase caster, SpellModifiers modifiers){ - construct.lifetime = (int)(20 * modifiers.get(WizardryItems.blast_upgrade)); + protected void addConstructExtras(EntityEarthquake construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ + // Calculates the lifetime based on the base radius and spread speed + // Also overwrites the -1 lifetime set due to permanent being true + construct.lifetime = (int)(getProperty(EFFECT_RADIUS).floatValue()/getProperty(SPREAD_SPEED).floatValue() + * modifiers.get(WizardryItems.blast_upgrade)); } @Override - protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ - // TODO: Couldn't this be moved to EntityEarthquake? if(world.isRemote){ world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX, @@ -49,15 +51,13 @@ public class Earthquake extends SpellConstruct { particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); - if(block != null){ - world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY, - particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, - Block.getStateId(block)); - } + world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY, + particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, + Block.getStateId(block)); } } - return super.spawnConstruct(world, x, y, z, caster, modifiers); + return super.spawnConstruct(world, x, y, z, side, caster, modifiers); } } diff --git a/src/main/java/electroblob/wizardry/spell/EmpoweringPresence.java b/src/main/java/electroblob/wizardry/spell/EmpoweringPresence.java new file mode 100644 index 00000000..ad42d9c3 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/EmpoweringPresence.java @@ -0,0 +1,81 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.event.SpellCastEvent; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.AllyDesignationSystem; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.List; + +@Mod.EventBusSubscriber +public class EmpoweringPresence extends Spell { + + public EmpoweringPresence(){ + super("empowering_presence", EnumAction.BOW, false); + addProperties(EFFECT_RADIUS, EFFECT_DURATION, EFFECT_STRENGTH); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + List targets = WizardryUtilities.getEntitiesWithinRadius(getProperty(EFFECT_RADIUS).doubleValue() + * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class); + + for(EntityPlayer target : targets){ + if(AllyDesignationSystem.isPlayerAlly(caster, target) || target == caster){ + + int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)); + + target.addPotionEffect(new PotionEffect(WizardryPotions.empowerment, + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier)); + } + } + + if(world.isRemote){ + + for(int i = 0; i < 50 * modifiers.get(WizardryItems.blast_upgrade); i++){ + + double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); + float angle = world.rand.nextFloat() * (float)Math.PI * 2; + + double x = caster.posX + radius * MathHelper.cos(angle); + double y = caster.getEntityBoundingBox().minY; + double z = caster.posZ + radius * MathHelper.sin(angle); + + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50).clr(0.5f, 0.4f, 0.75f).spawn(world); + + } + } + + //WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1 + 0.2f * world.rand.nextFloat()); + return true; + } + + @SubscribeEvent(priority = EventPriority.LOW) // Doesn't really matter but there's no point processing it if casting is blocked + public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ + // Empowerment stacks extra potency on top of the existing potency. + if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.empowerment)){ + + float potency = 1 + Constants.EMPOWERMENT_POTENCY_PER_LEVEL + * (event.getCaster().getActivePotionEffect(WizardryPotions.empowerment).getAmplifier() + 1); + + event.getModifiers().set(SpellModifiers.POTENCY, + event.getModifiers().get(SpellModifiers.POTENCY) * potency, true); + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/spell/Entrapment.java b/src/main/java/electroblob/wizardry/spell/Entrapment.java index 931a230e..7f20fbd8 100644 --- a/src/main/java/electroblob/wizardry/spell/Entrapment.java +++ b/src/main/java/electroblob/wizardry/spell/Entrapment.java @@ -1,8 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityBubble; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; @@ -13,21 +10,25 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Entrapment extends SpellRay { + public static final String DAMAGE_INTERVAL = "damage_interval"; + public Entrapment(){ - super("entrapment", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 35, 75, false, 10, SoundEvents.ENTITY_WITHER_SHOOT); + super("entrapment", false, EnumAction.NONE); this.soundValues(1, 0.85f, 0.3f); + addProperties(EFFECT_DURATION, DAMAGE_INTERVAL); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ @@ -38,7 +39,7 @@ public class Entrapment extends SpellRay { EntityBubble bubble = new EntityBubble(world); bubble.setPosition(target.posX, target.posY, target.posZ); bubble.setCaster(caster); - bubble.lifetime = ((int)(200 * modifiers.get(WizardryItems.duration_upgrade))); + bubble.lifetime = ((int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); bubble.isDarkOrb = true; bubble.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); @@ -51,12 +52,12 @@ public class Entrapment extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Evade.java b/src/main/java/electroblob/wizardry/spell/Evade.java new file mode 100644 index 00000000..9df46093 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Evade.java @@ -0,0 +1,48 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class Evade extends Spell { + + private static final String EVADE_VELOCITY = "evade_velocity"; + + private static final float UPWARD_VELOCITY = 0.25f; + + public Evade(){ + super("evade", EnumAction.NONE, false); + addProperties(EVADE_VELOCITY); + } + + @Override + public boolean requiresPacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + Vec3d look = caster.getLookVec(); + // We want a horizontal only vector + look = look.subtract(0, look.y, 0).normalize(); + + Vec3d evadeDirection; + if(caster.moveStrafing == 0){ + // If the caster isn't strafing, pick a random direction + evadeDirection = look.rotateYaw(world.rand.nextBoolean() ? (float)Math.PI/2f : (float)-Math.PI/2f); + }else{ + // Otherwise, evade always moves whichever direction the caster was already strafing + evadeDirection = look.rotateYaw(Math.signum(caster.moveStrafing) * (float)Math.PI/2f); + } + + evadeDirection = evadeDirection.scale(getProperty(EVADE_VELOCITY).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + caster.addVelocity(evadeDirection.x, UPWARD_VELOCITY, evadeDirection.z); + + return true; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/FireBreath.java b/src/main/java/electroblob/wizardry/spell/FireBreath.java new file mode 100644 index 00000000..338f375d --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/FireBreath.java @@ -0,0 +1,95 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class FireBreath extends SpellRay { + + public FireBreath(){ + super("fire_breath", true, EnumAction.NONE); + this.particleVelocity(1); + this.particleJitter(0.3); + this.particleSpacing(0.25); + addProperties(DAMAGE, BURN_DURATION); + } + + @Override + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + // Fire can damage armour stands + if(target instanceof EntityLivingBase){ + + if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ + if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster) + .sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); + // This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle + // with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry. + }else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){ + target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); + WizardryUtilities.attackEntityWithoutKnockback(target, + MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + } + } + + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(!WizardryUtilities.canDamageBlocks(caster, world)) return false; + + pos = pos.offset(side); + + if(world.isAirBlock(pos)){ + if(!world.isRemote) world.setBlockState(pos, Blocks.FIRE.getDefaultState()); + return true; + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).scale(2 + world.rand.nextFloat()).collide(true).spawn(world); + ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).scale(2 + world.rand.nextFloat()).collide(true).spawn(world); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Firestorm.java b/src/main/java/electroblob/wizardry/spell/Firestorm.java deleted file mode 100644 index fc15aa2e..00000000 --- a/src/main/java/electroblob/wizardry/spell/Firestorm.java +++ /dev/null @@ -1,110 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.MagicDamage; -import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Blocks; -import net.minecraft.init.SoundEvents; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.world.World; - -public class Firestorm extends SpellRay { - - private static final float BASE_DAMAGE = 6; - /** The base duration for which entities are set on fire by this spell. */ - private static final int BASE_DURATION = 10; - - public Firestorm(){ - super("firestorm", Tier.MASTER, Element.FIRE, SpellType.ATTACK, 15, 0, true, 10, null); - this.particleVelocity(1); - this.particleDither(0.3); - this.particleSpacing(0.25); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // Temporary solution until I implement a better continuous sound system - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag){ - if(ticksInUse % 16 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_FIRE, 0.5f, 1.0f); - } - } - return flag; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag){ - if(ticksInUse % 16 == 0){ - if(ticksInUse == 0) caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - caster.playSound(WizardrySounds.SPELL_LOOP_FIRE, 0.5f, 1.0f); - } - } - return flag; - } - - @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - // Fire can damage armour stands - if(target instanceof EntityLivingBase){ - - if(MagicDamage.isEntityImmune(DamageType.FIRE, target)){ - if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster) - .sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted()), true); - }else{ - target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); - WizardryUtilities.attackEntityWithoutKnockback(target, - MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); - } - - return true; - } - - return false; - } - - @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - - pos = pos.offset(side); - - if(world.isAirBlock(pos)){ - if(!world.isRemote) world.setBlockState(pos, Blocks.FIRE.getDefaultState()); - return true; - } - - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return true; - } - - @Override - protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ - ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).scale(3 + world.rand.nextFloat()).spawn(world); - ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).scale(3 + world.rand.nextFloat()).spawn(world); - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/FlameRay.java b/src/main/java/electroblob/wizardry/spell/FlameRay.java index 893d9284..b13e2e45 100644 --- a/src/main/java/electroblob/wizardry/spell/FlameRay.java +++ b/src/main/java/electroblob/wizardry/spell/FlameRay.java @@ -1,10 +1,6 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -12,55 +8,45 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class FlameRay extends SpellRay { - - private static final float BASE_DAMAGE = 3; - /** The base duration for which entities are set on fire by this spell. */ - private static final int BASE_DURATION = 10; public FlameRay(){ - super("flame_ray", Tier.APPRENTICE, Element.FIRE, SpellType.ATTACK, 5, 0, true, 10, null); + super("flame_ray", true, EnumAction.NONE); this.particleVelocity(1); this.particleSpacing(0.5); + addProperties(DAMAGE, BURN_DURATION); + this.soundValues(1.5f, 1, 0); + } + + // The following three methods serve as a good example of how to implement continuous spell sounds (hint: it's easy) + + @Override + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // TODO: Temporary solution until I implement a better continuous sound system - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag){ - if(ticksInUse % 16 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_FIRE, 0.5f, 1.0f); - } - } - return flag; + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag){ - if(ticksInUse % 16 == 0){ - if(ticksInUse == 0) caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - caster.playSound(WizardrySounds.SPELL_LOOP_FIRE, 0.5f, 1.0f); - } - } - return flag; + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ // Fire can damage armour stands if(target instanceof EntityLivingBase){ @@ -68,33 +54,33 @@ public class FlameRay extends SpellRay { if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster) .sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); - }else{ - target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); + // This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle + // with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry. + }else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){ + target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); } - - return true; } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ - ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).spawn(world); - ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).spawn(world); + ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).collide(true).spawn(world); + ParticleBuilder.create(Type.MAGIC_FIRE).pos(x, y, z).vel(vx, vy, vz).collide(true).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/FlamingAxe.java b/src/main/java/electroblob/wizardry/spell/FlamingAxe.java index 33498792..1f87a883 100644 --- a/src/main/java/electroblob/wizardry/spell/FlamingAxe.java +++ b/src/main/java/electroblob/wizardry/spell/FlamingAxe.java @@ -1,19 +1,16 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; public class FlamingAxe extends SpellConjuration { public FlamingAxe(){ - super("flaming_axe", Tier.ADVANCED, Element.FIRE, SpellType.UTILITY, 45, 50, WizardryItems.flaming_axe, SoundEvents.ENTITY_BLAZE_SHOOT); + super("flaming_axe", WizardryItems.flaming_axe); + addProperties(DAMAGE, BURN_DURATION); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java index 1c940d4e..bb1c3611 100644 --- a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java @@ -1,13 +1,9 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -15,16 +11,15 @@ import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemSword; import net.minecraft.util.EnumHand; import net.minecraft.world.World; public class FlamingWeapon extends Spell { public FlamingWeapon(){ - super("flaming_weapon", Tier.ADVANCED, Element.FIRE, SpellType.UTILITY, 35, 70, EnumAction.BOW, false); + super("flaming_weapon", EnumAction.BOW, false); + addProperties(EFFECT_DURATION); } @Override @@ -36,17 +31,17 @@ public class FlamingWeapon extends Spell { for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(caster)){ - if((stack.getItem() instanceof ItemSword || stack.getItem() instanceof ItemBow) + if((ImbueWeapon.isSword(stack.getItem()) || ImbueWeapon.isBow(stack.getItem())) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.flaming_weapon)){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. stack.addEnchantment(WizardryEnchantments.flaming_weapon, modifiers.get(SpellModifiers.POTENCY) == 1.0f ? 1 : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) - / Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); + / Constants.POTENCY_INCREASE_PER_TIER + 0.5f)); WizardData.get(caster).setImbuementDuration(WizardryEnchantments.flaming_weapon, - (int)(900 * modifiers.get(WizardryItems.duration_upgrade))); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); if(world.isRemote){ for(int i=0; i<10; i++){ @@ -57,7 +52,7 @@ public class FlamingWeapon extends Spell { } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Flight.java b/src/main/java/electroblob/wizardry/spell/Flight.java index eb36ceff..9e2d0d8a 100644 --- a/src/main/java/electroblob/wizardry/spell/Flight.java +++ b/src/main/java/electroblob/wizardry/spell/Flight.java @@ -1,40 +1,47 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.world.World; public class Flight extends Spell { + public static final String SPEED = "speed"; + public static final String ACCELERATION = "acceleration"; + + private static final double Y_NUDGE_ACCELERATION = 0.075; + public Flight(){ - super("flight", Tier.MASTER, Element.EARTH, SpellType.UTILITY, 10, 0, EnumAction.NONE, true); + super("flight", EnumAction.NONE, true); + addProperties(SPEED, ACCELERATION); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - if(!caster.isInWater() && !caster.isElytraFlying()){ + if(!caster.isInWater() && !caster.isInLava() && !caster.isElytraFlying()){ + + float speed = getProperty(SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY); + float acceleration = getProperty(ACCELERATION).floatValue() * modifiers.get(SpellModifiers.POTENCY); + // The division thingy checks if the look direction is the opposite way to the velocity. If this is the // case then the velocity should be added regardless of the player's current speed. - if((Math.abs(caster.motionX) < 0.6 || caster.motionX / caster.getLookVec().x < 0) - && (Math.abs(caster.motionZ) < 0.6 || caster.motionZ / caster.getLookVec().z < 0)){ - caster.addVelocity(caster.getLookVec().x / 20, 0, caster.getLookVec().z / 20); + if((Math.abs(caster.motionX) < speed || caster.motionX / caster.getLookVec().x < 0) + && (Math.abs(caster.motionZ) < speed || caster.motionZ / caster.getLookVec().z < 0)){ + caster.addVelocity(caster.getLookVec().x * acceleration, 0, caster.getLookVec().z * acceleration); } // y velocity is handled separately to stop the player from falling from the sky when they reach maximum // horizontal speed. - if(Math.abs(caster.motionY) < 0.6 || caster.motionY / caster.getLookVec().y < 0){ - caster.motionY += caster.getLookVec().y / 20 + 0.075; + if(Math.abs(caster.motionY) < speed || caster.motionY / caster.getLookVec().y < 0){ + caster.motionY += caster.getLookVec().y * acceleration + Y_NUDGE_ACCELERATION; } - caster.fallDistance = 0.0f; + + if(!Wizardry.settings.replaceVanillaFallDamage) caster.fallDistance = 0.0f; } if(world.isRemote){ @@ -45,12 +52,10 @@ public class Flight extends Spell { x = caster.posX - 1 + world.rand.nextDouble() * 2; y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); z = caster.posZ - 1 + world.rand.nextDouble() * 2; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(1, 1, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(1f, 1f, 1f).spawn(world); } - if(ticksInUse % 24 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERDRAGON_FLAP, 0.5F, 1.0f); - } + if(ticksInUse % 24 == 0) playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/FontOfMana.java b/src/main/java/electroblob/wizardry/spell/FontOfMana.java index 6963c42f..4dc20f74 100644 --- a/src/main/java/electroblob/wizardry/spell/FontOfMana.java +++ b/src/main/java/electroblob/wizardry/spell/FontOfMana.java @@ -1,13 +1,9 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -16,50 +12,67 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumHand; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.List; public class FontOfMana extends Spell { public FontOfMana(){ - super("font_of_mana", Tier.MASTER, Element.HEALING, SpellType.UTILITY, 100, 250, EnumAction.BOW, false); + super("font_of_mana", EnumAction.BOW, false); + this.soundValues(0.7f, 1.2f, 0.4f); + addProperties(EFFECT_RADIUS, EFFECT_DURATION, EFFECT_STRENGTH); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + double maxRadius = getProperty(EFFECT_RADIUS).doubleValue(); + List targets = WizardryUtilities.getEntitiesWithinRadius( - 5 * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world, - EntityPlayer.class); + maxRadius * modifiers.get(WizardryItems.blast_upgrade), + caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class); for(EntityPlayer target : targets){ - if(WizardryUtilities.isPlayerAlly(caster, target) || target == caster){ - // Damage multiplier can only ever be 1 or 1.6 for master spells, so there's little point in actually - // calculating this. + if(AllyDesignationSystem.isPlayerAlly(caster, target) || target == caster){ target.addPotionEffect(new PotionEffect(WizardryPotions.font_of_mana, - (int)(600 * modifiers.get(WizardryItems.duration_upgrade)), - modifiers.get(SpellModifiers.POTENCY) > 1 ? 1 : 0)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + (int)(getProperty(EFFECT_STRENGTH).intValue() + (modifiers.get(SpellModifiers.POTENCY) - 1) * 2))); } } if(world.isRemote){ for(int i = 0; i < 100 * modifiers.get(WizardryItems.blast_upgrade); i++){ - - double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); - double angle = world.rand.nextDouble() * Math.PI * 2; + + double radius = (1 + world.rand.nextDouble() * (maxRadius - 1)) * modifiers.get(WizardryItems.blast_upgrade); + float angle = world.rand.nextFloat() * (float)Math.PI * 2; + ; float hue = world.rand.nextFloat() * 0.4f; - - double x = caster.posX + radius * Math.cos(angle); + + double x = caster.posX + radius * MathHelper.cos(angle); double y = caster.getEntityBoundingBox().minY; - double z = caster.posZ + radius * Math.sin(angle); - + double z = caster.posZ + radius * MathHelper.sin(angle); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50) - .clr(1, 1 - hue, 0.6f + hue).spawn(world); + .clr(1, 1 - hue, 0.6f + hue).spawn(world); } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); + playSound(world, caster, ticksInUse, -1, modifiers); + return true; } -} + @SubscribeEvent(priority = EventPriority.LOW) // Doesn't really matter but there's no point processing it if casting is blocked + public static void onSpellCastPreEvent(SpellCastEvent.Pre event){ + // Moved from ItemWand (quite why this wasn't done with modifiers before I don't know!) + if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.font_of_mana)){ + // Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously + event.getModifiers().set(WizardryItems.cooldown_upgrade, event.getModifiers().get(WizardryItems.cooldown_upgrade) + / (2 + event.getCaster().getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier()), false); + } + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/spell/ForceArrow.java b/src/main/java/electroblob/wizardry/spell/ForceArrow.java new file mode 100644 index 00000000..4996b3d0 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ForceArrow.java @@ -0,0 +1,21 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.entity.projectile.EntityForceArrow; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; + +import javax.annotation.Nullable; + +public class ForceArrow extends SpellArrow { + + public ForceArrow(){ + super("force_arrow", EntityForceArrow::new); + this.addProperties(Spell.DAMAGE); + this.soundValues(1, 1.3f, 0.2f); + } + + @Override + protected void addArrowExtras(EntityForceArrow arrow, @Nullable EntityLivingBase caster, SpellModifiers modifiers){ + arrow.setMana((int)(this.getCost() * modifiers.get(SpellModifiers.COST))); + } +} diff --git a/src/main/java/electroblob/wizardry/spell/Forcefield.java b/src/main/java/electroblob/wizardry/spell/Forcefield.java new file mode 100644 index 00000000..bfc298b2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Forcefield.java @@ -0,0 +1,21 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.entity.construct.EntityForcefield; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; + +public class Forcefield extends SpellConstruct { + + public Forcefield(){ + super("forcefield", EnumAction.BOW, EntityForcefield::new, false); + addProperties(Spell.EFFECT_RADIUS); + } + + @Override + protected void addConstructExtras(EntityForcefield construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ + construct.setRadius(getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade)); + } +} diff --git a/src/main/java/electroblob/wizardry/spell/ForestOfThorns.java b/src/main/java/electroblob/wizardry/spell/ForestOfThorns.java new file mode 100644 index 00000000..93860407 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ForestOfThorns.java @@ -0,0 +1,99 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.block.BlockThorns; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.tileentity.TileEntityPlayerSaveTimed; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +public class ForestOfThorns extends Spell { + + public ForestOfThorns(){ + super("forest_of_thorns", EnumAction.BOW, false); + addProperties(EFFECT_RADIUS, DURATION, DAMAGE); + } + + @Override public boolean requiresPacket(){ return false; } + @Override public boolean canBeCastByNPCs(){ return true; } + @Override public boolean canBeCastByDispensers(){ return true; } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + if(!summonThorns(world, caster, caster.getPosition(), modifiers)) return false; + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + if(!summonThorns(world, caster, caster.getPosition(), modifiers)) return false; + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; + } + + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + if(!summonThorns(world, null, new BlockPos(x, y, z).offset(direction), modifiers)) return false; + this.playSound(world, x, y, z, ticksInUse, duration, modifiers); + return true; + } + + private boolean summonThorns(World world, @Nullable EntityLivingBase caster, BlockPos origin, SpellModifiers modifiers){ + + if(!world.isRemote){ + + double radius = getProperty(EFFECT_RADIUS).doubleValue() * modifiers.get(WizardryItems.blast_upgrade); + + List ring = new ArrayList<>((int)(7 * radius)); // 7 is a bit more than 2 pi + + for(int x = -(int)radius; x <= radius; x++){ + + for(int z = -(int)radius; z <= radius; z++){ + + double distance = MathHelper.sqrt(x*x + z*z); + + if(distance > radius || distance < radius - 1.5) continue; + + Integer y = WizardryUtilities.getNearestSurface(world, origin.add(x, 0, z), EnumFacing.UP, (int)radius, true, WizardryUtilities.SurfaceCriteria.BUILDABLE); + if(y != null) ring.add(new BlockPos(origin.getX() + x, y, origin.getZ() + z)); + } + } + + if(ring.isEmpty()) return false; + + // Because we're always using EnumFacing.UP in the code above, we can be sure that pos is the block above the floor + for(BlockPos pos : ring){ + + ((BlockThorns)WizardryBlocks.thorns).placeAt(world, pos, 3); + + for(int i=0; i<2; i++){ + + TileEntity tileentity = world.getTileEntity(pos.up(i)); + + if(tileentity instanceof TileEntityPlayerSaveTimed){ + ((TileEntityPlayerSaveTimed)tileentity).setLifetime((int)(getProperty(DURATION).floatValue() + * modifiers.get(WizardryItems.duration_upgrade))); + if(caster != null) ((TileEntityPlayerSaveTimed)tileentity).setCaster(caster); + } + } + } + } + + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java index 0cd51ef4..edb3f8d4 100644 --- a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java +++ b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java @@ -1,8 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; @@ -12,19 +9,16 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.world.World; public class ForestsCurse extends SpellAreaEffect { - - private static final int BASE_DAMAGE = 4; - private static final int BASE_DURATION = 140; public ForestsCurse(){ - super("forests_curse", Tier.MASTER, Element.EARTH, SpellType.ATTACK, 75, 200, EnumAction.BOW, 5, SoundEvents.ENTITY_WITHER_SPAWN); + super("forests_curse", EnumAction.BOW); this.soundValues(1, 1.1f, 0.2f); + addProperties(DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH); } @Override @@ -33,13 +27,15 @@ public class ForestsCurse extends SpellAreaEffect { if(!MagicDamage.isEntityImmune(DamageType.POISON, target) && WizardryUtilities.isLiving(target)){ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); - - int duration = (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)); - - target.addPotionEffect(new PotionEffect(MobEffects.POISON, duration, 2)); - target.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, duration, 2)); - target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, duration, 2)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + + int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)); + int duration = (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)); + int amplifier = (int)(getProperty(EFFECT_STRENGTH).floatValue() + bonusAmplifier); + + target.addPotionEffect(new PotionEffect(MobEffects.POISON, duration, amplifier)); + target.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, duration, amplifier)); + target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, duration, amplifier)); } } diff --git a/src/main/java/electroblob/wizardry/spell/Freeze.java b/src/main/java/electroblob/wizardry/spell/Freeze.java index ab335bc6..d0d59939 100644 --- a/src/main/java/electroblob/wizardry/spell/Freeze.java +++ b/src/main/java/electroblob/wizardry/spell/Freeze.java @@ -1,12 +1,7 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntityBlazeMinion; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -17,33 +12,33 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntityBlaze; import net.minecraft.entity.monster.EntityMagmaCube; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; +import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class Freeze extends SpellRay { - - /** The base duration of the frostbite effect appled by this spell. */ - private static final int BASE_DURATION = 200; - /** The base damage dealt to entities vulnerable to frost. */ - private static final float BASE_DAMAGE = 3; public Freeze(){ - super("freeze", Tier.BASIC, Element.ICE, SpellType.ATTACK, 5, 10, false, 10, WizardrySounds.SPELL_ICE); + super("freeze", false, EnumAction.NONE); this.soundValues(1, 1.4f, 0.4f); + addProperties(DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH); + this.hitLiquids(true); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ - if(target instanceof EntityBlaze || target instanceof EntityMagmaCube || target instanceof EntityBlazeMinion){ + if(target instanceof EntityBlaze || target instanceof EntityMagmaCube){ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); } if(MagicDamage.isEntityImmune(DamageType.FROST, target)){ @@ -51,11 +46,12 @@ public class Freeze extends SpellRay { new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue())); } if(target.isBurning()) target.extinguish(); - + return true; } @@ -63,24 +59,27 @@ public class Freeze extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - - if(world.getBlockState(pos).getBlock() == Blocks.WATER && !world.isRemote){ - world.setBlockState(pos, Blocks.ICE.getDefaultState()); - }else if(world.getBlockState(pos).getBlock() == Blocks.LAVA && !world.isRemote){ - world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState()); - }else if(world.getBlockState(pos).getBlock() == Blocks.FLOWING_LAVA && !world.isRemote){ - world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); - }else if(side == EnumFacing.UP && !world.isRemote && world.isSideSolid(pos, EnumFacing.UP) - && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ - world.setBlockState(pos.up(), Blocks.SNOW_LAYER.getDefaultState()); + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.canDamageBlocks(caster, world)){ + + if(world.getBlockState(pos).getBlock() == Blocks.WATER && !world.isRemote){ + world.setBlockState(pos, Blocks.ICE.getDefaultState()); + }else if(world.getBlockState(pos).getBlock() == Blocks.LAVA && !world.isRemote){ + world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState()); + }else if(world.getBlockState(pos).getBlock() == Blocks.FLOWING_LAVA && !world.isRemote){ + world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); + }else if(side == EnumFacing.UP && !world.isRemote && world.isSideSolid(pos, EnumFacing.UP) + && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ + world.setBlockState(pos.up(), Blocks.SNOW_LAYER.getDefaultState()); + } } return true; // Always succeeds if it hits a block } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java index 19b8a8bc..1c798319 100644 --- a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java @@ -1,13 +1,9 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -15,9 +11,7 @@ import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemSword; import net.minecraft.util.EnumHand; import net.minecraft.world.World; @@ -30,7 +24,8 @@ public class FreezingWeapon extends Spell { public static final String FREEZING_ARROW_NBT_KEY = "frostLevel"; public FreezingWeapon(){ - super("freezing_weapon", Tier.ADVANCED, Element.ICE, SpellType.UTILITY, 35, 70, EnumAction.BOW, false); + super("freezing_weapon", EnumAction.BOW, false); + addProperties(EFFECT_DURATION); } @Override @@ -42,17 +37,17 @@ public class FreezingWeapon extends Spell { for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(caster)){ - if((stack.getItem() instanceof ItemSword || stack.getItem() instanceof ItemBow) + if((ImbueWeapon.isSword(stack.getItem()) || ImbueWeapon.isBow(stack.getItem())) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.freezing_weapon)){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. stack.addEnchantment(WizardryEnchantments.freezing_weapon, modifiers.get(SpellModifiers.POTENCY) == 1.0f ? 1 : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) - / Constants.DAMAGE_INCREASE_PER_TIER + 0.5f)); + / Constants.POTENCY_INCREASE_PER_TIER + 0.5f)); WizardData.get(caster).setImbuementDuration(WizardryEnchantments.freezing_weapon, - (int)(900 * modifiers.get(WizardryItems.duration_upgrade))); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); if(world.isRemote){ for(int i=0; i<10; i++){ @@ -63,7 +58,7 @@ public class FreezingWeapon extends Spell { } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/FrostAxe.java b/src/main/java/electroblob/wizardry/spell/FrostAxe.java index e9b15a57..31c104db 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostAxe.java +++ b/src/main/java/electroblob/wizardry/spell/FrostAxe.java @@ -1,10 +1,6 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -14,7 +10,7 @@ import net.minecraft.world.World; public class FrostAxe extends SpellConjuration { public FrostAxe(){ - super("frost_axe", Tier.ADVANCED, Element.ICE, SpellType.UTILITY, 45, 50, WizardryItems.frost_axe, WizardrySounds.SPELL_ICE); + super("frost_axe", WizardryItems.frost_axe); } @Override diff --git a/src/main/java/electroblob/wizardry/spell/FrostRay.java b/src/main/java/electroblob/wizardry/spell/FrostRay.java index 6aa97807..7f4dbcaa 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostRay.java +++ b/src/main/java/electroblob/wizardry/spell/FrostRay.java @@ -1,11 +1,7 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -13,57 +9,45 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntityBlaze; import net.minecraft.entity.monster.EntityMagmaCube; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class FrostRay extends SpellRay { - private static final float BASE_DAMAGE = 3; - /** The base duration of the forstbite effect applied by this spell. */ - private static final int BASE_DURATION = 200; - public FrostRay(){ - super("frost_ray", Tier.APPRENTICE, Element.ICE, SpellType.ATTACK, 5, 0, true, 10, null); + super("frost_ray", true, EnumAction.NONE); this.particleVelocity(1); this.particleSpacing(0.5); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // TODO: Temporary solution until I implement a better continuous sound system - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag){ - if(ticksInUse % 12 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5f, 1); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_ICE, 0.5f, 1); - } - } - return flag; + addProperties(DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH); } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag){ - if(ticksInUse % 12 == 0){ - if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_ICE, 0.5f, 1); - caster.playSound(WizardrySounds.SPELL_LOOP_ICE, 0.5f, 1); - } - } - return flag; + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ @@ -73,32 +57,33 @@ public class FrostRay extends SpellRay { if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster) .sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); - }else{ + // This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle + // with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry. + }else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){ // For frost ray the entity can move slightly, unlike freeze ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue())); - float damage = BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY); + float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY); if(target instanceof EntityBlaze || target instanceof EntityMagmaCube) damage *= 2; WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.FROST), damage); } - - return true; } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } @@ -106,8 +91,8 @@ public class FrostRay extends SpellRay { protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ float brightness = world.rand.nextFloat(); ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12)) - .clr(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).spawn(world); - ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12)).spawn(world); + .clr(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).collide(true).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12)).collide(true).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Glide.java b/src/main/java/electroblob/wizardry/spell/Glide.java index 7821c800..c1c465ad 100644 --- a/src/main/java/electroblob/wizardry/spell/Glide.java +++ b/src/main/java/electroblob/wizardry/spell/Glide.java @@ -1,41 +1,66 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.world.World; public class Glide extends Spell { + public static final String SPEED = "speed"; + public static final String FALL_SPEED = "fall_speed"; + public static final String ACCELERATION = "acceleration"; + public Glide(){ - super("glide", Tier.ADVANCED, Element.EARTH, SpellType.UTILITY, 5, 0, EnumAction.NONE, true); + super("glide", EnumAction.NONE, true); + addProperties(SPEED, FALL_SPEED, ACCELERATION); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + if(ticksInUse == 0 && world.isRemote) Wizardry.proxy.playSpellSoundLoop(entity, this, this.sounds[0], this.sounds[0], this.sounds[0], + WizardrySounds.SPELLS, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + if(ticksInUse == 0 && world.isRemote){ + Wizardry.proxy.playSpellSoundLoop(world, x, y, z, this, this.sounds[0], this.sounds[0], this.sounds[0], + WizardrySounds.SPELLS, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f), duration); + } } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(caster.motionY < -0.1 && !caster.isInWater()){ - caster.motionY = -0.1; - if(Math.abs(caster.motionX) < 0.4 && Math.abs(caster.motionZ) < 0.4){ - caster.addVelocity(caster.getLookVec().x / 8, 0, caster.getLookVec().z / 8); - // entityplayer.moveEntity(entityplayer.motionX*10, 0, entityplayer.motionZ*10); + + float speed = getProperty(SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY); + // There seems to be some sort of 'terminal velocity', presumably due to the slight slowing-down effect in + // vanilla - this means we have to apply potency modifiers to the acceleration as well as the speed or they + // appear to have no effect (a bug which had me confused for quite a while!) This also applies to flight. + float acceleration = getProperty(ACCELERATION).floatValue() * modifiers.get(SpellModifiers.POTENCY); + + caster.motionY = -getProperty(FALL_SPEED).floatValue(); + if(Math.abs(caster.motionX) < speed && Math.abs(caster.motionZ) < speed){ + caster.addVelocity(caster.getLookVec().x * acceleration, 0, caster.getLookVec().z * acceleration); } - caster.fallDistance = 0.0f; + + if(!Wizardry.settings.replaceVanillaFallDamage) caster.fallDistance = 0.0f; } if(world.isRemote){ double x = caster.posX - 0.25 + world.rand.nextDouble() / 2; double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble(); double z = caster.posZ - 0.25 + world.rand.nextDouble() / 2; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(1, 1, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(1f, 1f, 1f).spawn(world); x = caster.posX - 0.25 + world.rand.nextDouble() / 2; y = caster.getEntityBoundingBox().minY + world.rand.nextDouble(); z = caster.posZ - 0.25 + world.rand.nextDouble() / 2; @@ -43,7 +68,7 @@ public class Glide extends Spell { } if(ticksInUse % 24 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ITEM_ELYTRA_FLYING, 0.5F, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); } return true; diff --git a/src/main/java/electroblob/wizardry/spell/Grapple.java b/src/main/java/electroblob/wizardry/spell/Grapple.java new file mode 100644 index 00000000..6ee73cab --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Grapple.java @@ -0,0 +1,419 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.IVariable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.RayTracer; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.EnumAction; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +public class Grapple extends Spell { + + /** The speed at which the vine extends/retracts from the caster, in blocks per tick. */ + public static final String EXTENSION_SPEED = "extension_speed"; + /** The speed at which the vine reels in the caster or target, in blocks per tick. */ + public static final String REEL_SPEED = "reel_speed"; + + public static final IVariable TARGET_KEY = new IVariable.Variable(Persistence.NEVER) + .withTicker(Grapple::update); + + /** The distance from the target position at which the spell will stop reeling in entities. */ + private static final double MINIMUM_REEL_DISTANCE = 3; + /** The acceleration with which the vine reels in the caster or target. */ + private static final double REEL_ACCELERATION = 0.3; + /** The speed at which the caster or target is lowered when the caster is sneaking. */ + private static final double PAYOUT_SPEED = 0.25; + /** Once attached, the vine can stretch beyond the maximum range by this factor before breaking. */ + private static final double STRETCH_LIMIT = 1.5; + /** The distance between spawned particles. */ + protected static final double PARTICLE_SPACING = 1.5; + /** The maximum jitter (random position offset) for spawned particles. */ + protected static final double PARTICLE_JITTER = 0.04; + + public Grapple(){ + super("grapple", EnumAction.NONE, true); + addProperties(RANGE, EXTENSION_SPEED, REEL_SPEED); + } + + @Override + public boolean canBeCastByNPCs(){ + return super.canBeCastByNPCs(); + } + + @Override + public boolean canBeCastByDispensers(){ + return true; + } + + @Override + protected SoundEvent[] createSounds(){ + return this.createSoundsWithSuffixes("shoot", "attach", "pull", "release"); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + WizardData data = WizardData.get(caster); + + Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight(), caster.posZ); + + float extensionSpeed = getProperty(EXTENSION_SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY); + + RayTraceResult hit = data.getVariable(TARGET_KEY); + + // Initial targeting + if(hit == null){ + hit = findTarget(world, caster, origin, caster.getLookVec(), modifiers); + data.setVariable(TARGET_KEY, hit); + caster.swingArm(hand); + // This condition prevents the sound playing every tick after a missed shot has finished extending + if(hit.typeOfHit != RayTraceResult.Type.MISS + || ticksInUse * extensionSpeed < getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade)){ + this.playSound(world, caster, ticksInUse, -1, modifiers, "shoot"); + } + } + + Vec3d target = hit.hitVec; + + if(hit.entityHit instanceof EntityLivingBase){ + // If the target is an entity, we need to use the entity's centre rather than the original hit position + // because the entity will have moved! + target = new Vec3d(hit.entityHit.posX, hit.entityHit.getEntityBoundingBox().minY + hit.entityHit.height/2, hit.entityHit.posZ); + } + + double distance = origin.distanceTo(target); + Vec3d direction = target.subtract(origin).normalize(); + + double maxLength = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade) * STRETCH_LIMIT; + + // If the vine stretched too far + if(distance > maxLength){ + if(world.isRemote && (ticksInUse-1) * extensionSpeed < distance){ + spawnLeafParticles(world, origin.subtract(0, SpellRay.Y_OFFSET, 0), direction, distance); + } + data.setVariable(TARGET_KEY, null); + return false; // The spell is finished + } + + boolean extending = ticksInUse * extensionSpeed < distance; + + if(extending){ + // Extension + if(world.isRemote){ + // world.getTotalWorldTime() - ticksInUse generates a constant but unique seed each time the spell is cast + ParticleBuilder.create(Type.VINE).entity(caster).pos(0, caster.getEyeHeight() - SpellRay.Y_OFFSET, 0) + .target(origin.add(direction.scale(ticksInUse * extensionSpeed))).tvel(direction.scale(extensionSpeed)) + .seed(world.getTotalWorldTime() - ticksInUse).spawn(world); + } + + }else{ + // Retraction + Vec3d velocity = direction.scale(getProperty(REEL_SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + + int retractTime = ticksInUse - (int)(distance/extensionSpeed); + + switch(hit.typeOfHit){ + + case BLOCK: + // Payout + if(caster.isSneaking() && ItemArtefact.isArtefactActive(caster, WizardryItems.charm_abseiling)) + velocity = new Vec3d(velocity.x, distance < maxLength-1 ? -PAYOUT_SPEED : distance-maxLength+1, velocity.z); + + // Reel the caster towards the block hit + double ax = (velocity.x - caster.motionX) * REEL_ACCELERATION; + double ay = (velocity.y - caster.motionY) * REEL_ACCELERATION; + double az = (velocity.z - caster.motionZ) * REEL_ACCELERATION; + caster.addVelocity(ax, ay, az); + + if(caster.motionY > 0 && !Wizardry.settings.replaceVanillaFallDamage) caster.fallDistance = 0; // Reset fall distance if the caster moves upwards + + if(world.isRemote){ + ParticleBuilder.create(Type.VINE).entity(caster).pos(0, caster.getEyeHeight() - SpellRay.Y_OFFSET, 0) + .target(target).seed(world.getTotalWorldTime() - ticksInUse).spawn(world); + } + + if(retractTime == 1){ // Just hit + this.playSound(world, caster, ticksInUse, -1, modifiers, "pull"); + this.playSound(world, hit.hitVec, ticksInUse, -1, modifiers, "attach"); + } + + break; + + case ENTITY: + // Payout + if(caster.isSneaking() && ItemArtefact.isArtefactActive(caster, WizardryItems.charm_abseiling)) + velocity = new Vec3d(velocity.x, distance < maxLength-1 ? PAYOUT_SPEED : maxLength-1-distance, velocity.z); + + // Reel the entity hit towards the caster + Entity entity = hit.entityHit; + + if(distance > MINIMUM_REEL_DISTANCE){ + double ax1 = (-velocity.x - entity.motionX) * REEL_ACCELERATION; + double ay1 = (-velocity.y - entity.motionY) * REEL_ACCELERATION; + double az1 = (-velocity.z - entity.motionZ) * REEL_ACCELERATION; + entity.addVelocity(ax1, ay1, az1); + // Player motion is handled on that player's client so needs packets + if(entity instanceof EntityPlayerMP){ + ((EntityPlayerMP)entity).connection.sendPacket(new SPacketEntityVelocity(entity)); + } + } + + if(world.isRemote){ + ParticleBuilder.create(Type.VINE).entity(caster).pos(0, caster.getEyeHeight() - SpellRay.Y_OFFSET, 0) + .target(entity).seed(world.getTotalWorldTime() - ticksInUse).spawn(world); + } + + if(retractTime == 1){ // Just hit + this.playSound(world, caster, ticksInUse, -1, modifiers, "pull"); + this.playSound(world, entity.posX, entity.posY, entity.posZ, ticksInUse, -1, modifiers, "attach"); + } + + break; + + default: + // Missed + if(world.isRemote && (ticksInUse-1) * extensionSpeed < distance){ + spawnLeafParticles(world, origin.subtract(0, SpellRay.Y_OFFSET, 0), direction, distance); + } + //caster.resetActiveHand(); + data.setVariable(TARGET_KEY, null); + return false; // The spell is finished + } + } + + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight(), caster.posZ); + + // If the target is an entity, we need to use the entity's centre rather than the original hit position + // because the entity will have moved! + Vec3d targetVec = new Vec3d(target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); + + double distance = origin.distanceTo(targetVec); + + // Can't cast the spell at all if the target is too far away + if(ticksInUse <= 1 && distance > getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade)) + return false; + + Vec3d vec = targetVec.subtract(origin).normalize(); + + float extensionSpeed = getProperty(EXTENSION_SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY); + + // If the vine stretched too far + if(distance > getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade) * STRETCH_LIMIT){ + if(world.isRemote && (ticksInUse-1) * extensionSpeed < distance){ + spawnLeafParticles(world, origin.subtract(0, SpellRay.Y_OFFSET, 0), vec, distance); + } + return false; + } + + Vec3d hookPosition; + + if(ticksInUse * extensionSpeed < distance){ + // Extension + hookPosition = origin.add(vec.scale(ticksInUse * extensionSpeed)); + + }else{ + // Retraction + Vec3d velocity = vec.scale(getProperty(REEL_SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + + // Reel the entity hit towards the caster + if(distance > MINIMUM_REEL_DISTANCE){ + double ax1 = (-velocity.x - target.motionX) * REEL_ACCELERATION; + double ay1 = (-velocity.y - target.motionY) * REEL_ACCELERATION; + double az1 = (-velocity.z - target.motionZ) * REEL_ACCELERATION; + target.addVelocity(ax1, ay1, az1); + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + } + + hookPosition = targetVec; + } + + if(world.isRemote){ + // world.getTotalWorldTime() - ticksInUse generates a constant but unique seed each time the spell is cast + ParticleBuilder.create(Type.VINE).pos(origin).target(hookPosition).tvel(vec.scale(extensionSpeed)) + .seed(world.getTotalWorldTime() - ticksInUse).spawn(world); + } + + return true; + } + + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + + Vec3d origin = new Vec3d(x, y, z); + + RayTraceResult result = findTarget(world, null, origin, new Vec3d(direction.getDirectionVec()), modifiers); + + if(result.entityHit instanceof EntityLivingBase){ + + Entity entity = result.entityHit; + + // If the target is an entity, we need to use the entity's centre rather than the original hit position + // because the entity will have moved! + Vec3d target = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.height/2, entity.posZ); + + double distance = origin.distanceTo(target); + Vec3d vec = target.subtract(origin).normalize(); + + float extensionSpeed = getProperty(EXTENSION_SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY); + + // If the vine stretched too far + if(distance > getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade) * STRETCH_LIMIT){ + if(world.isRemote && (ticksInUse-1) * extensionSpeed < distance){ + spawnLeafParticles(world, origin.subtract(0, SpellRay.Y_OFFSET, 0), vec, distance); + } + return false; + } + + Vec3d hookPosition; + + if(ticksInUse * extensionSpeed < distance){ + // Extension + hookPosition = origin.add(vec.scale(ticksInUse * extensionSpeed)); + + }else{ + // Retraction + Vec3d velocity = vec.scale(getProperty(REEL_SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + + // Reel the entity hit towards the caster + if(distance > MINIMUM_REEL_DISTANCE){ + double ax1 = (-velocity.x - entity.motionX) * REEL_ACCELERATION; + double ay1 = (-velocity.y - entity.motionY) * REEL_ACCELERATION; + double az1 = (-velocity.z - entity.motionZ) * REEL_ACCELERATION; + entity.addVelocity(ax1, ay1, az1); + // Player motion is handled on that player's client so needs packets + if(entity instanceof EntityPlayerMP){ + ((EntityPlayerMP)entity).connection.sendPacket(new SPacketEntityVelocity(entity)); + } + } + + hookPosition = target; + } + + if(world.isRemote){ + // world.getTotalWorldTime() - ticksInUse generates a constant but unique seed each time the spell is cast + ParticleBuilder.create(Type.VINE).pos(origin).target(hookPosition).seed(world.getTotalWorldTime() - ticksInUse).spawn(world); + } + + return true; + } + + return false; + } + + @Override + public void finishCasting(World world, @Nullable EntityLivingBase caster, double x, double y, double z, EnumFacing facing, int duration, SpellModifiers modifiers){ + + Vec3d origin = null; + Vec3d direction = null; + Vec3d target = null; + + if(caster != null){ + + origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight(), caster.posZ); + + if(caster instanceof EntityPlayer){ + WizardData data = WizardData.get((EntityPlayer)caster); + if(data != null){ + RayTraceResult hit = data.getVariable(TARGET_KEY); + if(hit != null) target = hit.hitVec; + } + }else if(caster instanceof EntityLiving){ + Entity entity = ((EntityLiving)caster).getAttackTarget(); + if(entity != null) target = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.height/2, entity.posZ); + } + + if(target != null) direction = target.subtract(origin).normalize(); + + this.playSound(world, caster, duration, duration, modifiers, "release"); + + }else if(!Double.isNaN(x) && !Double.isNaN(y) && !Double.isNaN(z)){ + + origin = new Vec3d(x, y, z); + direction = new Vec3d(facing.getDirectionVec()); + RayTraceResult result = findTarget(world, null, origin, direction, modifiers); + target = result.hitVec; + + this.playSound(world, origin, duration, duration, modifiers, "release"); + } + + if(world.isRemote && origin != null && direction != null){ + + float extensionSpeed = getProperty(EXTENSION_SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY); + double distance = Math.min(target.subtract(origin).length(), duration * extensionSpeed); + + spawnLeafParticles(world, origin, direction, distance); + } + } + + private void spawnLeafParticles(World world, Vec3d origin, Vec3d direction, double distance){ + // Copied from SpellRay + for(double d = PARTICLE_SPACING; d <= distance; d += PARTICLE_SPACING){ + double x = origin.x + d*direction.x;// + PARTICLE_JITTER * (world.rand.nextDouble()*2 - 1); + double y = origin.y + d*direction.y;// + PARTICLE_JITTER * (world.rand.nextDouble()*2 - 1); + double z = origin.z + d*direction.z;// + PARTICLE_JITTER * (world.rand.nextDouble()*2 - 1); + ParticleBuilder.create(Type.LEAF, world.rand, x, y, z, PARTICLE_JITTER, true).time(25 + world.rand.nextInt(5)).spawn(world); + } + } + + private RayTraceResult findTarget(World world, @Nullable EntityLivingBase caster, Vec3d origin, Vec3d direction, SpellModifiers modifiers){ + + double range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + + Vec3d endpoint = origin.add(direction.scale(range)); + + RayTraceResult result = RayTracer.rayTrace(world, origin, endpoint, 0, false, + true, false, Entity.class, RayTracer.ignoreEntityFilter(caster)); + + // Non-solid blocks (or if the result is null) count as misses + if(result == null || result.typeOfHit == RayTraceResult.Type.BLOCK + && !world.getBlockState(result.getBlockPos()).getMaterial().isSolid()){ + return new RayTraceResult(RayTraceResult.Type.MISS, endpoint, EnumFacing.DOWN, new BlockPos(endpoint)); + // Immovable entities count as misses too, but the endpoint is the hit vector instead + }else if(result.entityHit != null && !result.entityHit.canBePushed()){ + return new RayTraceResult(RayTraceResult.Type.MISS, result.hitVec, EnumFacing.DOWN, new BlockPos(endpoint)); + } + // If the ray trace missed, result.hitVec will be the endpoint anyway - neat! + return result; + } + + private static RayTraceResult update(EntityPlayer player, RayTraceResult grapplingTarget){ + + if(grapplingTarget != null && (!WizardryUtilities.isCasting(player, Spells.grapple) + || (grapplingTarget.entityHit != null && !grapplingTarget.entityHit.isEntityAlive()))){ + return null; + } + + return grapplingTarget; + } +} diff --git a/src/main/java/electroblob/wizardry/spell/GreaterFireball.java b/src/main/java/electroblob/wizardry/spell/GreaterFireball.java deleted file mode 100644 index 84db6989..00000000 --- a/src/main/java/electroblob/wizardry/spell/GreaterFireball.java +++ /dev/null @@ -1,85 +0,0 @@ -package electroblob.wizardry.spell; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.projectile.EntityLargeFireball; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - -public class GreaterFireball extends Spell { - - public GreaterFireball(){ - super("greater_fireball", Tier.ADVANCED, Element.FIRE, SpellType.ATTACK, 20, 30, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - Vec3d look = caster.getLookVec(); - - if(!world.isRemote){ - EntityLargeFireball fireball = new EntityLargeFireball(world, caster, 1, 1, 1); - fireball.setPosition(caster.posX + look.x, caster.posY + look.y + 1.3, caster.posZ + look.z); - fireball.accelerationX = look.x * 0.1; - fireball.accelerationY = look.y * 0.1; - fireball.accelerationZ = look.z * 0.1; - world.spawnEntity(fireball); - } - - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - caster.swingArm(hand); - return true; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, - SpellModifiers modifiers){ - - if(target != null){ - - if(!world.isRemote){ - - EntityLargeFireball fireball = new EntityLargeFireball(world, caster, 1, 1, 1); - - double dx = target.posX - caster.posX; - double dy = target.getEntityBoundingBox().minY + (double)(target.height / 2.0F) - - (caster.posY + (double)(caster.height / 2.0F)); - double dz = target.posZ - caster.posZ; - - fireball.accelerationX = dx / caster.getDistance(target) * 0.1; - fireball.accelerationY = dy / caster.getDistance(target) * 0.1; - fireball.accelerationZ = dz / caster.getDistance(target) * 0.1; - - fireball.setPosition(caster.posX, caster.posY + caster.getEyeHeight(), caster.posZ); - - world.spawnEntity(fireball); - } - - caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 1, 1); - caster.swingArm(hand); - return true; - } - - return false; - } - - @Override - public boolean canBeCastByNPCs(){ - return true; - } - -} diff --git a/src/main/java/electroblob/wizardry/spell/GreaterHeal.java b/src/main/java/electroblob/wizardry/spell/GreaterHeal.java index 52452809..9d7055fc 100644 --- a/src/main/java/electroblob/wizardry/spell/GreaterHeal.java +++ b/src/main/java/electroblob/wizardry/spell/GreaterHeal.java @@ -1,24 +1,21 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; public class GreaterHeal extends SpellBuff { public GreaterHeal(){ - super("greater_heal", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 15, 40, WizardrySounds.SPELL_HEAL, 1, 1, 0.3f); + super("greater_heal", 1, 1, 0.3f); this.soundValues(0.7f, 1.2f, 0.4f); + addProperties(HEALTH); } @Override protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ if(caster.getHealth() < caster.getMaxHealth() && caster.getHealth() > 0){ - caster.heal(8 * modifiers.get(SpellModifiers.POTENCY)); + caster.heal(getProperty(HEALTH).floatValue() * modifiers.get(SpellModifiers.POTENCY)); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/GreaterTelekinesis.java b/src/main/java/electroblob/wizardry/spell/GreaterTelekinesis.java new file mode 100644 index 00000000..3929d8d2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/GreaterTelekinesis.java @@ -0,0 +1,159 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.EntityLevitatingBlock; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityTNTPrimed; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.EnumAction; +import net.minecraft.network.play.server.SPacketEntityVelocity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class GreaterTelekinesis extends SpellRay { + + public static final String HOLD_RANGE = "hold_range"; + public static final String THROW_VELOCITY = "throw_velocity"; + + /** Makes things a bit smoother-looking / 'realistic'. */ + private static final float UNDERSHOOT = 0.2f; + + public GreaterTelekinesis(){ + super("greater_telekinesis", true, EnumAction.NONE); + this.aimAssist(0.4f); + this.particleSpacing(1); + this.particleJitter(0.05); + this.particleVelocity(0.3); + addProperties(HOLD_RANGE, THROW_VELOCITY, DAMAGE); + this.soundValues(0.8f, 1, 0.2f); + } + + @Override public boolean canBeCastByNPCs() { return false; } + @Override public boolean canBeCastByDispensers() { return false; } + + @Override + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + // Can't be cast by dispensers so we know caster isn't null, but just in case... + if(caster != null && (target instanceof EntityLivingBase || target instanceof EntityLevitatingBlock || target instanceof EntityTNTPrimed)){ + + if(target instanceof EntityPlayer && ((caster instanceof EntityPlayer && !Wizardry.settings.playersMoveEachOther) + || ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring))){ + + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); + return false; + } + + if(target instanceof EntityLevitatingBlock){ + ((EntityLevitatingBlock)target).suspend(); + ((EntityLevitatingBlock)target).setCaster(caster); // Yep, you can steal other players' blocks in mid-air! + } + + Vec3d targetPos = target.getPositionVector().add(0, target.height/2, 0); + + if(caster.isSneaking()){ + + Vec3d look = caster.getLookVec().scale(getProperty(THROW_VELOCITY).floatValue() * modifiers.get(WizardryItems.range_upgrade)); + target.addVelocity(look.x, look.y, look.z); + if(caster instanceof EntityPlayer) caster.swingArm(caster.getActiveHand()); + + }else{ + + WizardryUtilities.undoGravity(target); + + // The following code extrapolates the entity's current velocity to determine whether it will pass the + // target position in the next tick, and adds or subtracts velocity accordingly. + + Vec3d vec = origin.add(caster.getLookVec().scale(getProperty(HOLD_RANGE).floatValue())); + + Vec3d velocity = vec.subtract(targetPos).subtract(target.motionX, target.motionY, target.motionZ) + .scale(1 - UNDERSHOOT); + + target.addVelocity(velocity.x, velocity.y, velocity.z); + } + + // Player motion is handled on that player's client so needs packets + if(target instanceof EntityPlayerMP){ + ((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target)); + } + + if(world.isRemote){ + + ParticleBuilder.create(Type.BEAM).entity(caster).clr(0.2f, 0.6f + 0.3f * world.rand.nextFloat(), 1) + .pos(origin.subtract(caster.getPositionVector())).target(target).time(0) + .scale(MathHelper.sin(ticksInUse * 0.3f) * 0.1f + 0.9f).spawn(world); + + if(ticksInUse % 18 == 1) ParticleBuilder.create(Type.FLASH).entity(target).pos(0, target.height/2, 0) + .scale(2.5f).time(30).clr(0.2f, 0.8f, 1).fade(1f, 1f, 1f).spawn(world); + + ParticleBuilder.create(Type.SPARKLE, target).vel(0, 0.05, 0).time(15).scale(0.6f).clr(0.2f, 0.6f, 1) + .fade(1f, 1f, 1f).spawn(world); + } + + return true; + } + + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.canDamageBlocks(caster, world) && !WizardryUtilities.isBlockUnbreakable(world, pos) + && world.getBlockState(pos).getMaterial().isSolid() + && (world.getTileEntity(pos) == null || !world.getTileEntity(pos).getTileData().hasUniqueId(ArcaneLock.NBT_KEY))){ + + if(!world.isRemote){ + + EntityLevitatingBlock block = new EntityLevitatingBlock(world, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, + world.getBlockState(pos)); + + block.fallTime = 1; + block.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + block.setCaster(caster); + + world.spawnEntity(block); + world.setBlockToAir(pos); + } + + return true; + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/GroupHeal.java b/src/main/java/electroblob/wizardry/spell/GroupHeal.java index 71593ec1..cc2677e0 100644 --- a/src/main/java/electroblob/wizardry/spell/GroupHeal.java +++ b/src/main/java/electroblob/wizardry/spell/GroupHeal.java @@ -1,16 +1,8 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; @@ -19,10 +11,14 @@ import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.world.World; +import java.util.List; + public class GroupHeal extends Spell { public GroupHeal(){ - super("group_heal", Tier.ADVANCED, Element.HEALING, SpellType.DEFENCE, 35, 150, EnumAction.BOW, false); + super("group_heal", EnumAction.BOW, false); + this.soundValues(0.7f, 1.2f, 0.4f); + addProperties(EFFECT_RADIUS, HEALTH); } @Override @@ -30,64 +26,20 @@ public class GroupHeal extends Spell { boolean flag = false; - List targets = WizardryUtilities.getEntitiesWithinRadius( - 5 * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + List targets = WizardryUtilities.getEntitiesWithinRadius(getProperty(EFFECT_RADIUS).floatValue() + * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); for(EntityLivingBase target : targets){ - if(target instanceof EntityPlayer){ + if(target == caster || AllyDesignationSystem.isAllied(caster, target)){ - if(WizardryUtilities.isPlayerAlly(caster, (EntityPlayer)target) || target == caster){ + if(target.getHealth() < target.getMaxHealth() && target.getHealth() > 0){ - if(((EntityPlayer)target).shouldHeal()){ + target.heal(getProperty(HEALTH).floatValue() * modifiers.get(SpellModifiers.POTENCY)); - target.heal(6 * modifiers.get(SpellModifiers.POTENCY)); - - if(world.isRemote){ - - for(int i = 0; i < 10; i++){ - double x = caster.posX + world.rand.nextDouble() * 2 - 1; - double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); - double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(1, 1, 0.3f).spawn(world); - } - - ParticleBuilder.create(Type.BUFF).entity(caster).clr(1, 1, 0.3f).spawn(world); - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - flag = true; - } - } - - // Now also works on summoned creatures - }else if(target instanceof ISummonedCreature){ - - EntityLivingBase summoner = ((ISummonedCreature)target).getCaster(); - - if(summoner == caster || (summoner instanceof EntityPlayer - && WizardryUtilities.isPlayerAlly(caster, (EntityPlayer)summoner))){ - - if(target.getHealth() < target.getMaxHealth() && target.getHealth() > 0){ - - target.heal(6 * modifiers.get(SpellModifiers.POTENCY)); - - if(world.isRemote){ - for(int i = 0; i < 10; i++){ - double x = caster.posX + world.rand.nextDouble() * 2 - 1; - double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); - double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(1, 1, 0.3f).spawn(world); - } - - ParticleBuilder.create(Type.BUFF).entity(caster).clr(1, 1, 0.3f).spawn(world); - } - - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - flag = true; - } + if(world.isRemote) ParticleBuilder.spawnHealParticles(world, target); + playSound(world, target, ticksInUse, -1, modifiers); + flag = true; } } } diff --git a/src/main/java/electroblob/wizardry/spell/GrowthAura.java b/src/main/java/electroblob/wizardry/spell/GrowthAura.java index c873ba80..929c803f 100644 --- a/src/main/java/electroblob/wizardry/spell/GrowthAura.java +++ b/src/main/java/electroblob/wizardry/spell/GrowthAura.java @@ -1,9 +1,7 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.IGrowable; @@ -15,14 +13,18 @@ import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import java.util.List; + public class GrowthAura extends Spell { public GrowthAura(){ - super("growth_aura", Tier.APPRENTICE, Element.EARTH, SpellType.UTILITY, 20, 50, EnumAction.NONE, false); + super("growth_aura", EnumAction.NONE, false); + addProperties(EFFECT_RADIUS); + soundValues(0.7f, 1.2f, 0.2f); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @@ -31,45 +33,43 @@ public class GrowthAura extends Spell { boolean flag = false; - for(int i = -2; i < 1; i++){ + List sphere = WizardryUtilities.getBlockSphere(caster.getPosition(), + getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade)); - for(int j = -1; j < 2; j++){ + for(BlockPos pos : sphere){ - int x = (int)caster.posX + i; - int y = WizardryUtilities.getNearestFloorLevelC(world, - new BlockPos(caster.posX + i, caster.posY, caster.posZ + j), 2) - 1; - int z = (int)caster.posZ + j; + IBlockState state = world.getBlockState(pos); - BlockPos pos = new BlockPos(x, y, z); + if(state.getBlock() instanceof IGrowable){ - if(y > -1 && caster.getDistance(x, y, z) <= 2){ + IGrowable plant = (IGrowable)state.getBlock(); - IBlockState state = world.getBlockState(pos); + if(plant.canGrow(world, pos, state, world.isRemote)){ - if(state.getBlock() instanceof IGrowable){ - - IGrowable igrowable = (IGrowable)state.getBlock(); - - if(igrowable.canGrow(world, pos, state, world.isRemote)){ - - if(!world.isRemote){ - if(igrowable.canUseBonemeal(world, world.rand, pos, state)){ - igrowable.grow(world, world.rand, pos, state); + if(!world.isRemote){ + if(plant.canUseBonemeal(world, world.rand, pos, state)){ + if(world.rand.nextFloat() < 0.35f && ItemArtefact.isArtefactActive(caster, WizardryItems.charm_growth)){ + while(plant.canGrow(world, pos, state, false)){ + plant.grow(world, world.rand, pos, state); + state = world.getBlockState(pos); // Update the state with the new one + plant = (IGrowable)state.getBlock(); // Update the block with the new one } }else{ - // Yes, it's meant to be 0, and it automatically changes it to 15. - ItemDye.spawnBonemealParticles(world, pos, 0); + plant.grow(world, world.rand, pos, state); } - - flag = true; } + }else{ + // Yes, it's meant to be 0, and it automatically changes it to 15. + ItemDye.spawnBonemealParticles(world, pos, 0); } + + flag = true; } } } - if(flag) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); + if(flag) this.playSound(world, caster, ticksInUse, -1, modifiers); + return flag; } diff --git a/src/main/java/electroblob/wizardry/spell/Hailstorm.java b/src/main/java/electroblob/wizardry/spell/Hailstorm.java index b054517e..b68d2ecd 100644 --- a/src/main/java/electroblob/wizardry/spell/Hailstorm.java +++ b/src/main/java/electroblob/wizardry/spell/Hailstorm.java @@ -1,23 +1,20 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityHailstorm; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; import net.minecraft.world.World; public class Hailstorm extends SpellConstructRanged { public Hailstorm(){ - super("hailstorm", Tier.MASTER, Element.ICE, SpellType.ATTACK, 75, 300, EntityHailstorm::new, 120, 20, WizardrySounds.SPELL_ICE); + super("hailstorm", EntityHailstorm::new, false); this.floor(true); } @Override - protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ // Moves the entity back towards the caster a bit, so the area of effect is better centred on the position. // 3 is the distance to move the entity back towards the caster. @@ -29,13 +26,13 @@ public class Hailstorm extends SpellConstructRanged { // Moves the entity up 5 blocks so that it is above mobs' heads. y += 5; - return super.spawnConstruct(world, x, y, z, caster, modifiers); + return super.spawnConstruct(world, x, y, z, side, caster, modifiers); } @Override - protected void addConstructExtras(EntityHailstorm construct, EntityLivingBase caster, SpellModifiers modifiers){ + protected void addConstructExtras(EntityHailstorm construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ // Makes the arrows shoot in the direction the caster was looking when they cast the spell. - construct.rotationYaw = caster.rotationYawHead; + if(caster != null) construct.rotationYaw = caster.rotationYawHead; } } diff --git a/src/main/java/electroblob/wizardry/spell/Heal.java b/src/main/java/electroblob/wizardry/spell/Heal.java index 46055d50..8bc201da 100644 --- a/src/main/java/electroblob/wizardry/spell/Heal.java +++ b/src/main/java/electroblob/wizardry/spell/Heal.java @@ -1,24 +1,21 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; public class Heal extends SpellBuff { public Heal(){ - super("heal", Tier.BASIC, Element.HEALING, SpellType.DEFENCE, 5, 20, WizardrySounds.SPELL_HEAL, 1, 1, 0.3f); + super("heal", 1, 1, 0.3f); this.soundValues(0.7f, 1.2f, 0.4f); + addProperties(HEALTH); } @Override protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ if(caster.getHealth() < caster.getMaxHealth() && caster.getHealth() > 0){ - caster.heal(4 * modifiers.get(SpellModifiers.POTENCY)); + caster.heal(getProperty(HEALTH).floatValue() * modifiers.get(SpellModifiers.POTENCY)); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/HealAlly.java b/src/main/java/electroblob/wizardry/spell/HealAlly.java index e36ab8eb..ffcbf274 100644 --- a/src/main/java/electroblob/wizardry/spell/HealAlly.java +++ b/src/main/java/electroblob/wizardry/spell/HealAlly.java @@ -1,29 +1,26 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class HealAlly extends SpellRay { public HealAlly(){ - super("heal_ally", Tier.APPRENTICE, Element.HEALING, SpellType.DEFENCE, 10, 20, false, 10, WizardrySounds.SPELL_HEAL); + super("heal_ally", false, EnumAction.NONE); this.soundValues(0.7f, 1.2f, 0.4f); + addProperties(HEALTH); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ @@ -31,21 +28,10 @@ public class HealAlly extends SpellRay { if(entity.getHealth() < entity.getMaxHealth() && entity.getHealth() > 0){ - entity.heal((int)(5 * modifiers.get(SpellModifiers.POTENCY))); + entity.heal(getProperty(HEALTH).floatValue() * modifiers.get(SpellModifiers.POTENCY)); - if(world.isRemote){ - - float r = 1; float g = 1; float b = 0.3f; - - for(int i = 0; i < 10; i++){ - double x1 = (double)((float)entity.posX + world.rand.nextFloat() * 2 - 1.0f); - double y1 = (double)((float)entity.getEntityBoundingBox().minY + entity.getEyeHeight() - 0.5f + world.rand.nextFloat()); - double z1 = (double)((float)entity.posZ + world.rand.nextFloat() * 2 - 1.0f); - ParticleBuilder.create(Type.SPARKLE).pos(x1, y1, z1).vel(0, 0.1F, 0).clr(r, g, b).spawn(world); - } - - ParticleBuilder.create(Type.BUFF).entity(caster).clr(r, g, b).spawn(world); - } + if(world.isRemote) ParticleBuilder.spawnHealParticles(world, entity); + playSound(world, entity, ticksInUse, -1, modifiers); } return true; @@ -55,12 +41,12 @@ public class HealAlly extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/IceAge.java b/src/main/java/electroblob/wizardry/spell/IceAge.java index 040e5c32..8c94d203 100644 --- a/src/main/java/electroblob/wizardry/spell/IceAge.java +++ b/src/main/java/electroblob/wizardry/spell/IceAge.java @@ -1,163 +1,89 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; +import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.tileentity.TileEntityStatue; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.monster.EntityBlaze; -import net.minecraft.entity.monster.EntityMagmaCube; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import java.util.List; + public class IceAge extends Spell { - private static final int baseDuration = 1200; - public IceAge(){ - super("ice_age", Tier.MASTER, Element.ICE, SpellType.ATTACK, 70, 250, EnumAction.BOW, false); + super("ice_age", EnumAction.BOW, false); + this.soundValues(0.7f, 1.0f, 0); + addProperties(EFFECT_RADIUS, EFFECT_DURATION); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - List targets = WizardryUtilities.getEntitiesWithinRadius( - 7 * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + float radius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade); + + List targets = WizardryUtilities.getEntitiesWithinRadius(radius, caster.posX, caster.posY, caster.posZ, world); for(EntityLivingBase target : targets){ - if(WizardryUtilities.isValidTarget(caster, target)){ + if(AllyDesignationSystem.isValidTarget(caster, target)){ if(!world.isRemote){ - if(target instanceof EntityBlaze || target instanceof EntityMagmaCube){ - // These have been removed for the time being because they cause the entity to sink into the - // floor when it breaks out. - // target.attackEntityFrom(WizardryUtilities.causePlayerMagicDamage(entityplayer), 8.0f * - // modifiers.get(SpellModifiers.DAMAGE)); - }else{ - // target.attackEntityFrom(WizardryUtilities.causePlayerMagicDamage(entityplayer), 4.0f * - // modifiers.get(SpellModifiers.DAMAGE)); - } - if(target.isBurning()){ - target.extinguish(); - } - - if(target instanceof EntityBlaze) WizardryAdvancementTriggers.freeze_blaze.triggerFor(caster); if(target instanceof EntityLiving){ - - // Stops the entity looking red while frozen and the resulting z-fighting - target.hurtTime = 0; - - BlockPos pos = new BlockPos(target); - - // Short mobs such as spiders and pigs - if((target.height < 1.2 || target.isChild()) - && WizardryUtilities.canBlockBeReplaced(world, pos)){ - world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart((EntityLiving)target, 1, - 1); - ((TileEntityStatue)world.getTileEntity(pos)).setLifetime( - (int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - target.setDead(); - target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); - } - // Normal sized mobs like zombies and skeletons - else if(target.height < 2.5 && WizardryUtilities.canBlockBeReplaced(world, pos) - && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ - world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart((EntityLiving)target, 1, - 2); - ((TileEntityStatue)world.getTileEntity(pos)).setLifetime( - (int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - - world.setBlockState(pos.up(), WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up())) - .setCreatureAndPart((EntityLiving)target, 2, 2); - } - target.setDead(); - target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); - } - // Tall mobs like endermen - else if(WizardryUtilities.canBlockBeReplaced(world, pos) - && WizardryUtilities.canBlockBeReplaced(world, pos.up()) - && WizardryUtilities.canBlockBeReplaced(world, pos.up(2))){ - world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart((EntityLiving)target, 1, - 3); - ((TileEntityStatue)world.getTileEntity(pos)).setLifetime( - (int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade))); - } - - world.setBlockState(pos.up(), WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up())) - .setCreatureAndPart((EntityLiving)target, 2, 3); - } - - world.setBlockState(pos.up(2), WizardryBlocks.ice_statue.getDefaultState()); - if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos.up(2))) - .setCreatureAndPart((EntityLiving)target, 3, 3); - } - target.setDead(); - target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); + if(((BlockStatue)WizardryBlocks.ice_statue).convertToStatue((EntityLiving)target, + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)))){ + target.playSound(WizardrySounds.MISC_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); } } } } } - if(!world.isRemote){ - for(int i = -7; i < 8; i++){ - for(int j = -7; j < 8; j++){ + if(!world.isRemote && WizardryUtilities.canDamageBlocks(caster, world)){ + for(int i = -(int)radius; i < (int)radius + 1; i++){ + for(int j = -(int)radius; j < (int)radius + 1; j++){ BlockPos pos = new BlockPos(caster).add(i, 0, j); - int y = WizardryUtilities.getNearestFloorLevelB(world, new BlockPos(pos), 7); + Integer y = WizardryUtilities.getNearestSurface(world, new BlockPos(pos), EnumFacing.UP, (int)radius, true, WizardryUtilities.SurfaceCriteria.BUILDABLE); - pos = new BlockPos(pos.getX(), y, pos.getZ()); + if(y != null){ - double dist = caster.getDistance((int)caster.posX + i, y, (int)caster.posZ + j); + pos = new BlockPos(pos.getX(), y, pos.getZ()); - // Randomised with weighting so that the nearer the block the more likely it is to be snowed. - if(y != -1 && world.rand.nextInt((int)dist * 2 + 1) < 7 && dist < 8){ - if(world.getBlockState(pos.down()) == Blocks.WATER.getDefaultState()){ - world.setBlockState(pos.down(), Blocks.ICE.getDefaultState()); - }else if(world.getBlockState(pos.down()) == Blocks.LAVA.getDefaultState()){ - world.setBlockState(pos.down(), Blocks.OBSIDIAN.getDefaultState()); - }else if(world.getBlockState(pos.down()) == Blocks.FLOWING_LAVA.getDefaultState()){ - world.setBlockState(pos.down(), Blocks.COBBLESTONE.getDefaultState()); - }else if(Blocks.SNOW_LAYER.canPlaceBlockAt(world, pos)){ - world.setBlockState(pos, Blocks.SNOW_LAYER.getDefaultState()); + double dist = caster.getDistance((int)caster.posX + i, y, (int)caster.posZ + j); + + // Randomised with weighting so that the nearer the block the more likely it is to be snowed. + if(y != -1 && world.rand.nextInt((int)dist * 2 + 1) < radius && dist < radius){ + if(world.getBlockState(pos.down()) == Blocks.WATER.getDefaultState()){ + world.setBlockState(pos.down(), Blocks.ICE.getDefaultState()); + }else if(world.getBlockState(pos.down()) == Blocks.LAVA.getDefaultState()){ + world.setBlockState(pos.down(), Blocks.OBSIDIAN.getDefaultState()); + }else if(world.getBlockState(pos.down()) == Blocks.FLOWING_LAVA.getDefaultState()){ + world.setBlockState(pos.down(), Blocks.COBBLESTONE.getDefaultState()); + }else if(Blocks.SNOW_LAYER.canPlaceBlockAt(world, pos)){ + world.setBlockState(pos, Blocks.SNOW_LAYER.getDefaultState()); + } } } } } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.7F, 1.0f); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_WIND, 1.0F, 1.0f); + + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/IceSpikes.java b/src/main/java/electroblob/wizardry/spell/IceSpikes.java index 7a07adc7..5f7f7d26 100644 --- a/src/main/java/electroblob/wizardry/spell/IceSpikes.java +++ b/src/main/java/electroblob/wizardry/spell/IceSpikes.java @@ -1,49 +1,62 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityIceSpike; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class IceSpikes extends SpellConstructRanged { - private static final int BASE_SPAWN_COUNT = 17; // Was 18, reduced to 17 to account for the extra one in the middle. + public static final String ICE_SPIKE_COUNT = "ice_spike_count"; public IceSpikes(){ - // Base duration is set to -1 so that the superclass doesn't waste time retrieving the duration multiplier - super("ice_spikes", Tier.ADVANCED, Element.ICE, SpellType.ATTACK, 30, 75, EntityIceSpike::new, -1, 20, WizardrySounds.SPELL_ICE); + super("ice_spikes", EntityIceSpike::new, true); + addProperties(EFFECT_RADIUS, ICE_SPIKE_COUNT, DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH); + this.ignoreUncollidables(true); } @Override - protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ - - if(world.getBlockState(new BlockPos(x, y, z)).isNormalCube()) return false; + protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ + + BlockPos blockHit = new BlockPos(x, y, z); + if(side != null && side.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE) blockHit = blockHit.offset(side); + + if(world.getBlockState(blockHit).isNormalCube()) return false; + + Vec3d origin = new Vec3d(x, y, z); + + Vec3d pos = origin.add(new Vec3d(side.getOpposite().getDirectionVec())); // Now always spawns a spike exactly at the position aimed at - super.spawnConstruct(world, x, y-1, z, caster, modifiers); - - int quantity = (int)(BASE_SPAWN_COUNT * modifiers.get(WizardryItems.blast_upgrade)); + super.spawnConstruct(world, pos.x, pos.y, pos.z, side, caster, modifiers); + // -1 because of the one spawned above + int quantity = (int)(getProperty(ICE_SPIKE_COUNT).floatValue() * modifiers.get(WizardryItems.blast_upgrade)) - 1; + + float maxRadius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade); for(int i=0; i -1){ - super.spawnConstruct(world, x1, y1, z1, caster, modifiers); + // First, generate a random vector of length radius with a z component of zero + // Then rotate it so that what was south is now the side that was hit + Vec3d offset = Vec3d.fromPitchYaw(world.rand.nextFloat() * 180 - 90, world.rand.nextBoolean() ? 0 : 180) + .scale(radius).rotateYaw(side.getHorizontalAngle() * (float)Math.PI/180).rotatePitch(WizardryUtilities.getPitch(side) * (float)Math.PI/180); + + if(side.getAxis().isHorizontal()) offset = offset.rotateYaw((float)Math.PI/2); + + Integer surface = WizardryUtilities.getNearestSurface(world, new BlockPos(origin.add(offset)), side, + (int)maxRadius, true, WizardryUtilities.SurfaceCriteria.basedOn(World::isBlockFullCube)); + + if(surface != null){ + Vec3d vec = WizardryUtilities.replaceComponent(origin.add(offset), side.getAxis(), surface) + .subtract(new Vec3d(side.getDirectionVec())); + super.spawnConstruct(world, vec.x, vec.y, vec.z, side, caster, modifiers); } } @@ -51,9 +64,10 @@ public class IceSpikes extends SpellConstructRanged { } @Override - protected void addConstructExtras(EntityIceSpike construct, EntityLivingBase caster, SpellModifiers modifiers){ + protected void addConstructExtras(EntityIceSpike construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ // In this particular case, lifetime is implemented as a delay instead so is treated differently. construct.lifetime = 30 + construct.world.rand.nextInt(15); + construct.setFacing(side); } } diff --git a/src/main/java/electroblob/wizardry/spell/IceStatue.java b/src/main/java/electroblob/wizardry/spell/IceStatue.java index 9c5b1cfd..35665491 100644 --- a/src/main/java/electroblob/wizardry/spell/IceStatue.java +++ b/src/main/java/electroblob/wizardry/spell/IceStatue.java @@ -1,54 +1,56 @@ package electroblob.wizardry.spell; import electroblob.wizardry.block.BlockStatue; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class IceStatue extends SpellRay { - private static final int BASE_DURATION = 400; - public IceStatue(){ - super("ice_statue", Tier.APPRENTICE, Element.ICE, SpellType.ATTACK, 15, 40, false, 10, WizardrySounds.SPELL_ICE); + super("ice_statue", false, EnumAction.NONE); this.soundValues(1, 1.4f, 0.4f); + addProperties(EFFECT_DURATION); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected SoundEvent[] createSounds(){ + return createSoundsWithSuffixes("shoot", "freeze"); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(target instanceof EntityLiving && !world.isRemote){ // Unchecked cast is fine because the block is a static final field if(((BlockStatue)WizardryBlocks.ice_statue).convertToStatue((EntityLiving)target, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)))){ - - target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); - return true; + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)))){ + + //target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); } } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Ignite.java b/src/main/java/electroblob/wizardry/spell/Ignite.java index 0acbe1c5..b686d89d 100644 --- a/src/main/java/electroblob/wizardry/spell/Ignite.java +++ b/src/main/java/electroblob/wizardry/spell/Ignite.java @@ -1,34 +1,32 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class Ignite extends SpellRay { - - /** The base duration for which entities are set on fire by this spell. */ - private static final int BASE_DURATION = 10; public Ignite(){ - super("ignite", Tier.BASIC, Element.FIRE, SpellType.ATTACK, 5, 10, false, 10, SoundEvents.ITEM_FLINTANDSTEEL_USE); + super("ignite", false, EnumAction.NONE); this.soundValues(1, 1, 0.4f); + addProperties(BURN_DURATION); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ // Fire can damage armour stands, so this includes them if(target instanceof EntityLivingBase) { @@ -36,7 +34,7 @@ public class Ignite extends SpellRay { if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ - target.setFire((int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); + target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); } return true; @@ -46,8 +44,10 @@ public class Ignite extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(!WizardryUtilities.canDamageBlocks(caster, world)) return false; + pos = pos.offset(side); if(world.isAirBlock(pos)){ @@ -63,7 +63,7 @@ public class Ignite extends SpellRay { } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java index ec1178fd..a41cd34b 100644 --- a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java @@ -1,30 +1,27 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.registry.WizardryEnchantments; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemBow; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemSword; +import net.minecraft.item.*; import net.minecraft.util.EnumHand; import net.minecraft.world.World; +import java.util.Arrays; + public class ImbueWeapon extends Spell { public ImbueWeapon(){ - super("imbue_weapon", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 20, 50, EnumAction.BOW, false); + super("imbue_weapon", EnumAction.BOW, false); + addProperties(EFFECT_DURATION); } @Override @@ -35,29 +32,29 @@ public class ImbueWeapon extends Spell { for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(caster)){ - if(stack.getItem() instanceof ItemSword + if(isSword(stack.getItem()) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.magic_sword) && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.magic_sword) <= 0){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. stack.addEnchantment(WizardryEnchantments.magic_sword, modifiers.get(SpellModifiers.POTENCY) == 1.0f ? 1 - : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) / Constants.DAMAGE_INCREASE_PER_TIER + : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) / Constants.POTENCY_INCREASE_PER_TIER + 0.5f)); WizardData.get(caster).setImbuementDuration(WizardryEnchantments.magic_sword, - (int)(900 * modifiers.get(WizardryItems.duration_upgrade))); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); - }else if(stack.getItem() instanceof ItemBow + }else if(isBow(stack.getItem()) && !EnchantmentHelper.getEnchantments(stack).containsKey(WizardryEnchantments.magic_bow) && WizardData.get(caster).getImbuementDuration(WizardryEnchantments.magic_bow) <= 0){ // The enchantment level as determined by the damage multiplier. The + 0.5f is so that // weird float processing doesn't incorrectly round it down. stack.addEnchantment(WizardryEnchantments.magic_bow, modifiers.get(SpellModifiers.POTENCY) == 1.0f ? 1 - : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) / Constants.DAMAGE_INCREASE_PER_TIER + : (int)((modifiers.get(SpellModifiers.POTENCY) - 1.0f) / Constants.POTENCY_INCREASE_PER_TIER + 0.5f)); WizardData.get(caster).setImbuementDuration(WizardryEnchantments.magic_bow, - (int)(900 * modifiers.get(WizardryItems.duration_upgrade))); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); }else{ continue; @@ -72,11 +69,21 @@ public class ImbueWeapon extends Spell { } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } } return false; } + /** Returns true if the given item counts as a sword, i.e. it extends {@link ItemSword} or is in the whitelist. */ + public static boolean isSword(Item item){ + return item instanceof ItemSword || Arrays.asList(Wizardry.settings.swordItemWhitelist).contains(item.getRegistryName()); + } + + /** Returns true if the given item counts as a bow, i.e. it extends {@link ItemBow} or is in the whitelist. */ + public static boolean isBow(Item item){ + return item instanceof ItemBow || Arrays.asList(Wizardry.settings.bowItemWhitelist).contains(item.getRegistryName()); + } + } diff --git a/src/main/java/electroblob/wizardry/spell/Intimidate.java b/src/main/java/electroblob/wizardry/spell/Intimidate.java index 626c7210..6c9889ea 100644 --- a/src/main/java/electroblob/wizardry/spell/Intimidate.java +++ b/src/main/java/electroblob/wizardry/spell/Intimidate.java @@ -1,10 +1,5 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.ParticleBuilder; @@ -13,11 +8,9 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityCreature; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.RandomPositionGenerator; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.pathfinding.PathPoint; @@ -29,17 +22,22 @@ import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.util.List; + @Mod.EventBusSubscriber public class Intimidate extends Spell { /** The NBT tag name for storing the feared entity's UUID in the target's tag compound. */ public static final String NBT_KEY = "fearedEntity"; - - private static final double BASE_RANGE = 8; - private static final int BASE_DURATION = 600; + + // These aren't spell properties because they're part fo the actual potion effect, not the spell itself. + // However, the avoid distance can be modified using the potion amplifier. + private static final double BASE_AVOID_DISTANCE = 16; + private static final double AVOID_DISTANCE_PER_LEVEL = 4; public Intimidate(){ - super("intimidate", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 20, 100, EnumAction.BOW, false); + super("intimidate", EnumAction.BOW, false); + addProperties(EFFECT_RADIUS, EFFECT_DURATION, EFFECT_STRENGTH); } @Override @@ -48,19 +46,21 @@ public class Intimidate extends Spell { if(!world.isRemote){ List entities = WizardryUtilities.getEntitiesWithinRadius( - BASE_RANGE * modifiers.get(WizardryItems.range_upgrade), caster.posX, caster.posY, caster.posZ, - world, EntityCreature.class); + getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.range_upgrade), + caster.posX, caster.posY, caster.posZ, world, EntityCreature.class); for(EntityCreature target : entities){ + // Why do we need this here? + //runAway(target, caster); - runAway(target, caster); + int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)); NBTTagCompound entityNBT = target.getEntityData(); if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); - ((EntityLiving)target).addPotionEffect(new PotionEffect(WizardryPotions.fear, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); - + target.addPotionEffect(new PotionEffect(WizardryPotions.fear, + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier)); } }else{ @@ -71,7 +71,7 @@ public class Intimidate extends Spell { 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); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -81,13 +81,14 @@ public class Intimidate extends Spell { * * @param target The entity running away * @param caster The entity that is being run away from + * @param distance How far the entity will run from the caster * @return True if a new path was found and set, false if not. */ - public static boolean runAway(EntityCreature target, EntityLivingBase caster){ + public static boolean runAway(EntityCreature target, EntityLivingBase caster, double distance){ - if(target.getDistance(caster) < 16){ + if(target.getDistance(caster) < distance){ - Vec3d Vec3d = RandomPositionGenerator.findRandomTargetBlockAwayFrom(target, 16, 7, + Vec3d Vec3d = RandomPositionGenerator.findRandomTargetBlockAwayFrom(target, (int)distance, (int)(distance/2), new Vec3d(caster.posX, caster.posY, caster.posZ)); if(Vec3d == null){ @@ -95,15 +96,14 @@ public class Intimidate extends Spell { }else{ // In both cases it is necessary to check if the entity already has a path so it doesn't change - // direction - // every tick, unless that path is towards the caster. + // direction every tick, unless that path is towards the caster. // Path path = target.getNavigator().getPathToXYZ(Vec3d.xCoord, Vec3d.yCoord, Vec3d.zCoord); boolean flag = true; if(!target.getNavigator().noPath()){ PathPoint point = target.getNavigator().getPath().getFinalPathPoint(); - if(point != null) flag = caster.getDistance(point.x, point.y, point.z) < 16; + if(point != null) flag = caster.getDistance(point.x, point.y, point.z) < distance; } // Has a built in mind trick effect because for whatever reason this makes it work with skeletons. target.setAttackTarget(null); @@ -129,7 +129,9 @@ public class Intimidate extends Spell { Entity caster = WizardryUtilities.getEntityByUUID(creature.world, entityNBT.getUniqueId(NBT_KEY)); if(caster instanceof EntityLivingBase){ - runAway(creature, (EntityLivingBase)caster); + double distance = BASE_AVOID_DISTANCE + AVOID_DISTANCE_PER_LEVEL + * event.getEntityLiving().getActivePotionEffect(WizardryPotions.fear).getAmplifier(); + runAway(creature, (EntityLivingBase)caster, distance); } } } diff --git a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java index 425e7c3b..c6c473b8 100644 --- a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java +++ b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java @@ -1,12 +1,7 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -16,29 +11,34 @@ import net.minecraft.init.MobEffects; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumHand; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class InvigoratingPresence extends Spell { - - private static final double BASE_RANGE = 5; - private static final int BASE_DURATION = 900; public InvigoratingPresence(){ - super("invigorating_presence", Tier.APPRENTICE, Element.HEALING, SpellType.UTILITY, 30, 60, EnumAction.BOW, false); + super("invigorating_presence", EnumAction.BOW, false); + this.soundValues(0.7f, 1.2f, 0.4f); + addProperties(EFFECT_RADIUS, EFFECT_DURATION, EFFECT_STRENGTH); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ List targets = WizardryUtilities.getEntitiesWithinRadius( - BASE_RANGE * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world, - EntityPlayer.class); + getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade), + caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class); for(EntityPlayer target : targets){ - if(WizardryUtilities.isPlayerAlly(caster, target) || target == caster){ - // Strength 2 for 45 seconds. + if(AllyDesignationSystem.isPlayerAlly(caster, target) || target == caster){ + + int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)); + target.addPotionEffect(new PotionEffect(MobEffects.STRENGTH, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1, false, false)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier)); } } @@ -47,18 +47,18 @@ public class InvigoratingPresence extends Spell { for(int i = 0; i < 50 * modifiers.get(WizardryItems.blast_upgrade); i++){ double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade); - double angle = world.rand.nextDouble() * Math.PI * 2; + float angle = world.rand.nextFloat() * (float)Math.PI * 2;; - double x = caster.posX + radius * Math.cos(angle); + double x = caster.posX + radius * MathHelper.cos(angle); double y = caster.getEntityBoundingBox().minY; - double z = caster.posZ + radius * Math.sin(angle); + double z = caster.posZ + radius * MathHelper.sin(angle); ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50).clr(1, 0.2f, 0.2f).spawn(world); } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1 + 0.2f * world.rand.nextFloat()); + playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java index 71ce3368..e62718ac 100644 --- a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java +++ b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java @@ -1,25 +1,26 @@ package electroblob.wizardry.spell; -import java.util.Random; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; +import java.util.Random; + public class InvokeWeather extends Spell { + public static final String THUNDERSTORM_CHANCE = "thunderstorm_chance"; + public InvokeWeather(){ - super("invoke_weather", Tier.ADVANCED, Element.LIGHTNING, SpellType.UTILITY, 30, 100, EnumAction.BOW, false); + super("invoke_weather", EnumAction.BOW, false); + addProperties(THUNDERSTORM_CHANCE); + soundValues(0.5f, 1, 0); } @Override @@ -32,20 +33,21 @@ public class InvokeWeather extends Spell { int standardWeatherTime = (300 + (new Random()).nextInt(600)) * 20; if(world.isRaining()){ - caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".sun")); + caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".sun"), true); world.getWorldInfo().setCleanWeatherTime(standardWeatherTime); world.getWorldInfo().setRainTime(0); world.getWorldInfo().setThunderTime(0); world.getWorldInfo().setRaining(false); world.getWorldInfo().setThundering(false); }else{ - caster.sendMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".rain")); + caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".rain"), true); world.getWorldInfo().setCleanWeatherTime(0); world.getWorldInfo().setRainTime(standardWeatherTime); world.getWorldInfo().setThunderTime(standardWeatherTime); world.getWorldInfo().setRaining(true); - // 1/3 chance for a thunderstorm - world.getWorldInfo().setThundering(world.rand.nextInt(3) == 0); + // Thunderstorm is guaranteed if the caster has a bottled thundercloud charm equipped + world.getWorldInfo().setThundering(ItemArtefact.isArtefactActive(caster, WizardryItems.charm_storm) + || world.rand.nextFloat() < getProperty(THUNDERSTORM_CHANCE).floatValue()); } } @@ -58,7 +60,7 @@ public class InvokeWeather extends Spell { } } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_LIGHTNING_THUNDER, 0.5f, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Leap.java b/src/main/java/electroblob/wizardry/spell/Leap.java index 2bb1263b..16b69acc 100644 --- a/src/main/java/electroblob/wizardry/spell/Leap.java +++ b/src/main/java/electroblob/wizardry/spell/Leap.java @@ -1,12 +1,7 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; @@ -14,8 +9,13 @@ import net.minecraft.world.World; public class Leap extends Spell { + public static final String HORIZONTAL_SPEED = "horizontal_speed"; + public static final String VERTICAL_SPEED = "vertical_speed"; + public Leap(){ - super("leap", Tier.BASIC, Element.EARTH, SpellType.UTILITY, 10, 20, EnumAction.NONE, false); + super("leap", EnumAction.NONE, false); + addProperties(HORIZONTAL_SPEED, VERTICAL_SPEED); + soundValues(0.5f, 1, 0); } @Override @@ -23,19 +23,20 @@ public class Leap extends Spell { if(caster.onGround){ - caster.motionY = 0.65 * modifiers.get(SpellModifiers.POTENCY); - caster.addVelocity(caster.getLookVec().x * 0.3, 0, caster.getLookVec().z * 0.3); + caster.motionY = getProperty(VERTICAL_SPEED).floatValue() * modifiers.get(SpellModifiers.POTENCY); + double horizontalSpeed = getProperty(HORIZONTAL_SPEED).floatValue(); + caster.addVelocity(caster.getLookVec().x * horizontalSpeed, 0, caster.getLookVec().z * horizontalSpeed); if(world.isRemote){ for(int i = 0; i < 10; i++){ - double x = (double)(caster.posX + world.rand.nextFloat() - 0.5F); - double y = (double)(caster.getEntityBoundingBox().minY); - double z = (double)(caster.posZ + world.rand.nextFloat() - 0.5F); + double x = caster.posX + world.rand.nextFloat() - 0.5F; + double y = caster.getEntityBoundingBox().minY; + double z = caster.posZ + world.rand.nextFloat() - 0.5F; world.spawnParticle(EnumParticleTypes.CLOUD, x, y, z, 0, 0, 0); } } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERDRAGON_FLAP, 0.5F, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); caster.swingArm(hand); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Levitation.java b/src/main/java/electroblob/wizardry/spell/Levitation.java index 60e16ab8..f70e8f29 100644 --- a/src/main/java/electroblob/wizardry/spell/Levitation.java +++ b/src/main/java/electroblob/wizardry/spell/Levitation.java @@ -1,30 +1,49 @@ package electroblob.wizardry.spell; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.world.World; public class Levitation extends Spell { + public static final String SPEED = "speed"; + public static final String ACCELERATION = "acceleration"; + public Levitation(){ - super("levitation", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 10, 0, EnumAction.BOW, true); + super("levitation", EnumAction.BOW, true); + addProperties(SPEED, ACCELERATION); + soundValues(0.5f, 1, 0); + } + + @Override + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - caster.fallDistance = 0; + if(!Wizardry.settings.replaceVanillaFallDamage) caster.fallDistance = 0; - caster.motionY = caster.motionY < 0.5 ? caster.motionY + 0.1 : caster.motionY; + caster.motionY = caster.motionY < getProperty(SPEED).floatValue() ? caster.motionY + + getProperty(ACCELERATION).floatValue() : caster.motionY; if(world.isRemote){ double x = caster.posX - 0.25 + world.rand.nextDouble() * 0.5; @@ -32,9 +51,9 @@ public class Levitation extends Spell { double z = caster.posZ - 0.25 + world.rand.nextDouble() * 0.5; ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(0.5f, 1, 0.7f).spawn(world); } - if(ticksInUse % 24 == 0 && world.isRemote){ - Wizardry.proxy.playMovingSound(caster, WizardrySounds.SPELL_LOOP_SPARKLE, 0.5f, 1, false); - } + + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; } diff --git a/src/main/java/electroblob/wizardry/spell/LifeDrain.java b/src/main/java/electroblob/wizardry/spell/LifeDrain.java index b60109f9..a4cf6add 100644 --- a/src/main/java/electroblob/wizardry/spell/LifeDrain.java +++ b/src/main/java/electroblob/wizardry/spell/LifeDrain.java @@ -1,9 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -11,79 +7,67 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class LifeDrain extends SpellRay { - - private static final float BASE_DAMAGE = 2; - /** The fraction of the damage dealt that is transferred to the caster as healing. */ - private static final float HEAL_FACTOR = 0.35f; + + public static final String HEAL_FACTOR = "heal_factor"; public LifeDrain(){ - super("life_drain", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 10, 0, true, 10, null); + super("life_drain", true, EnumAction.NONE); this.particleVelocity(-0.5); this.particleSpacing(0.4); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // TODO: Temporary solution until I implement a better continuous sound system - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag){ - if(ticksInUse % 18 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SUMMONING, 1, 0.6f); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_CRACKLE, 2, 1); - } - } - return flag; + addProperties(DAMAGE, HEAL_FACTOR); + this.soundValues(0.6f, 1, 0); } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag){ - if(ticksInUse % 18 == 0){ - if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_SUMMONING, 1, 0.6f); - caster.playSound(WizardrySounds.SPELL_LOOP_CRACKLE, 2, 1); - } - } - return flag; + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ if(ticksInUse % 12 == 0){ - float damage = BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY); + float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY); WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.MAGIC), damage); - caster.heal(damage * HEAL_FACTOR); + if(caster != null) caster.heal(damage * getProperty(HEAL_FACTOR).floatValue()); } - - return true; } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Light.java b/src/main/java/electroblob/wizardry/spell/Light.java index 76b5fb9b..95571fb5 100644 --- a/src/main/java/electroblob/wizardry/spell/Light.java +++ b/src/main/java/electroblob/wizardry/spell/Light.java @@ -1,14 +1,11 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.item.ItemArtefact; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.tileentity.TileEntityTimer; +import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; @@ -19,18 +16,21 @@ import net.minecraft.world.World; public class Light extends Spell { public Light(){ - super("light", Tier.BASIC, Element.SORCERY, SpellType.UTILITY, 5, 15, EnumAction.NONE, false); + super("light", EnumAction.NONE, false); + addProperties(RANGE, DURATION); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - RayTraceResult rayTrace = WizardryUtilities.standardBlockRayTrace(world, caster, 4, false); + double range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + + RayTraceResult rayTrace = RayTracer.standardBlockRayTrace(world, caster, range, false); if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ @@ -41,20 +41,21 @@ public class Light extends Spell { if(!world.isRemote){ world.setBlockState(pos, WizardryBlocks.magic_light.getDefaultState()); if(world.getTileEntity(pos) instanceof TileEntityTimer){ - ((TileEntityTimer)world.getTileEntity(pos)) - .setLifetime((int)(600 * modifiers.get(WizardryItems.duration_upgrade))); + int lifetime = ItemArtefact.isArtefactActive(caster, WizardryItems.charm_light) ? -1 + : (int)(getProperty(DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)); + ((TileEntityTimer)world.getTileEntity(pos)).setLifetime(lifetime); } } caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } }else{ - int x = (int)(Math.floor(caster.posX) + caster.getLookVec().x * 4); - int y = (int)(Math.floor(caster.posY) + caster.eyeHeight + caster.getLookVec().y * 4); - int z = (int)(Math.floor(caster.posZ) + caster.getLookVec().z * 4); + int x = (int)(Math.floor(caster.posX) + caster.getLookVec().x * range); + int y = (int)(Math.floor(caster.posY) + caster.eyeHeight + caster.getLookVec().y * range); + int z = (int)(Math.floor(caster.posZ) + caster.getLookVec().z * range); BlockPos pos = new BlockPos(x, y, z); @@ -62,12 +63,13 @@ public class Light extends Spell { if(!world.isRemote){ world.setBlockState(pos, WizardryBlocks.magic_light.getDefaultState()); if(world.getTileEntity(pos) instanceof TileEntityTimer){ - ((TileEntityTimer)world.getTileEntity(pos)) - .setLifetime((int)(600 * modifiers.get(WizardryItems.duration_upgrade))); + int lifetime = ItemArtefact.isArtefactActive(caster, WizardryItems.charm_light) ? -1 + : (int)(getProperty(DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)); + ((TileEntityTimer)world.getTileEntity(pos)).setLifetime(lifetime); } } caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } } diff --git a/src/main/java/electroblob/wizardry/spell/LightningBolt.java b/src/main/java/electroblob/wizardry/spell/LightningBolt.java index 49c854d3..461cb126 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningBolt.java +++ b/src/main/java/electroblob/wizardry/spell/LightningBolt.java @@ -1,52 +1,51 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.effect.EntityLightningBolt; -import net.minecraft.entity.monster.EntityCreeper; -import net.minecraft.entity.passive.EntityPig; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import net.minecraftforge.event.entity.EntityStruckByLightningEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -@Mod.EventBusSubscriber +//@Mod.EventBusSubscriber public class LightningBolt extends SpellRay { /** The NBT key used to store the UUID of the player that summoned the lightning bolt. Used for achievements. */ public static final String NBT_KEY = "summoningPlayer"; public LightningBolt(){ - super("lightning_bolt", Tier.ADVANCED, Element.LIGHTNING, SpellType.ATTACK, 40, 80, false, 200, null); - this.ignoreEntities(true); + super("lightning_bolt", false, EnumAction.NONE); + this.ignoreLivingEntities(true); } - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(world.canBlockSeeSky(pos.up())){ if(!world.isRemote){ + // Temporarily disable the fire tick gamerule if player block damage is disabled + // Bit of a hack but it works fine! + boolean doFireTick = world.getGameRules().getBoolean("doFireTick"); + if(doFireTick && !Wizardry.settings.playerBlockDamage) world.getGameRules().setOrCreateGameRule("doFireTick", "false"); EntityLightningBolt entitylightning = new EntityLightningBolt(world, pos.getX(), pos.getY(), pos.getZ(), false); world.addWeatherEffect(entitylightning); + // Reset doFireTick to true if it was true before + if(doFireTick && !Wizardry.settings.playerBlockDamage) world.getGameRules().setOrCreateGameRule("doFireTick", "true"); // Code for eventhandler recognition for achievements if(caster instanceof EntityPlayer){ @@ -62,26 +61,26 @@ public class LightningBolt extends SpellRay { } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } - @SubscribeEvent - public static void onEntityStruckByLightningEvent(EntityStruckByLightningEvent event){ - - if(event.getLightning().getEntityData() != null && event.getLightning().getEntityData().hasUniqueId(NBT_KEY)){ - - EntityPlayer player = (EntityPlayer)WizardryUtilities.getEntityByUUID(event.getLightning().world, - event.getLightning().getEntityData().getUniqueId("summoningPlayer")); - - if(event.getEntity() instanceof EntityCreeper){ - WizardryAdvancementTriggers.charge_creeper.triggerFor(player); - } - - if(event.getEntity() instanceof EntityPig){ - WizardryAdvancementTriggers.frankenstein.triggerFor(player); - } - } - } +// @SubscribeEvent +// public static void onEntityStruckByLightningEvent(EntityStruckByLightningEvent event){ +// +// if(event.getLightning().getEntityData() != null && event.getLightning().getEntityData().hasUniqueId(NBT_KEY)){ +// +// EntityPlayer player = (EntityPlayer)WizardryUtilities.getEntityByUUID(event.getLightning().world, +// event.getLightning().getEntityData().getUniqueId("summoningPlayer")); +// +// if(event.getEntity() instanceof EntityCreeper){ +// WizardryAdvancementTriggers.charge_creeper.triggerFor(player); +// } +// +// if(event.getEntity() instanceof EntityPig){ +// WizardryAdvancementTriggers.frankenstein.triggerFor(player); +// } +// } +// } } diff --git a/src/main/java/electroblob/wizardry/spell/LightningHammer.java b/src/main/java/electroblob/wizardry/spell/LightningHammer.java index e31c283e..faa1354b 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningHammer.java +++ b/src/main/java/electroblob/wizardry/spell/LightningHammer.java @@ -1,33 +1,33 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityHammer; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class LightningHammer extends SpellConstructRanged { + public static final String ATTACK_INTERVAL = "attack_interval"; + public static final String SECONDARY_MAX_TARGETS = "secondary_max_targets"; + public LightningHammer(){ - super("lightning_hammer", Tier.MASTER, Element.LIGHTNING, SpellType.ATTACK, 100, 300, EntityHammer::new, 600, 40, WizardrySounds.SPELL_SUMMONING); + super("lightning_hammer", EntityHammer::new, false); this.soundValues(3, 1, 0); this.floor(true); this.overlap(true); + addProperties(EFFECT_RADIUS, SECONDARY_MAX_TARGETS, ATTACK_INTERVAL, DIRECT_DAMAGE, SPLASH_DAMAGE); } @Override - protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ - // TESTME: Does this need to be one block higher? + protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ if(!world.canBlockSeeSky(new BlockPos(x, y, z))) return false; - return super.spawnConstruct(world, x, y + 50, z, caster, modifiers); + return super.spawnConstruct(world, x, y + 50, z, side, caster, modifiers); } @Override - protected void addConstructExtras(EntityHammer construct, EntityLivingBase caster, SpellModifiers modifiers){ + protected void addConstructExtras(EntityHammer construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ construct.motionY = -2; } diff --git a/src/main/java/electroblob/wizardry/spell/LightningPulse.java b/src/main/java/electroblob/wizardry/spell/LightningPulse.java index 69c1543b..42b8037b 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningPulse.java +++ b/src/main/java/electroblob/wizardry/spell/LightningPulse.java @@ -1,56 +1,52 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.EnumAction; import net.minecraft.network.play.server.SPacketEntityVelocity; import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class LightningPulse extends Spell { - - private static final double BASE_RADIUS = 3; - private static final float BASE_DAMAGE = 8; + + public static final String REPULSION_VELOCITY = "repulsion_velocity"; public LightningPulse(){ - super("lightning_pulse", Tier.ADVANCED, Element.LIGHTNING, SpellType.ATTACK, 25, 75, EnumAction.NONE, false); - } - - @Override - public boolean doesSpellRequirePacket(){ - return false; + super("lightning_pulse", EnumAction.NONE, false); + addProperties(EFFECT_RADIUS, DAMAGE, REPULSION_VELOCITY); + this.soundValues(2, 1, 0); } // TODO: NPC casting support + @Override + protected SoundEvent[] createSounds(){ + return createSoundsWithSuffixes("spark", "explosion"); + } + @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(caster.onGround){ List targets = WizardryUtilities.getEntitiesWithinRadius( - BASE_RADIUS * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade), + caster.posX, caster.posY, caster.posZ, world); for(EntityLivingBase target : targets){ - if(WizardryUtilities.isValidTarget(caster, target)){ + if(AllyDesignationSystem.isValidTarget(caster, target)){ // Base damage is 4 hearts no matter where the target is. target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); if(!world.isRemote){ @@ -61,9 +57,9 @@ public class LightningPulse extends Spell { dx /= vectorLength; dz /= vectorLength; - target.motionX = 0.8 * dx; + target.motionX = getProperty(REPULSION_VELOCITY).floatValue() * dx; target.motionY = 0; - target.motionZ = 0.8 * dz; + target.motionZ = getProperty(REPULSION_VELOCITY).floatValue() * dz; // Player motion is handled on that player's client so needs packets if(target instanceof EntityPlayerMP){ @@ -80,8 +76,7 @@ public class LightningPulse extends Spell { } caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1, 1); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 2, 1); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } return false; diff --git a/src/main/java/electroblob/wizardry/spell/LightningRay.java b/src/main/java/electroblob/wizardry/spell/LightningRay.java index ce6ddd15..21bb5c0b 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningRay.java +++ b/src/main/java/electroblob/wizardry/spell/LightningRay.java @@ -1,9 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -11,100 +7,90 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class LightningRay extends SpellRay { - - private static final float BASE_DAMAGE = 3; public LightningRay(){ - super("lightning_ray", Tier.APPRENTICE, Element.LIGHTNING, SpellType.ATTACK, 5, 0, true, 10, null); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // TODO: Temporary solution until I implement a better continuous sound system - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag){ - if(ticksInUse == 1){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1, 1); - }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1, 1); - } - } - return flag; + super("lightning_ray", true, EnumAction.NONE); + this.aimAssist(0.6f); + addProperties(DAMAGE); } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag){ - if(ticksInUse == 1){ - caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1, 1); - }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - caster.playSound(WizardrySounds.SPELL_LOOP_LIGHTNING, 1, 1); - } - } - return flag; + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + if(WizardryUtilities.isLiving(target)){ if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); - }else{ + // This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle + // with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry. + }else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){ WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); } 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); - + // Particle effect for(int i=0; i<5; i++){ ParticleBuilder.create(Type.SPARK, target).spawn(world); } } - - return true; } - + + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ // This is a nice example of when onMiss is used for more than just returning a boolean if(world.isRemote && ticksInUse % 4 == 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 - Vec3d endpoint = origin.add(direction.scale(freeRange)); - - ParticleBuilder.create(Type.LIGHTNING).entity(caster) - .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(endpoint).spawn(world); + + // The arc does not reach full range when it has a free end + double freeRange = 0.8 * getRange(world, origin, direction, caster, ticksInUse, modifiers); + + if(caster != null){ + ParticleBuilder.create(Type.LIGHTNING).entity(caster).pos(origin.subtract(caster.getPositionVector())) + .length(freeRange).spawn(world); + }else{ + ParticleBuilder.create(Type.LIGHTNING).pos(origin).target(origin.add(direction.scale(freeRange))).spawn(world); + } } return true; diff --git a/src/main/java/electroblob/wizardry/spell/LightningWeb.java b/src/main/java/electroblob/wizardry/spell/LightningWeb.java index cdc11ea2..759ea581 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningWeb.java +++ b/src/main/java/electroblob/wizardry/spell/LightningWeb.java @@ -1,146 +1,138 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -public class LightningWeb extends SpellRay { - - private static final float PRIMARY_DAMAGE = 5; - private static final float SECONDARY_DAMAGE = 4; - private static final float TERTIARY_DAMAGE = 3; +import java.util.List; - private static final double PRIMARY_RANGE = 10; - private static final double SECONDARY_RANGE = 5; - private static final double TERTIARY_RANGE = 5; - - private static final int SECONDARY_MAX_TARGETS = 5; - private static final int TERTIARY_MAX_TARGETS = 2; // This is per secondary target, giving 10 in total +public class LightningWeb extends SpellRay { + + public static final String PRIMARY_DAMAGE = "primary_damage"; + public static final String SECONDARY_DAMAGE = "secondary_damage"; + public static final String TERTIARY_DAMAGE = "tertiary_damage"; + + public static final String SECONDARY_RANGE = "secondary_range"; + public static final String TERTIARY_RANGE = "tertiary_range"; + + public static final String SECONDARY_MAX_TARGETS = "secondary_max_targets"; + public static final String TERTIARY_MAX_TARGETS = "tertiary_max_targets"; // This is per secondary target public LightningWeb(){ - super("lightning_web", Tier.MASTER, Element.LIGHTNING, SpellType.ATTACK, 15, 0, true, PRIMARY_RANGE, null); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // TODO: Temporary solution until I implement a better continuous sound system - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag){ - if(ticksInUse == 1){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LIGHTNING, 1, 1); - }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_LIGHTNING, 1, 1); - } - } - return flag; + super("lightning_web", true, EnumAction.NONE); + this.aimAssist(0.6f); + addProperties(PRIMARY_DAMAGE, SECONDARY_DAMAGE, TERTIARY_DAMAGE, SECONDARY_RANGE, TERTIARY_RANGE, + SECONDARY_MAX_TARGETS, TERTIARY_MAX_TARGETS); } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag){ - if(ticksInUse == 1){ - caster.playSound(WizardrySounds.SPELL_LIGHTNING, 1, 1); - }else if(ticksInUse > 0 && ticksInUse % 20 == 0){ - caster.playSound(WizardrySounds.SPELL_LOOP_LIGHTNING, 1, 1); - } - } - return flag; + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ - - electrocute(world, caster, caster, target, PRIMARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY), ticksInUse); + + electrocute(world, caster, origin, target, getProperty(PRIMARY_DAMAGE).floatValue() + * modifiers.get(SpellModifiers.POTENCY), ticksInUse); // Secondary chaining effect - List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(SECONDARY_RANGE, - target.posX, target.posY + target.height / 2, target.posZ, world); + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius( + getProperty(SECONDARY_RANGE).floatValue(), target.posX, target.posY + target.height / 2, + target.posZ, world); secondaryTargets.remove(target); secondaryTargets.removeIf(e -> !WizardryUtilities.isLiving(e)); - secondaryTargets.removeIf(e -> !WizardryUtilities.isValidTarget(caster, e)); - if(secondaryTargets.size() > SECONDARY_MAX_TARGETS) secondaryTargets = secondaryTargets.subList(0, SECONDARY_MAX_TARGETS); + secondaryTargets.removeIf(e -> !AllyDesignationSystem.isValidTarget(caster, e)); + if(secondaryTargets.size() > getProperty(SECONDARY_MAX_TARGETS).intValue()) + secondaryTargets = secondaryTargets.subList(0, getProperty(SECONDARY_MAX_TARGETS).intValue()); for(EntityLivingBase secondaryTarget : secondaryTargets){ - electrocute(world, caster, target, secondaryTarget, - SECONDARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY), ticksInUse); + electrocute(world, caster, target.getPositionVector().add(0, target.height/2, 0), secondaryTarget, + getProperty(SECONDARY_DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY), ticksInUse); // Tertiary chaining effect - List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(TERTIARY_RANGE, - secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, - secondaryTarget.posZ, world); + List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius( + getProperty(TERTIARY_RANGE).floatValue(), secondaryTarget.posX, + secondaryTarget.posY + secondaryTarget.height / 2, secondaryTarget.posZ, world); tertiaryTargets.remove(target); tertiaryTargets.removeAll(secondaryTargets); tertiaryTargets.removeIf(e -> !WizardryUtilities.isLiving(e)); - tertiaryTargets.removeIf(e -> !WizardryUtilities.isValidTarget(caster, e)); - if(tertiaryTargets.size() > TERTIARY_MAX_TARGETS) tertiaryTargets = tertiaryTargets.subList(0, TERTIARY_MAX_TARGETS); + tertiaryTargets.removeIf(e -> !AllyDesignationSystem.isValidTarget(caster, e)); + if(tertiaryTargets.size() > getProperty(TERTIARY_MAX_TARGETS).intValue()) + tertiaryTargets = tertiaryTargets.subList(0, getProperty(TERTIARY_MAX_TARGETS).intValue()); for(EntityLivingBase tertiaryTarget : tertiaryTargets){ - electrocute(world, caster, secondaryTarget, tertiaryTarget, - TERTIARY_DAMAGE * modifiers.get(SpellModifiers.POTENCY), ticksInUse); + electrocute(world, caster, secondaryTarget.getPositionVector().add(0, secondaryTarget.height/2, 0), + tertiaryTarget, getProperty(TERTIARY_DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY), ticksInUse); } } } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ // This is a nice example of when onMiss is used for more than just returning a boolean if(world.isRemote){ - - if(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){ - ParticleBuilder.create(Type.LIGHTNING).entity(caster) - .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(endpoint).spawn(world); - + // The arc does not reach full range when it has a free end + double freeRange = 0.8 * getRange(world, origin, direction, caster, ticksInUse, modifiers); + + if(caster != null){ + ParticleBuilder.create(Type.BEAM).entity(caster).pos(origin.subtract(caster.getPositionVector())) + .length(freeRange).clr(0.2f, 0.6f, 1).spawn(world); + }else{ + ParticleBuilder.create(Type.BEAM).pos(origin).target(origin.add(direction.scale(freeRange))) + .clr(0.2f, 0.6f, 1).spawn(world); + } + + if(ticksInUse % 4 == 0){ + if(caster != null){ + ParticleBuilder.create(Type.LIGHTNING).entity(caster).pos(origin.subtract(caster.getPositionVector())) + .length(freeRange).spawn(world); + }else{ + ParticleBuilder.create(Type.LIGHTNING).pos(origin).target(origin.add(direction.scale(freeRange))).spawn(world); + } } } return true; } - private void electrocute(World world, Entity caster, Entity origin, Entity target, float damage, int ticksInUse){ + private void electrocute(World world, Entity caster, Vec3d origin, Entity target, float damage, int ticksInUse){ if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) diff --git a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java index 174e28ef..77f4fbee 100644 --- a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java +++ b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java @@ -2,35 +2,18 @@ package electroblob.wizardry.spell; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.EntitySkeletonMinion; -import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.entity.living.*; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.monster.EntityCaveSpider; -import net.minecraft.entity.monster.EntityHusk; -import net.minecraft.entity.monster.EntityMagmaCube; -import net.minecraft.entity.monster.EntityPigZombie; -import net.minecraft.entity.monster.EntitySkeleton; -import net.minecraft.entity.monster.EntitySlime; -import net.minecraft.entity.monster.EntitySpider; -import net.minecraft.entity.monster.EntityStray; -import net.minecraft.entity.monster.EntityWitherSkeleton; -import net.minecraft.entity.monster.EntityZombie; -import net.minecraft.entity.passive.EntityBat; -import net.minecraft.entity.passive.EntityChicken; -import net.minecraft.entity.passive.EntityCow; -import net.minecraft.entity.passive.EntityMooshroom; -import net.minecraft.entity.passive.EntityPig; +import net.minecraft.entity.monster.*; +import net.minecraft.entity.passive.*; +import net.minecraft.item.EnumAction; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; @@ -46,10 +29,11 @@ public class Metamorphosis extends SpellRay { addTransformation(EntityCow.class, EntityMooshroom.class); addTransformation(EntityChicken.class, EntityBat.class); addTransformation(EntityZombie.class, EntityHusk.class); - addTransformation(EntitySkeleton.class, EntityWitherSkeleton.class, EntityStray.class); + addTransformation(EntitySkeleton.class, EntityStray.class, EntityWitherSkeleton.class); addTransformation(EntitySpider.class, EntityCaveSpider.class); addTransformation(EntitySlime.class, EntityMagmaCube.class); - addTransformation(EntitySkeletonMinion.class, EntityWitherSkeletonMinion.class); + addTransformation(EntityZombieMinion.class, EntityHuskMinion.class); + addTransformation(EntitySkeletonMinion.class, EntityStrayMinion.class, EntityWitherSkeletonMinion.class); } /** Adds circular mappings between the given entity classes to the transformations map. In other words, given an @@ -64,23 +48,24 @@ public class Metamorphosis extends SpellRay { } public Metamorphosis(){ - super("metamorphosis", Tier.APPRENTICE, Element.NECROMANCY, SpellType.UTILITY, 15, 30, false, 10, WizardrySounds.SPELL_DEFLECTION); - this.soundValues(0.5f, 0.8f, 0); + super("metamorphosis", false, EnumAction.NONE); + this.soundValues(0.5f, 1f, 0); } @Override public boolean canBeCastByNPCs() { return false; } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + if(WizardryUtilities.isLiving(target)){ - + double xPos = target.posX; double yPos = target.posY; double zPos = target.posZ; // Sneaking allows the entities to be cycled through in the other direction. - Class newEntityClass = caster.isSneaking() ? + // Dispensers always cycle through entities in the normal direction. + Class newEntityClass = caster != null && caster.isSneaking() ? TRANSFORMATIONS.inverse().get(target.getClass()) : TRANSFORMATIONS.get(target.getClass()); if(newEntityClass == null) return false; @@ -103,7 +88,7 @@ public class Metamorphosis extends SpellRay { NBTTagCompound tag = new NBTTagCompound(); target.writeToNBT(tag); // Remove the UUID because keeping it the same causes the entity to disappear - WizardryUtilities.removeUniqueId(tag, "UUID"); + NBTExtras.removeUniqueId(tag, "UUID"); newEntity.readFromNBT(tag); target.setDead(); @@ -111,22 +96,27 @@ public class Metamorphosis extends SpellRay { world.spawnEntity(newEntity); }else{ - for(int i=0; i<5; i++){ - ParticleBuilder.create(Type.DARK_MAGIC).pos(xPos, yPos, zPos).clr(0.1f, 0, 0).spawn(world); + for(int i=0; i<20; i++){ + ParticleBuilder.create(Type.DARK_MAGIC, world.rand, xPos, yPos + 1, zPos, 1, false) + .clr(0.1f, 0, 0).spawn(world); } + ParticleBuilder.create(Type.BUFF).pos(xPos, yPos, zPos).clr(0xd363cb).spawn(world); } + + this.playSound(world, (EntityLivingBase)target, ticksInUse, -1, modifiers); + return true; } return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Meteor.java b/src/main/java/electroblob/wizardry/spell/Meteor.java index e309762e..a89f1173 100644 --- a/src/main/java/electroblob/wizardry/spell/Meteor.java +++ b/src/main/java/electroblob/wizardry/spell/Meteor.java @@ -1,41 +1,44 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.EntityMeteor; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Meteor extends SpellRay { + // It doesn't really make sense to have a blast radius when the explosion is measured by strength + public static final String BLAST_STRENGTH = "blast_strength"; + public Meteor(){ - super("meteor", Tier.MASTER, Element.FIRE, SpellType.ATTACK, 100, 200, false, 40, WizardrySounds.SPELL_SUMMONING); + super("meteor", false, EnumAction.NONE); this.soundValues(3, 1, 0); - this.ignoreEntities(true); + this.ignoreLivingEntities(true); + addProperties(BLAST_STRENGTH); } - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(world.canBlockSeeSky(pos.up())){ if(!world.isRemote){ EntityMeteor meteor = new EntityMeteor(world, pos.getX(), pos.getY() + 50, pos.getZ(), - modifiers.get(WizardryItems.blast_upgrade)); + modifiers.get(WizardryItems.blast_upgrade), WizardryUtilities.canDamageBlocks(caster, world)); world.spawnEntity(meteor); } @@ -46,7 +49,7 @@ public class Meteor extends SpellRay { } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/MindControl.java b/src/main/java/electroblob/wizardry/spell/MindControl.java index a472cf92..caa03f9d 100644 --- a/src/main/java/electroblob/wizardry/spell/MindControl.java +++ b/src/main/java/electroblob/wizardry/spell/MindControl.java @@ -1,31 +1,27 @@ package electroblob.wizardry.spell; -import java.util.Arrays; -import java.util.List; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntityEvilWizard; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityList; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.INpc; -import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.*; import net.minecraft.entity.item.EntityArmorStand; +import net.minecraft.entity.passive.EntitySheep; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; +import net.minecraft.item.EnumDyeColor; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; @@ -33,45 +29,57 @@ import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.util.Arrays; +import java.util.List; + @Mod.EventBusSubscriber public class MindControl extends SpellRay { /** The NBT tag name for storing the controlling entity's UUID in the target's tag compound. */ public static final String NBT_KEY = "controllingEntity"; - - private static final int BASE_DURATION = 600; public MindControl(){ - super("mind_control", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 40, 150, false, 8, WizardrySounds.SPELL_SUMMONING); + super("mind_control", false, EnumAction.NONE); + addProperties(EFFECT_DURATION); } + @Override public boolean canBeCastByNPCs() { return false; } + @Override public boolean canBeCastByDispensers() { return false; } + @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ - - if(!world.isRemote){ - if(!canControl(target)){ - // Adds a message saying that the player/boss entity/wizard resisted mind control - ((EntityPlayer)caster).sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), - this.getNameForTranslationFormatted()), true); - - }else if(target instanceof EntityLiving){ - + if(!canControl(target)){ + if(!world.isRemote){ + if(caster instanceof EntityPlayer){ + // Adds a message saying that the player/boss entity/wizard resisted mind control + ((EntityPlayer)caster).sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); + } + } + + }else if(target instanceof EntityLiving){ + + if(!world.isRemote){ if(!MindControl.findMindControlTarget((EntityLiving)target, caster, world)){ // If no valid target was found, this just acts like mind trick. ((EntityLiving)target).setAttackTarget(null); } - - NBTTagCompound entityNBT = target.getEntityData(); - if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID()); - - ((EntityLiving)target).addPotionEffect(new PotionEffect(WizardryPotions.mind_control, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); } - - }else{ + + if(target instanceof EntitySheep && ((EntitySheep)target).getFleeceColor() == EnumDyeColor.BLUE + && WizardryUtilities.canDamageBlocks(caster, world)){ + if(!world.isRemote) ((EntitySheep)target).setFleeceColor(EnumDyeColor.RED); // Wololo! + world.playSound(caster.posX, caster.posY, caster.posZ, SoundEvents.EVOCATION_ILLAGER_PREPARE_WOLOLO, WizardrySounds.SPELLS, 1, 1, false); + } + + if(!world.isRemote) startControlling((EntityLiving)target, caster, + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); + } + + if(world.isRemote){ for(int i=0; i<10; i++){ ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, @@ -90,12 +98,12 @@ public class MindControl extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } @@ -106,6 +114,11 @@ public class MindControl extends SpellRay { .contains(EntityList.getKey(target.getClass())); } + public static void startControlling(EntityLiving target, EntityLivingBase controller, int duration){ + target.getEntityData().setUniqueId(NBT_KEY, controller.getUniqueID()); + target.addPotionEffect(new PotionEffect(WizardryPotions.mind_control, duration, 0)); + } + /** * Finds the nearest creature to the given target which it is allowed to attack according to the given caster and * sets it as the target's attack target. Handles both new and old AI and takes follow range into account. Defined @@ -122,7 +135,7 @@ public class MindControl extends SpellRay { // no longer lasts until the creature dies; instead it is a potion effect which continues to // set the target until it wears off. List possibleTargets = WizardryUtilities.getEntitiesWithinRadius( - ((EntityLiving)target).getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).getAttributeValue(), + target.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).getAttributeValue(), target.posX, target.posY, target.posZ, world); possibleTargets.remove(target); @@ -131,7 +144,7 @@ public class MindControl extends SpellRay { EntityLivingBase newAITarget = null; for(EntityLivingBase possibleTarget : possibleTargets){ - if(WizardryUtilities.isValidTarget(caster, possibleTarget) && (newAITarget == null + if(AllyDesignationSystem.isValidTarget(caster, possibleTarget) && (newAITarget == null || target.getDistance(possibleTarget) < target.getDistance(newAITarget))){ newAITarget = possibleTarget; } @@ -140,7 +153,7 @@ public class MindControl extends SpellRay { if(newAITarget != null){ // From 1.7.10 - this seems not to work quite right; the entity appears to continue attacking this target // after it gets killed (not noticeable in survival since it will target the player again immediately.) - ((EntityLiving)target).setAttackTarget(newAITarget); + target.setAttackTarget(newAITarget); return true; } @@ -163,7 +176,7 @@ public class MindControl extends SpellRay { if(caster instanceof EntityLivingBase){ // If the current target is already a valid mind control target, nothing happens. - if(WizardryUtilities.isValidTarget(caster, currentTarget)) return; + if(AllyDesignationSystem.isValidTarget(caster, currentTarget)) return; if(MindControl.findMindControlTarget(entity, (EntityLivingBase)caster, world)){ // If it worked, skip setting the target to null. diff --git a/src/main/java/electroblob/wizardry/spell/MindTrick.java b/src/main/java/electroblob/wizardry/spell/MindTrick.java index 739d585f..7aeb5cde 100644 --- a/src/main/java/electroblob/wizardry/spell/MindTrick.java +++ b/src/main/java/electroblob/wizardry/spell/MindTrick.java @@ -1,11 +1,7 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -15,9 +11,11 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; @@ -26,16 +24,15 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber public class MindTrick extends SpellRay { - - private static final int BASE_DURATION = 300; public MindTrick(){ - super("mind_trick", Tier.BASIC, Element.NECROMANCY, SpellType.ATTACK, 10, 40, false, 8, WizardrySounds.SPELL_DEFLECTION); + super("mind_trick", false, EnumAction.NONE); this.soundValues(0.7f, 1, 0.4f); + addProperties(EFFECT_DURATION); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ @@ -44,13 +41,13 @@ public class MindTrick extends SpellRay { if(target instanceof EntityPlayer){ ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.NAUSEA, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), 0)); }else if(target instanceof EntityLiving){ ((EntityLiving)target).setAttackTarget(null); ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 0)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), 0)); } }else{ @@ -68,12 +65,12 @@ public class MindTrick extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Mine.java b/src/main/java/electroblob/wizardry/spell/Mine.java new file mode 100644 index 00000000..30389fb9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Mine.java @@ -0,0 +1,157 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.event.ForgeEventFactory; + +import java.util.List; + +public class Mine extends SpellRay { + + public Mine(){ + super("mine", false, EnumAction.NONE); + this.ignoreLivingEntities(true); + this.particleSpacing(0.5); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + // Needs to be outside because it gets run on the client-side + if(caster instanceof EntityPlayer){ + if(caster.getHeldItemMainhand().getItem() instanceof ISpellCastingItem){ + caster.swingArm(EnumHand.MAIN_HAND); + }else if(caster.getHeldItemOffhand().getItem() instanceof ISpellCastingItem){ + caster.swingArm(EnumHand.OFF_HAND); + } + } + + if(!world.isRemote){ + + if(WizardryUtilities.isBlockUnbreakable(world, pos)) return false; + // The mine spell ignores the block damage setting for players, since that's the entire point of the spell + // Instead, it triggers block break events at the appropriate points, which protection mods should be able to + // pick up and allow/disallow accordingly + // For the time being, dispensers respect the mobGriefing gamerule + if(!(caster instanceof EntityPlayer) && !WizardryUtilities.canDamageBlocks(caster, world)) return false; + // Can't mine arcane-locked blocks + if(world.getTileEntity(pos) != null && world.getTileEntity(pos).getTileData().hasUniqueId(ArcaneLock.NBT_KEY)) return false; + + IBlockState state = world.getBlockState(pos); + // The maximum harvest level as determined by the potency multiplier. The + 0.5f is so that + // weird float processing doesn't incorrectly round it down. + int harvestLevel = (int)((modifiers.get(SpellModifiers.POTENCY) - 1) / Constants.POTENCY_INCREASE_PER_TIER + 0.5f); + + if(harvestLevel > 0) harvestLevel--; // Shifts them all down one since normally novice wands give some potency + + // The >= 3 is to allow master earth wands to break anything. + if(state.getBlock().getHarvestLevel(state) <= harvestLevel || harvestLevel >= 3){ + + boolean flag = false; + + int blastUpgradeCount = (int)((modifiers.get(WizardryItems.blast_upgrade) - 1) / Constants.RANGE_INCREASE_PER_LEVEL + 0.5f); + // Results in the following patterns: + // 0 blast upgrades: single block + // 1 blast upgrade: 3x3 without corners or edges + // 2 blast upgrades: 3x3 with corners + // 3 blast upgrades: 5x5 without corners or edges + float radius = 0.5f + 0.73f * blastUpgradeCount; + + List sphere = WizardryUtilities.getBlockSphere(pos, radius); + + for(BlockPos pos1 : sphere){ + + if(WizardryUtilities.isBlockUnbreakable(world, pos1)) continue; + + IBlockState state1 = world.getBlockState(pos1); + + if(state1.getBlock().getHarvestLevel(state1) <= harvestLevel || harvestLevel >= 3){ + + if(caster instanceof EntityPlayerMP){ // Everything in here is server-side only so this is fine + + boolean silkTouch = state1.getBlock().canSilkHarvest(world, pos1, state1, (EntityPlayer)caster) + && ItemArtefact.isArtefactActive((EntityPlayer)caster, WizardryItems.charm_silk_touch); + + // Some protection mods seem to use this event instead so let's trigger it to check + if(ForgeEventFactory.getBreakSpeed((EntityPlayer)caster, state1, 1, pos1) <= 0) continue; + + int xp = ForgeHooks.onBlockBreakEvent(world, + ((EntityPlayerMP)caster).interactionManager.getGameType(), (EntityPlayerMP)caster, pos1); + + if(xp == -1) continue; // Event was cancelled + + if(silkTouch){ + flag = world.destroyBlock(pos1, false); + if(flag) Block.spawnAsEntity(world, pos1, getSilkTouchDrop(state1)); + }else{ + flag = world.destroyBlock(pos1, true); + if(flag) state1.getBlock().dropXpOnBlockBreak(world, pos1, xp); + } + + }else{ + // NPCs can dig the block under the target's feet + flag = world.destroyBlock(pos1, true) || flag; + } + } + } + + return flag; + } + }else{ + return true; + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.DUST).pos(x, y, z).time(20 + world.rand.nextInt(5)).clr(0.9f, 0.95f, 1) + .shaded(false).spawn(world); + } + + // Copied from Block, where (for some reason) it's protected + private static ItemStack getSilkTouchDrop(IBlockState state){ + + Item item = Item.getItemFromBlock(state.getBlock()); + int i = 0; + + if(item.getHasSubtypes()){ + i = state.getBlock().getMetaFromState(state); + } + + return new ItemStack(item, 1, i); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/None.java b/src/main/java/electroblob/wizardry/spell/None.java index 95e82045..c627002d 100644 --- a/src/main/java/electroblob/wizardry/spell/None.java +++ b/src/main/java/electroblob/wizardry/spell/None.java @@ -1,8 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; @@ -17,11 +14,11 @@ import net.minecraft.world.World; public class None extends Spell { public None(){ - super("none", Tier.BASIC, Element.MAGIC, SpellType.UTILITY, 0, 0, EnumAction.NONE, false); + super("none", EnumAction.NONE, false); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Paralysis.java b/src/main/java/electroblob/wizardry/spell/Paralysis.java new file mode 100644 index 00000000..795a884a --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Paralysis.java @@ -0,0 +1,123 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +@Mod.EventBusSubscriber +public class Paralysis extends SpellRay { + + /** Creatures with this much health or less will snap out of paralysis - but only when they take damage, so a + * creature on critical health may still be paralysed, but if it takes any damage at all the paralysis effect + * will end. */ + private static final String CRITICAL_HEALTH = "critical_health"; + + public Paralysis(){ + super("paralysis", false, EnumAction.NONE); + addProperties(DAMAGE, EFFECT_DURATION, CRITICAL_HEALTH); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + if(world.isRemote){ + // Rather neatly, the entity can be set here and if it's null nothing will happen. + ParticleBuilder.create(Type.BEAM).entity(caster).clr(0.2f, 0.6f, 1) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world); + ParticleBuilder.create(Type.LIGHTNING).entity(caster) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world); + } + + // This is a lot neater than it was, thanks to the damage type system. + if(MagicDamage.isEntityImmune(DamageType.SHOCK, target)){ + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", + target.getName(), this.getNameForTranslationFormatted()), true); + }else{ + target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + } + + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.paralysis, + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), 0)); + } + + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(world.isRemote){ + + if(world.getBlockState(pos).getMaterial().isSolid()){ + Vec3d vec = hit.add(new Vec3d(side.getDirectionVec()).scale(WizardryUtilities.ANTI_Z_FIGHTING_OFFSET)); + ParticleBuilder.create(Type.SCORCH).pos(vec).face(side).clr(0.4f, 0.8f, 1).spawn(world); + } + } + + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + // This is first because we want the endpoint to be unaffected by the offset + Vec3d endpoint = origin.add(direction.scale(getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade))); + + if(world.isRemote){ + ParticleBuilder.create(Type.LIGHTNING).time(4).pos(origin).target(endpoint).scale(0.5f).spawn(world); + ParticleBuilder.create(Type.BEAM).clr(0.2f, 0.6f, 1).time(4).pos(origin) + .target(endpoint).spawn(world); + } + + return true; + } + + // See WizardryClientEventHandler for prevention of players' movement under the effects of paralysis + + // TODO: (Animated?) screen overlay effect for paralysed players in first-person + + @SubscribeEvent + public static void onLivingUpdateEvent(LivingUpdateEvent event){ + // Disables entities' AI when under the effects of paralysis and re-enables it on the last update of the effect + // - this can't be in the potion class because it requires access to the duration and hence the actual + // PotionEffect instance + if(event.getEntity() instanceof EntityLiving && event.getEntityLiving().isPotionActive(WizardryPotions.paralysis)){ + int timeLeft = event.getEntityLiving().getActivePotionEffect(WizardryPotions.paralysis).getDuration(); + ((EntityLiving)event.getEntity()).setNoAI(timeLeft > 1); + } + } + + @SubscribeEvent + public static void onLivingHurtEvent(LivingHurtEvent event){ + // Paralysed creatures snap out of paralysis when they take critical damage + if(event.getEntityLiving().isPotionActive(WizardryPotions.paralysis) && event.getEntityLiving().getHealth() + - event.getAmount() <= Spells.paralysis.getProperty(CRITICAL_HEALTH).floatValue()){ + event.getEntityLiving().removePotionEffect(WizardryPotions.paralysis); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Petrify.java b/src/main/java/electroblob/wizardry/spell/Petrify.java index 757d9f29..de5e6d4b 100644 --- a/src/main/java/electroblob/wizardry/spell/Petrify.java +++ b/src/main/java/electroblob/wizardry/spell/Petrify.java @@ -1,9 +1,6 @@ package electroblob.wizardry.spell; import electroblob.wizardry.block.BlockStatue; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.ParticleBuilder; @@ -12,42 +9,43 @@ import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Petrify extends SpellRay { - private static final int BASE_DURATION = 900; + // This is more descriptive and more accurate than the standard "effect_duration" in this case + public static final String MINIMUM_EFFECT_DURATION = "minimum_effect_duration"; public Petrify(){ - super("petrify", Tier.ADVANCED, Element.SORCERY, SpellType.ATTACK, 40, 100, false, 10, SoundEvents.ENTITY_WITHER_SPAWN); + super("petrify", false, EnumAction.NONE); this.soundValues(1, 1.1f, 0.2f); + addProperties(MINIMUM_EFFECT_DURATION); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(target instanceof EntityLiving && !world.isRemote){ // Unchecked cast is fine because the block is a static final field if(((BlockStatue)WizardryBlocks.petrified_stone).convertToStatue((EntityLiving)target, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)))){ - - return true; + (int)(getProperty(MINIMUM_EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)))){ } } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/PhaseStep.java b/src/main/java/electroblob/wizardry/spell/PhaseStep.java index 05f9a9f1..18926341 100644 --- a/src/main/java/electroblob/wizardry/spell/PhaseStep.java +++ b/src/main/java/electroblob/wizardry/spell/PhaseStep.java @@ -2,73 +2,39 @@ package electroblob.wizardry.spell; import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class PhaseStep extends Spell { + public static final String WALL_THICKNESS = "wall_thickness"; + public PhaseStep(){ - super("phase_step", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 35, 40, EnumAction.NONE, false); + super("phase_step", EnumAction.NONE, false); + addProperties(RANGE, WALL_THICKNESS); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // Phase step does not gain range from range multiplier, instead it increases the thickness - // of the wall you can teleport through. - RayTraceResult rayTrace = WizardryUtilities.standardBlockRayTrace(world, caster, 5, false); - - if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ - - BlockPos pos = new BlockPos(rayTrace.getBlockPos().getX(), (int)caster.posY, rayTrace.getBlockPos().getZ()); - - // The maximum wall thickness as determined by the range multiplier. The + 0.5f is so that - // weird float processing doesn't incorrectly round it down. - int maxThickness = 1 + (int)((modifiers.get(WizardryItems.range_upgrade) - 1) / Constants.RANGE_INCREASE_PER_LEVEL + 0.5f); - - if(rayTrace.sideHit.getAxis().isHorizontal()){ - - // i represents how far the player needs to teleport to get through the wall - for(int i = 0; i <= maxThickness; i++){ - - BlockPos pos1 = pos.offset(rayTrace.sideHit.getOpposite(), i); - - // Prevents the player from teleporting through unbreakable blocks, so they cannot cheat in other - // mods' mazes and dungeons. - if((WizardryUtilities.isBlockUnbreakable(world, pos1) || WizardryUtilities.isBlockUnbreakable(world, pos1.up())) - && !Wizardry.settings.teleportThroughUnbreakableBlocks) - return false; - - if(!world.getBlockState(pos1).getMaterial().blocksMovement() - && !world.getBlockState(pos1.up()).getMaterial().blocksMovement()){ - - if(!world.isRemote){ - caster.setPositionAndUpdate(pos1.getX() + 0.5, caster.posY, pos1.getZ() + 0.5); - } - - caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERMEN_TELEPORT, 1.0F, 1.0f); - return true; - } - } - } - } + double range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + RayTraceResult rayTrace = RayTracer.standardBlockRayTrace(world, caster, range, false); // This is here because the conditions are false on the client for whatever reason. (see the Javadoc for cast() // for an explanation) if(world.isRemote){ + for(int i = 0; i < 10; i++){ double dx1 = caster.posX; double dy1 = caster.getEntityBoundingBox().minY + 2 * world.rand.nextFloat(); @@ -76,12 +42,94 @@ public class PhaseStep extends Spell { world.spawnParticle(EnumParticleTypes.PORTAL, dx1, dy1, dz1, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5); } - + // Can't be bothered to route this through the proxies! electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); } - return false; + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ + + BlockPos pos = rayTrace.getBlockPos(); + + // The maximum wall thickness as determined by the range multiplier. The + 0.5f is so that + // weird float processing doesn't incorrectly round it down. + int maxThickness = getProperty(WALL_THICKNESS).intValue() + + (int)((modifiers.get(WizardryItems.range_upgrade) - 1) / Constants.RANGE_INCREASE_PER_LEVEL + 0.5f); + + if(rayTrace.sideHit == EnumFacing.UP) maxThickness++; // Allow space for the player's head + + // i represents how far the player needs to teleport to get through the wall + for(int i = 0; i <= maxThickness; i++){ + + BlockPos pos1 = pos.offset(rayTrace.sideHit.getOpposite(), i); + + // Prevents the player from teleporting through unbreakable blocks, so they cannot cheat in other + // mods' mazes and dungeons. + if((WizardryUtilities.isBlockUnbreakable(world, pos1) || WizardryUtilities.isBlockUnbreakable(world, pos1.up())) + && !Wizardry.settings.teleportThroughUnbreakableBlocks) + break; // Don't return false yet, there are other possible outcomes below now + + if(!world.getBlockState(pos1).getMaterial().blocksMovement() + && !world.getBlockState(pos1.up()).getMaterial().blocksMovement()){ + + // Plays before and after so it is heard from both positions + this.playSound(world, caster, ticksInUse, -1, modifiers); + + if(!world.isRemote){ + caster.setPositionAndUpdate(pos1.getX() + 0.5, pos1.getY() + 0.5, pos1.getZ() + 0.5); + } + + caster.swingArm(hand); + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; + } + } + + // If no suitable position was found on the other side of the wall, works like blink instead + + // Leave space for the player's head + if(rayTrace.sideHit == EnumFacing.DOWN) pos = pos.down(); + + // This means stuff like snow layers is ignored, meaning when on snow-covered ground the player does + // not teleport 1 block above the ground. + if(rayTrace.sideHit == EnumFacing.UP && !world.getBlockState(pos).getMaterial().blocksMovement()){ + pos = pos.down(); + } + + pos = pos.offset(rayTrace.sideHit); + + // Prevents the player from teleporting into blocks and suffocating + if(world.getBlockState(pos).getMaterial().blocksMovement() + || world.getBlockState(pos.up()).getMaterial().blocksMovement()){ + return false; + } + + // Plays before and after so it is heard from both positions + this.playSound(world, caster, ticksInUse, -1, modifiers); + + if(!world.isRemote) caster.setPositionAndUpdate(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + + this.playSound(world, caster, ticksInUse, -1, modifiers); + caster.swingArm(hand); + return true; + + }else{ // The ray trace missed + + Vec3d destination = caster.getPositionVector().add(caster.getLookVec().scale(range)); + BlockPos pos = new BlockPos(destination); + + // Prevents the player from teleporting into blocks and suffocating. + if(world.getBlockState(pos).getMaterial().blocksMovement() + || world.getBlockState(pos.up()).getMaterial().blocksMovement()){ + return false; + } + + if(!world.isRemote) caster.setPositionAndUpdate(destination.x, destination.y, destination.z); + + this.playSound(world, caster, ticksInUse, -1, modifiers); + caster.swingArm(hand); + return true; + } } } diff --git a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java index e1d71f41..bf1c9d32 100644 --- a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java +++ b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java @@ -1,54 +1,48 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; +import java.util.List; + public class PlagueOfDarkness extends Spell { - - private static final double BASE_RADIUS = 5; - private static final float BASE_DAMAGE = 8; - private static final int BASE_DURATION = 140; public PlagueOfDarkness(){ - super("plague_of_darkness", Tier.MASTER, Element.NECROMANCY, SpellType.ATTACK, 75, 200, EnumAction.BOW, false); + super("plague_of_darkness", EnumAction.BOW, false); + addProperties(EFFECT_RADIUS, DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH); + soundValues(1, 1.1f, 0.2f); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - List targets = WizardryUtilities.getEntitiesWithinRadius( - BASE_RADIUS * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + double radius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade); + + List targets = WizardryUtilities.getEntitiesWithinRadius(radius, caster.posX, caster.posY, caster.posZ, world); for(EntityLivingBase target : targets){ - if(WizardryUtilities.isValidTarget(caster, target) + if(AllyDesignationSystem.isValidTarget(caster, target) && !MagicDamage.isEntityImmune(DamageType.WITHER, target)){ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); target.addPotionEffect(new PotionEffect(MobEffects.WITHER, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 2)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)))); } } + if(world.isRemote){ double particleX, particleZ; @@ -74,10 +68,16 @@ public class PlagueOfDarkness extends Spell { particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, Block.getStateId(block)); } } + + ParticleBuilder.create(Type.SPHERE) + .pos(caster.posX, caster.getEntityBoundingBox().minY + 0.1, caster.posZ) + .scale((float)radius * 0.8f) + .clr(0.8f, 0, 0.05f) + .spawn(world); } caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_DEATH, 1, 1 + 0.2f * world.rand.nextFloat()); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/PocketFurnace.java b/src/main/java/electroblob/wizardry/spell/PocketFurnace.java index dbcb7312..4b9afbc1 100644 --- a/src/main/java/electroblob/wizardry/spell/PocketFurnace.java +++ b/src/main/java/electroblob/wizardry/spell/PocketFurnace.java @@ -1,29 +1,31 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemStack; +import net.minecraft.item.*; import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; +import java.util.Arrays; + public class PocketFurnace extends Spell { + public static final String ITEMS_SMELTED = "items_smelted"; + public PocketFurnace(){ - super("pocket_furnace", Tier.APPRENTICE, Element.FIRE, SpellType.UTILITY, 30, 40, EnumAction.BOW, false); + super("pocket_furnace", EnumAction.BOW, false); + addProperties(ITEMS_SMELTED); + soundValues(1, 0.75f, 0); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - int usesLeft = 5; + int usesLeft = (int)(getProperty(ITEMS_SMELTED).floatValue() * modifiers.get(SpellModifiers.POTENCY)); ItemStack stack, result; @@ -31,11 +33,14 @@ public class PocketFurnace extends Spell { stack = caster.inventory.getStackInSlot(i); - if(!stack.isEmpty()){ + if(!stack.isEmpty() && !world.isRemote){ result = FurnaceRecipes.instance().getSmeltingResult(stack); - if(!result.isEmpty()){ + if(!result.isEmpty() && !(result.getItem() instanceof ItemTool) && !(result.getItem() instanceof ItemSword) + && !(result.getItem() instanceof ItemArmor) + && !Arrays.asList(Wizardry.settings.pocketFurnaceItemBlacklist).contains(result.getItem().getRegistryName())){ + if(stack.getCount() <= usesLeft){ ItemStack stack2 = new ItemStack(result.getItem(), stack.getCount(), result.getItemDamage()); if(WizardryUtilities.doesPlayerHaveItem(caster, result.getItem())){ @@ -55,7 +60,7 @@ public class PocketFurnace extends Spell { } } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, 1, 0.75f); + this.playSound(world, caster, ticksInUse, -1, modifiers); if(world.isRemote){ for(int i = 0; i < 10; i++){ diff --git a/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java b/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java index fc5e9e6a..fb4ea0d1 100644 --- a/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java +++ b/src/main/java/electroblob/wizardry/spell/PocketWorkbench.java @@ -2,12 +2,7 @@ package electroblob.wizardry.spell; import electroblob.wizardry.Wizardry; import electroblob.wizardry.WizardryGuiHandler; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; @@ -16,11 +11,11 @@ import net.minecraft.world.World; public class PocketWorkbench extends Spell { public PocketWorkbench(){ - super("pocket_workbench", Tier.APPRENTICE, Element.SORCERY, SpellType.UTILITY, 30, 40, EnumAction.BOW, false); + super("pocket_workbench", EnumAction.BOW, false); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @@ -33,7 +28,7 @@ public class PocketWorkbench extends Spell { (int)caster.posY, (int)caster.posZ); } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Poison.java b/src/main/java/electroblob/wizardry/spell/Poison.java index a08a5920..5cf6a5f9 100644 --- a/src/main/java/electroblob/wizardry/spell/Poison.java +++ b/src/main/java/electroblob/wizardry/spell/Poison.java @@ -1,10 +1,6 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; @@ -13,20 +9,22 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class Poison extends SpellRay { - - private static final int BASE_DURATION = 200; public Poison(){ - super("poison", Tier.APPRENTICE, Element.EARTH, SpellType.ATTACK, 10, 20, false, 10, WizardrySounds.SPELL_ICE); + super("poison", false, EnumAction.NONE); this.soundValues(1, 1.1f, 0.2f); + addProperties(DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH); } @Override @@ -35,7 +33,7 @@ public class Poison extends SpellRay { } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ @@ -45,24 +43,23 @@ public class Poison extends SpellRay { new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON), - 1 * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.POISON, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)))); } - - return true; } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Possession.java b/src/main/java/electroblob/wizardry/spell/Possession.java new file mode 100644 index 00000000..a7bad811 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Possession.java @@ -0,0 +1,714 @@ +package electroblob.wizardry.spell; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Multimap; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.IVariable; +import electroblob.wizardry.data.IVariable.Variable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.entity.living.*; +import electroblob.wizardry.entity.projectile.*; +import electroblob.wizardry.integration.DamageSafetyChecker; +import electroblob.wizardry.packet.PacketControlInput; +import electroblob.wizardry.packet.PacketPossession; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.*; +import net.minecraft.entity.ai.EntityAIAttackMelee; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.ai.attributes.IAttribute; +import net.minecraft.entity.ai.attributes.IAttributeInstance; +import net.minecraft.entity.monster.*; +import net.minecraft.entity.passive.EntityChicken; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.projectile.EntityPotion; +import net.minecraft.entity.projectile.EntitySnowball; +import net.minecraft.init.Enchantments; +import net.minecraft.init.Items; +import net.minecraft.init.PotionTypes; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemBow; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.potion.PotionEffect; +import net.minecraft.potion.PotionUtils; +import net.minecraft.util.*; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants.NBT; +import net.minecraftforge.event.entity.item.ItemTossEvent; +import net.minecraftforge.event.entity.living.LivingAttackEvent; +import net.minecraftforge.event.entity.living.LivingDamageEvent; +import net.minecraftforge.event.entity.living.LivingDeathEvent; +import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; +import net.minecraftforge.event.entity.player.AttackEntityEvent; +import net.minecraftforge.event.entity.player.EntityItemPickupEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.world.BlockEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.Function; + +@Mod.EventBusSubscriber +public class Possession extends SpellRay { + + /** A {@code ResourceLocation} representing the shader file used when possessing an entity. */ + public static final ResourceLocation SHADER = new ResourceLocation(Wizardry.MODID, "shaders/post/possession.json"); + + /** The NBT tag name for storing the possessing entity's UUID in the target's tag compound. */ + public static final String NBT_KEY = "possessor"; + /** The NBT tag name for storing the possessor's previous inventory in their tag compound. */ + public static final String INVENTORY_NBT_KEY = "prevInventory"; + + /** The health (in half-hearts) below or equal to which the possessor will automatically stop possessing. */ + public static final String CRITICAL_HEALTH = "critical_health"; + + private static final int PROJECTILE_COOLDOWN = 30; + + public static final IVariable TIMER_KEY = new Variable(Persistence.DIMENSION_CHANGE).withTicker(Possession::update); + public static final IVariable POSSESSEE_KEY = new Variable<>(Persistence.DIMENSION_CHANGE); + public static final IVariable SHOOT_COOLDOWN_KEY = new Variable(Persistence.DIMENSION_CHANGE).withTicker((p, n) -> Math.max(n-1, 0)); + + private static final Multimap, BiConsumer> abilities = HashMultimap.create(); + private static final Map, Function> projectiles = new HashMap<>(); + + private static final Map INHERITED_ATTRIBUTES; + + static { + + INHERITED_ATTRIBUTES = ImmutableMap.of( + SharedMonsterAttributes.MOVEMENT_SPEED, UUID.fromString("f65cfcaf-e7ec-4dfb-aa6c-711735d007e3"), + SharedMonsterAttributes.ATTACK_DAMAGE, UUID.fromString("ab67c89e-74a5-4e27-9621-40bffb4f7a03"), + SharedMonsterAttributes.KNOCKBACK_RESISTANCE, UUID.fromString("05529535-9bcf-42bb-8822-45f5ce6a8f08")); + + addAbility(EntitySpider.class, (spider, player) -> { if(player.collidedHorizontally) player.motionY = 0.2; }); + addAbility(EntityChicken.class, (chicken, player) -> { if(!player.onGround && player.motionY < 0) player.motionY *= 0.6D; }); + addAbility(EntityLiving.class, (entity, player) -> { if(!entity.isImmuneToFire() && player.isBurning()) player.extinguish(); }); + + addProjectile(EntitySnowman.class, EntitySnowball::new); // Woooo snowballs! + addProjectile(EntityBlaze.class, EntityMagicFireball::new); // Ugh normal fireballs don't fit so let's just use mine! + addProjectile(EntityGhast.class, EntityLargeMagicFireball::new); + addProjectile(EntityIceWraith.class, EntityIceShard::new); + addProjectile(EntityShadowWraith.class, EntityDarknessOrb::new); + addProjectile(EntityStormElemental.class, EntityLightningDisc::new); + addProjectile(EntityWitch.class, EntityPotion::new); + + } + + public Possession(){ + super("possession", false, EnumAction.NONE); + addProperties(EFFECT_DURATION, CRITICAL_HEALTH); + } + + @Override public boolean canBeCastByNPCs() { return false; } + @Override public boolean canBeCastByDispensers() { return false; } + + @Override + public boolean requiresPacket(){ + return false; // Has its own packet + } + + @Override + protected SoundEvent[] createSounds(){ + return createSoundsWithSuffixes("possess", "end"); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + Vec3d look = caster.getLookVec(); + Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight() - Y_OFFSET, caster.posZ); + + if(!shootSpell(world, origin, look, caster, ticksInUse, modifiers)) return false; + + if(casterSwingsArm(world, caster, hand, ticksInUse, modifiers)) caster.swingArm(hand); + this.playSound(world, caster, ticksInUse, -1, modifiers, "possess"); // TODO: There must be a better way... + return true; + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, + SpellModifiers modifiers){ + + if(target instanceof EntityLiving && caster instanceof EntityPlayer && !isPossessing((EntityPlayer)caster)){ + + EntityPlayer player = (EntityPlayer)caster; + + if(!player.isCreative() && player.getHealth() <= getProperty(CRITICAL_HEALTH).floatValue()){ + player.sendStatusMessage(new TextComponentTranslation( + "spell." + this.getRegistryName() + ".insufficienthealth"), true); + return false; + } + + if(!world.isRemote){ + int duration = (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)); + if(possess(player, (EntityLiving)target, duration)){ + return true; + } + } + } + + return false; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, + SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + // ================================================ Helper methods ================================================ + + /** + * Causes the given player to start possessing the given target for the given duration, and sets all relevant data + * for both entities accordingly. Also takes care of sending packets to update clients. + * @param possessor The player doing the possessing. + * @param target The entity being possessed. + * @param duration The number of ticks for which the possession should last. Pass in a negative integer to make the + * possession last indefinitely (until manually ended with the dismount key). + * @return True if the possession succeeded, false if for some reason it did not (only happens if the player's + * {@link WizardData} is null). + */ + public boolean possess(EntityPlayer possessor, EntityLiving target, int duration){ + + if(WizardData.get(possessor) != null){ + + WizardData.get(possessor).setVariable(POSSESSEE_KEY, target); + WizardData.get(possessor).setVariable(TIMER_KEY, duration); + + possessor.setPositionAndRotation(target.posX, target.posY, target.posZ, target.rotationYaw, target.rotationPitch); + possessor.eyeHeight = target.getEyeHeight(); + setSize(possessor, target.width, target.height); + + target.setDead(); + target.setNoAI(true); + target.setAttackTarget(null); + + // Attributes + + if(target instanceof EntityFlying || target instanceof net.minecraft.entity.passive.EntityFlying){ + possessor.capabilities.allowFlying = true; + possessor.capabilities.isFlying = true; + } + + // Apply attribute modifiers which change the player's attribute value to the target's value + // Uses predefined UUIDs so we can easily remove them later + attributes: + for(IAttribute attribute : INHERITED_ATTRIBUTES.keySet()){ + + IAttributeInstance instance = target.getAttributeMap().getAttributeInstance(attribute); + + if(instance != null){ + + double targetValue = instance.getAttributeValue(); + double currentValue = possessor.getAttributeMap().getAttributeInstance(attribute).getAttributeValue(); + // Don't ask me why, but the player's base movement speed seems to be 0.1 + if(attribute == SharedMonsterAttributes.MOVEMENT_SPEED) currentValue /= possessor.capabilities.getWalkSpeed(); + + for(EntityEquipmentSlot slot : EntityEquipmentSlot.values()){ + if(target.getItemStackFromSlot(slot).getAttributeModifiers(slot).containsKey(attribute.getName())){ + // If the mob has equipment, use the modifiers for that equipment instead of the mob's normal ones + // Not doing this results in the player being able to one-hit most mobs when possessing a zombie pigman! + continue attributes; + } + } + + possessor.getAttributeMap().getAttributeInstance(attribute).applyModifier(new AttributeModifier( + INHERITED_ATTRIBUTES.get(attribute), "possessionModifier", targetValue / currentValue, + WizardryUtilities.Operations.MULTIPLY_FLAT)); + } + } + + if(possessor.world.isRemote){ + // Shaders and effects + if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER); + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); // Looks quite nice... + + }else{ + + // Targeting + + for(EntityLiving creature : WizardryUtilities.getEntitiesWithinRadius(16, possessor.posX, + possessor.posY, possessor.posZ, possessor.world, EntityLiving.class)){ + // Mobs are dumb, if a player possesses something they're like "Huh?! Where'd you go?" + // Of course, this won't last long if the player attacks them, since they'll revenge-target them + if(creature.getAttackTarget() == possessor && !creature.canAttackClass(target.getClass())) + creature.setAttackTarget(null); + } + + // Inventory and items + + if(possessor.getEntityData() != null){ + possessor.getEntityData().setTag(INVENTORY_NBT_KEY, possessor.inventory.writeToNBT(new NBTTagList())); + } + + possessor.inventory.clear(); + possessor.inventoryContainer.detectAndSendChanges(); + + ItemStack stack = target.getHeldItemMainhand().copy(); + + if(target instanceof EntityEnderman && ((EntityEnderman)target).getHeldBlockState() != null){ + stack = new ItemStack(((EntityEnderman)target).getHeldBlockState().getBlock()); + + }else if(stack.getItem() instanceof ItemBow){ + Map enchantments = EnchantmentHelper.getEnchantments(stack); + enchantments.put(Enchantments.INFINITY, 1); + EnchantmentHelper.setEnchantments(enchantments, stack); + ItemStack arrow = new ItemStack(Items.ARROW); + if(target instanceof EntityStray || target instanceof EntityStrayMinion){ + arrow = new ItemStack(Items.TIPPED_ARROW); + PotionUtils.addPotionToItemStack(arrow, PotionTypes.SLOWNESS); + } + possessor.setHeldItem(EnumHand.OFF_HAND, arrow); + } + + possessor.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, stack); + + // Packets + + WizardryPacketHandler.net.sendToAllTracking(new PacketPossession.Message(possessor, target, duration), possessor); + if(possessor instanceof EntityPlayerMP){ + WizardryPacketHandler.net.sendTo(new PacketPossession.Message(possessor, target, duration), (EntityPlayerMP)possessor); + } + } + + return true; + } + + return false; + } + + /** Causes the given player to stop possessing their current possessee, if any, and resets all relevant data for + * both entities. Also takes care of sending packets to update clients. */ + public void endPossession(EntityPlayer player){ + + // Reverts the possessed entity back to normal + + EntityLiving victim = getPossessee(player); + + if(victim != null){ + + victim.isDead = false; + victim.setNoAI(false); + victim.setPosition(player.posX, player.posY, player.posZ); + if(!player.world.isRemote) player.world.spawnEntity(victim); + + for(PotionEffect effect : player.getActivePotionEffects()){ + victim.addPotionEffect(effect); + } + } + + // Reverts the player back to normal + + player.clearActivePotions(); + + player.eyeHeight = player.getDefaultEyeHeight(); // How convenient! + + if(WizardData.get(player) != null){ + WizardData.get(player).setVariable(TIMER_KEY, 0); + WizardData.get(player).setVariable(POSSESSEE_KEY, null); + } + + if(!player.capabilities.isCreativeMode){ + player.capabilities.allowFlying = false; + player.capabilities.isFlying = false; + } + + if(player.world.isRemote){ + net.minecraft.client.Minecraft.getMinecraft().entityRenderer.stopUseShader(); + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); // Looks quite nice... + } + + for(IAttribute attribute : INHERITED_ATTRIBUTES.keySet()){ + player.getAttributeMap().getAttributeInstance(attribute).removeModifier(INHERITED_ATTRIBUTES.get(attribute)); + } + + if(player instanceof EntityPlayerMP){ + + player.inventory.clear(); + + if(player.getEntityData() != null){ + player.inventory.readFromNBT(player.getEntityData().getTagList(INVENTORY_NBT_KEY, NBT.TAG_COMPOUND)); + } + + player.inventoryContainer.detectAndSendChanges(); + } + + this.playSound(player.world, player, 0, -1, null, "end"); + + if(!player.world.isRemote && player instanceof EntityPlayerMP){ + WizardryPacketHandler.net.sendToAllTracking(new PacketPossession.Message(player, null, 0), player); + WizardryPacketHandler.net.sendTo(new PacketPossession.Message(player, null, 0), (EntityPlayerMP)player); + } + } + + /** Returns the {@code EntityLiving} that is currently being possessed by the given player, or null if the player is + * not currently possessing an entity. */ + @Nullable + public static EntityLiving getPossessee(EntityPlayer player){ + return WizardData.get(player) == null ? null : WizardData.get(player).getVariable(POSSESSEE_KEY); + } + + /** Returns true if the given player is currently possessing an entity, false otherwise. Just a shortcut for + * {@code Possession.getPossessee(player) != null}. */ + public static boolean isPossessing(EntityPlayer player){ + return getPossessee(player) != null; + } + + private static int update(EntityPlayer player, Integer possessionTimer){ + + if(possessionTimer == null) possessionTimer = 0; + + if(possessionTimer > 0){ + + if(isPossessing(player) && !player.isSneaking()){ + + possessionTimer--; + + if(player.world.isRemote){ + ParticleBuilder.create(Type.DARK_MAGIC, player).clr(0.1f, 0, 0.3f).spawn(player.world); + // TODO: This (and a few other similar uses) needs ClientProxy-ing. + if(!net.minecraft.client.Minecraft.getMinecraft().entityRenderer.isShaderActive()) + if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER); + } + + }else{ + ((Possession)Spells.possession).endPossession(player); + return 0; + } + + }else if(isPossessing(player)){ + ((Possession)Spells.possession).endPossession(player); + } + + return possessionTimer; + } + + /** Adds the given {@link BiConsumer} to the list of abilities. An ability is an entity-specific action or + * effect that happens when a certain type of entity is possessed. For example, spiders can climb walls, endermen + * can pick up blocks, creepers explode, etc. Other mods may use this method to */ + public static void addAbility(Class entityType, BiConsumer ability){ + abilities.put(entityType, ability); + } + + @SuppressWarnings("unchecked") // Guess what? Type erasure again! + private static void performAbilities(EntityLiving entity, EntityPlayer player){ + // Now we have a type parameter T to work with we can ram the entity into the consumer without a compiler error + for(Class entityType : abilities.keySet()){ + if(entityType.isAssignableFrom(entity.getClass())){ + abilities.get(entityType).forEach(a -> ((BiConsumer)a).accept((T)entity, player)); + } + } + } + + /** Adds the given factory to the list of projectiles. When a player right-clicks while possessing an entity of the + * given type, the given projectile factory will be invoked to create a projectile, which is then aimed and spawned. */ + public static void addProjectile(Class entityType, Function factory){ + projectiles.put(entityType, factory); + } + + /** Copied from Entity#setSize, with the call to move(...) removed. This is presumably also better than reflecting + * into Entity#setSize, which is protected. */ + private static void setSize(Entity entity, float width, float height){ + + if(width != entity.width || height != entity.height){ + + entity.width = width; + entity.height = height; + + double halfWidth = (double)width / 2.0D; + entity.setEntityBoundingBox(new AxisAlignedBB(entity.posX - halfWidth, entity.posY, entity.posZ - halfWidth, entity.posX + halfWidth, entity.posY + (double)entity.height, entity.posZ + halfWidth)); + } + } + + // ================================================ Event Handlers ================================================ + // We got every kind of event handler goin', folks! + + @SubscribeEvent + public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){ + + if(event.phase == TickEvent.Phase.START){ + + EntityLiving possessee = getPossessee(event.player); + + if(possessee != null){ + // Updating these to the player's variables won't have an effect on player movement, but it will + // affect various bits of mob-specific logic + possessee.setPosition(event.player.posX, event.player.posY, event.player.posZ); + possessee.motionX = event.player.motionX; + possessee.motionY = event.player.motionY; + possessee.motionZ = event.player.motionZ; + possessee.onGround = event.player.onGround; + + possessee.onUpdate(); // Event though it's not in the world, it still needs updating + possessee.ticksExisted++; // Normally gets updated from World + + if(possessee.getHealth() <= 0){ + ((Possession)Spells.possession).endPossession(event.player); + } + + performAbilities(possessee, event.player); + } + } + + // Right at the end of EntityPlayer#onUpdate() it calls EntityPlayer#updateSize(), which resets the player's + // size (and is also where this event is fired from, oddly enough) ... but not on my watch! + if(event.phase == TickEvent.Phase.END){ + EntityLiving possessee = getPossessee(event.player); + if(possessee != null){ + setSize(event.player, possessee.width, possessee.height); + } + } + } + + // When possessing, attacks are diverted to the possessed entity for armour, immunity, resistance calculations + // and so on, then when the damage is actually applied, the player is also damaged via onLivingDamageEvent below + @SubscribeEvent(priority = EventPriority.HIGH) + public static void onLivingAttackEvent(LivingAttackEvent event){ + + if(event.getEntity() instanceof EntityPlayer && event.getSource() != DamageSource.OUT_OF_WORLD){ + + EntityLiving possessee = getPossessee((EntityPlayer)event.getEntity()); + + if(possessee != null){ + DamageSafetyChecker.attackEntitySafely(possessee, event.getSource(), event.getAmount(), event.getSource().getDamageType()); + event.setCanceled(true); + } + } + } + + // LivingDamageEvent used in preference to LivingHurtEvent because the player is 'inside' the possessed entity, so + // any damage should come through that entity (and any armour, potions, enchantments etc. it has) first. + @SubscribeEvent + public static void onLivingDamageEvent(LivingDamageEvent event){ + + for(EntityPlayer player : event.getEntity().world.playerEntities){ + + EntityLiving possessee = getPossessee(player); + + if(possessee == event.getEntity()){ + // Possessors take half of all damage taken by the entity they are possessing. If the possessor receives + // fatal/critical damage (i.e. damage that takes them to half a heart or less), their health is reset to half + // a heart and the possession ends. + if(!player.capabilities.isCreativeMode){ + // TODO: Make this a proper DamageSource? + DamageSafetyChecker.attackEntitySafely(player, DamageSource.OUT_OF_WORLD, event.getAmount() / 2, + DamageSource.OUT_OF_WORLD.getDamageType()); + } + + if(player.getHealth() <= Spells.possession.getProperty(CRITICAL_HEALTH).floatValue()){ + player.setHealth(Spells.possession.getProperty(CRITICAL_HEALTH).floatValue()); + ((Possession)Spells.possession).endPossession(player); + } + } + } + } + + // Prevents possessing players from interacting with blocks and controls projectile shooting + @SubscribeEvent + public static void onPlayerInteractEvent(PlayerInteractEvent event){ + + if(event instanceof PlayerInteractEvent.RightClickItem) return; // Can always do this + + EntityLiving possessee = getPossessee(event.getEntityPlayer()); + + if(possessee != null){ + + // Let endermen interact with blocks + if(possessee instanceof EntityEnderman && ( + (event instanceof PlayerInteractEvent.RightClickBlock && ((EntityEnderman)possessee).getHeldBlockState() != null) + || (event instanceof PlayerInteractEvent.LeftClickBlock && ((EntityEnderman)possessee).getHeldBlockState() == null))) + return; + + if(WizardData.get(event.getEntityPlayer()) != null && event.getWorld().isRemote + && (event instanceof PlayerInteractEvent.RightClickEmpty + || event instanceof PlayerInteractEvent.EntityInteract + || event instanceof PlayerInteractEvent.RightClickBlock)){ + + Integer cooldown = WizardData.get(event.getEntityPlayer()).getVariable(SHOOT_COOLDOWN_KEY); + + if(cooldown == null || cooldown == 0){ + + WizardryPacketHandler.net.sendToServer(new PacketControlInput.Message(PacketControlInput.ControlType.POSSESSION_PROJECTILE)); + WizardData.get(event.getEntityPlayer()).setVariable(SHOOT_COOLDOWN_KEY, PROJECTILE_COOLDOWN); + + if(possessee instanceof EntityLightningWraith){ + Spells.arc.cast(event.getWorld(), event.getEntityPlayer(), EnumHand.MAIN_HAND, 0, new SpellModifiers()); + } + + if(possessee instanceof EntityCreeper){ + ((EntityCreeper)possessee).ignite(); + } + } + } + + if(event.isCancelable()) event.setCanceled(true); + } + } + + /** Called via packets to shoot a projectile if the entity currently possessed by the given player can do so. */ + public static void shootProjectile(EntityPlayer possessor){ + + if(WizardData.get(possessor) != null){ + + Integer cooldown = WizardData.get(possessor).getVariable(SHOOT_COOLDOWN_KEY); + + if(cooldown == null || cooldown == 0){ + + EntityLiving possessee = getPossessee(possessor); + + if(possessee != null){ + + if(possessee instanceof EntityLightningWraith){ + Spells.arc.cast(possessor.world, possessor, EnumHand.MAIN_HAND, 0, new SpellModifiers()); + } + + if(possessee instanceof EntityCreeper){ + ((Possession)Spells.possession).endPossession(possessor); + ((EntityCreeper)possessee).ignite(); // Aaaaaaand.... RUN! + } + + Function factory = projectiles.get(possessee.getClass()); + + if(factory != null){ + + IProjectile projectile = factory.apply(possessor.world); + Vec3d look = possessor.getLookVec(); + ((Entity)projectile).setPosition(possessor.posX + look.x, possessor.posY + possessor.getEyeHeight() + look.y, possessor.posZ + look.z); + projectile.shoot(look.x, look.y, look.z, 1.6f, WizardryUtilities.getDefaultAimingError(possessor.world.getDifficulty())); + + if(projectile instanceof EntityMagicProjectile) ((EntityMagicProjectile)projectile).setCaster(possessor); + else if(projectile instanceof EntityMagicArrow) ((EntityMagicArrow)projectile).setCaster(possessor); + + possessor.world.spawnEntity((Entity)projectile); + + } + + WizardData.get(possessor).setVariable(SHOOT_COOLDOWN_KEY, PROJECTILE_COOLDOWN); + } + } + } + } + + @SubscribeEvent + public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){ // Not fired for revenge-targeting + if(event.getTarget() instanceof EntityPlayer && event.getEntityLiving() instanceof EntityLiving){ + EntityLiving possessee = getPossessee((EntityPlayer)event.getTarget()); + EntityLiving attacker = (EntityLiving)event.getEntityLiving(); + if(possessee != null && !attacker.canAttackClass(possessee.getClass())){ + event.setCanceled(true); // Mobs can't target a player possessing an entity they don't normally attack + } + } + } + + // With these two methods I'm pretty sure it's watertight + + @SubscribeEvent + public static void onLivingDeathEvent(LivingDeathEvent event){ + if(event.getEntity() instanceof EntityPlayer && isPossessing((EntityPlayer)event.getEntity())){ + ((Possession)Spells.possession).endPossession((EntityPlayer)event.getEntity()); // Just in case, to make sure the player drops their items + } + } + + @SubscribeEvent + public static void onPlayerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event){ + if(isPossessing(event.player)) ((Possession)Spells.possession).endPossession(event.player); + } + + @SubscribeEvent + public static void onBlockBreakEvent(BlockEvent.BreakEvent event){ + + EntityLiving possessee = getPossessee(event.getPlayer()); + + if(possessee instanceof EntityEnderman){ + if(((EntityEnderman)possessee).getHeldBlockState() == null){ + ((EntityEnderman)possessee).setHeldBlockState(event.getState()); + event.getPlayer().setHeldItem(EnumHand.MAIN_HAND, new ItemStack(event.getState().getBlock())); + event.setExpToDrop(0); + event.getWorld().setBlockToAir(event.getPos()); // Remove block before it can drop + }else{ + event.setCanceled(true); + } + } + } + + @SubscribeEvent + public static void onBlockPlaceEvent(BlockEvent.PlaceEvent event){ + + EntityLiving possessee = getPossessee(event.getPlayer()); + + if(possessee instanceof EntityEnderman){ + if(((EntityEnderman)possessee).getHeldBlockState() == event.getState()){ + ((EntityEnderman)possessee).setHeldBlockState(null); + }else{ + event.setCanceled(true); + } + } + } + + @SubscribeEvent + public static void onEntityItemPickupEvent(EntityItemPickupEvent event){ // Why are there two item pickup events? + + EntityLiving possessee = getPossessee(event.getEntityPlayer()); + + if(possessee != null){ + + if(possessee.canPickUpLoot() && possessee.getHeldItemMainhand().isEmpty()){ + possessee.setHeldItem(EnumHand.MAIN_HAND, event.getItem().getItem()); + }else{ + event.setCanceled(true); + } + } + } + + @SubscribeEvent + static void onItemTossEvent(ItemTossEvent event){ + if(isPossessing(event.getPlayer())){ // Can't drop items while possessing + event.setCanceled(true); + event.getPlayer().inventory.addItemStackToInventory(event.getEntityItem().getItem()); + } + } + + @SubscribeEvent + public static void onAttackEntityEvent(AttackEntityEvent event){ + + EntityLiving possessee = getPossessee(event.getEntityPlayer()); + + if(possessee == null) return; + + if(possessee instanceof EntityCreeper){ + event.setCanceled(true); // Why do creepers have a melee AI?! + }else if(possessee.tasks.taskEntries.stream().noneMatch(t -> t.action instanceof EntityAIAttackMelee)){ + event.setCanceled(true); // Can't melee with a non-melee mob + } + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/RayOfPurification.java b/src/main/java/electroblob/wizardry/spell/RayOfPurification.java new file mode 100644 index 00000000..4367fd39 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/RayOfPurification.java @@ -0,0 +1,103 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; + +public class RayOfPurification extends SpellRay { + + /** The number by which this spell's damage is multiplied for undead entities. */ + public static final String UNDEAD_DAMAGE_MULTIPLIER = "undead_damage_multiplier"; + + public RayOfPurification(){ + super("ray_of_purification", true, EnumAction.NONE); + addProperties(DAMAGE, EFFECT_DURATION, BURN_DURATION, UNDEAD_DAMAGE_MULTIPLIER); + } + + // The following three methods serve as a good example of how to implement continuous spell sounds (hint: it's easy) + + @Override + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(WizardryUtilities.isLiving(target)){ + + if(MagicDamage.isEntityImmune(DamageType.RADIANT, target)){ + if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster) + .sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(), + this.getNameForTranslationFormatted()), true); + }else{ + + float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY); + // Fire + if(((EntityLivingBase)target).isEntityUndead()){ + target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); + damage *= getProperty(UNDEAD_DAMAGE_MULTIPLIER).floatValue(); + } + // Damage + WizardryUtilities.attackEntityWithoutKnockback(target, + MagicDamage.causeDirectMagicDamage(caster, DamageType.RADIANT), damage); + // Blindness + ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)))); + } + } + + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticleRay(World world, Vec3d origin, Vec3d direction, EntityLivingBase caster, double distance){ + + if(caster != null){ + ParticleBuilder.create(Type.BEAM).entity(caster).pos(origin.subtract(caster.getPositionVector())) + .length(distance).clr(1, 0.6f + 0.3f * world.rand.nextFloat(), 0.2f) + .scale(MathHelper.sin(world.getTotalWorldTime() * 0.2f) * 0.1f + 1.4f).spawn(world); + }else{ + ParticleBuilder.create(Type.BEAM).pos(origin).target(origin.add(direction.scale(distance))) + .clr(1, 0.6f + 0.3f * world.rand.nextFloat(), 0.2f) + .scale(MathHelper.sin(world.getTotalWorldTime() * 0.2f) * 0.1f + 1.4f).spawn(world); + } + } +} diff --git a/src/main/java/electroblob/wizardry/spell/RemoveCurse.java b/src/main/java/electroblob/wizardry/spell/RemoveCurse.java new file mode 100644 index 00000000..927d0b3a --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/RemoveCurse.java @@ -0,0 +1,53 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.potion.Curse; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.potion.PotionEffect; +import net.minecraft.world.World; + +public class RemoveCurse extends SpellBuff { + + public RemoveCurse(){ + super("remove_curse", 1, 1, 0.3f); + this.soundValues(0.7f, 1.2f, 0.4f); + } + + @Override + protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ + + if(!caster.getActivePotionEffects().isEmpty()){ + + boolean flag = false; + + for(PotionEffect effect : caster.getActivePotionEffects()){ + // The PotionEffect version (as opposed to Potion) does not call cleanup callbacks + if(effect.getPotion() instanceof Curse){ + caster.removePotionEffect(effect.getPotion()); + flag = true; + } + } + + return flag; + } + + return false; + } + + @Override + protected void spawnParticles(World world, EntityLivingBase caster, SpellModifiers modifiers){ + + super.spawnParticles(world, caster, modifiers); + + for(int i = 0; i < particleCount*2; i++){ + double x = caster.posX + world.rand.nextDouble() * 2 - 1; + double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = caster.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.14, 0).clr(0x0f001b) + .time(20 + world.rand.nextInt(12)).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0x0f001b).spawn(world); + } + } +} diff --git a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java index d5aa5028..f2ec06c2 100644 --- a/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java +++ b/src/main/java/electroblob/wizardry/spell/ReplenishHunger.java @@ -1,9 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -12,9 +8,13 @@ import net.minecraft.world.World; public class ReplenishHunger extends SpellBuff { + public static final String HUNGER_POINTS = "hunger_points"; + public static final String SATURATION_MODIFIER = "saturation_modifier"; + public ReplenishHunger(){ - super("replenish_hunger", Tier.APPRENTICE, Element.HEALING, SpellType.BUFF, 10, 30, WizardrySounds.SPELL_HEAL, 1, 0.7f, 0.3f); + super("replenish_hunger", 1, 0.7f, 0.3f); this.soundValues(0.7f, 1.2f, 0.4f); + addProperties(HUNGER_POINTS, SATURATION_MODIFIER); } @Override public boolean canBeCastByNPCs(){ return false; } @@ -28,9 +28,9 @@ public class ReplenishHunger extends SpellBuff { public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(caster.getFoodStats().needFood()){ - int foodAmount = (int)(4 * modifiers.get(SpellModifiers.POTENCY)); + int foodAmount = (int)(getProperty(HUNGER_POINTS).floatValue() * modifiers.get(SpellModifiers.POTENCY)); // Fixed issue #6: Changed to addStats, since setFoodLevel is client-side only - caster.getFoodStats().addStats(foodAmount, foodAmount * 0.1f); + caster.getFoodStats().addStats(foodAmount, getProperty(SATURATION_MODIFIER).floatValue()); return super.cast(world, caster, hand, ticksInUse, modifiers); } diff --git a/src/main/java/electroblob/wizardry/spell/Resurrection.java b/src/main/java/electroblob/wizardry/spell/Resurrection.java new file mode 100644 index 00000000..1809e07b --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Resurrection.java @@ -0,0 +1,111 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ISpellCastingItem; +import electroblob.wizardry.packet.PacketResurrection; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.EnumAction; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +import java.util.Arrays; +import java.util.Comparator; + +public class Resurrection extends Spell { + + public static final String WAIT_TIME = "wait_time"; + + public Resurrection(){ + super("resurrection", EnumAction.NONE, false); + addProperties(EFFECT_RADIUS, WAIT_TIME); + } + + @Override + public boolean requiresPacket(){ + return false; // Has its own packets + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + WizardData data = WizardData.get(caster); + + double radius = getProperty(EFFECT_RADIUS).doubleValue() * modifiers.get(WizardryItems.range_upgrade); + + if(!world.isRemote && caster.getServer() != null){ + // Potency reduces the time you have to wait to resurrect an ally + int waitTime = (int)(getProperty(WAIT_TIME).floatValue() / modifiers.get(SpellModifiers.POTENCY)); + + EntityPlayerMP nearestDeadAlly = caster.getServer().getPlayerList().getPlayers().stream() + .filter(p -> !p.isEntityAlive() && p.deathTime > waitTime && (data.isPlayerAlly(p) || caster == p) + && p.getDistanceSq(caster) < radius * radius) + .min(Comparator.comparingDouble(caster::getDistanceSq)) + .orElse(null); + + if(nearestDeadAlly != null){ + // When the player entity dies, it is removed from world#loadedEntityList. However, it is NOT removed + // from playerEntityList (and probably a few other places) until respawn is clicked, and since that + // never happens here we need to clean up those references or the player will have duplicate entries + // in some entity lists - and weirdness will ensue! + world.removeEntity(nearestDeadAlly); // Clean up the old entity references + resurrect(nearestDeadAlly); // Reset isDead, must be before spawning the player again + world.spawnEntity(nearestDeadAlly); // Re-add the player to all the relevant entity lists + + // Notify clients to reset the appropriate fields, spawn particles and play sounds + IMessage msg = new PacketResurrection.Message(nearestDeadAlly.getEntityId()); + WizardryPacketHandler.net.sendToDimension(msg, caster.dimension); + + if(caster == nearestDeadAlly){ + caster.getServer().getPlayerList().sendMessage(new TextComponentTranslation( + "spell." + this.getRegistryName() + ".resurrect_self", caster.getDisplayName())); + }else{ + caster.getServer().getPlayerList().sendMessage(new TextComponentTranslation( + "spell." + this.getRegistryName() + ".resurrect_ally", nearestDeadAlly.getDisplayName(), caster.getDisplayName())); + } + + return true; + } + } + + return false; + } + + /** Sets the given player back to alive, sets their health to half-full and (on the client) spawns particles. */ + public void resurrect(EntityPlayer player){ + + player.isDead = false; + player.setHealth(player.getMaxHealth() / 2); + // Experience doesn't normally get reset until respawn, so we need to do that here too + player.deathTime = 0; + player.experience = 0; + player.experienceLevel = 0; + player.experienceTotal = 0; + + if(player.world.isRemote){ + ParticleBuilder.spawnHealParticles(player.world, player); + this.playSound(player.world, player, 0, -1, null); // We know the modifiers parameter isn't used + } + } + + public static int getRemainingWaitTime(int timeSinceDeath){ + return Math.max(0, MathHelper.ceil((Spells.resurrection.getProperty(Resurrection.WAIT_TIME).floatValue() - timeSinceDeath) / 20)); + } + + /** Helper method for detecting if a stack can be used to cast the resurrection spell. */ + public static boolean canStackResurrect(ItemStack stack, EntityPlayer player){ + return stack.getItem() instanceof ISpellCastingItem + && Arrays.asList(((ISpellCastingItem)stack.getItem()).getSpells(stack)).contains(Spells.resurrection) + && ((ISpellCastingItem)stack.getItem()).canCast(stack, Spells.resurrection, player, EnumHand.MAIN_HAND, 0, new SpellModifiers()); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Reversal.java b/src/main/java/electroblob/wizardry/spell/Reversal.java new file mode 100644 index 00000000..f8c79376 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Reversal.java @@ -0,0 +1,83 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.EnumAction; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Reversal extends SpellRay { + + public static final String REVERSED_EFFECTS = "reversed_effects"; + + public Reversal(){ + super("reversal", false, EnumAction.NONE); + addProperties(REVERSED_EFFECTS); + } + + @Override + public boolean canBeCastByDispensers(){ + return false; + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, @Nullable EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + // Naturally, this spell won't work unless it has a living caster and target + if(caster != null && target instanceof EntityLivingBase){ + + List negativePotions = new ArrayList<>(caster.getActivePotionEffects()); + negativePotions.removeIf(p -> !p.getPotion().isBadEffect()); + + if(!world.isRemote){ + + if(negativePotions.isEmpty()) return false; // Needs potion effects to reverse! + + // 1 effect for non-necromancy wands, 2 for apprentice necromancy wands, 3 for advanced and 4 for master + int bonusEffects = (int)((modifiers.get(SpellModifiers.POTENCY) - 1) / Constants.POTENCY_INCREASE_PER_TIER + 0.5f) - 1; + int n = getProperty(REVERSED_EFFECTS).intValue() + bonusEffects; + + // Chooses n random negative potion effects, where n is the potency level + Collections.shuffle(negativePotions); + negativePotions = negativePotions.subList(0, negativePotions.size() < n ? negativePotions.size() : n); + + // Now reverse them! + negativePotions.forEach(p -> caster.removePotionEffect(p.getPotion())); + negativePotions.forEach(((EntityLivingBase)target)::addPotionEffect); + + }else{ + ParticleBuilder.create(Type.BUFF).entity(caster).clr(1, 1, 0.3f).spawn(world); + } + } + + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, @Nullable EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + return false; + } + + @Override + protected boolean onMiss(World world, @Nullable EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ + return true; + } + + @Override + protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.1f, 0, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(0.1f, 0, 0.05f).spawn(world); + } +} diff --git a/src/main/java/electroblob/wizardry/spell/Satiety.java b/src/main/java/electroblob/wizardry/spell/Satiety.java new file mode 100644 index 00000000..8f3ce6e4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/Satiety.java @@ -0,0 +1,40 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class Satiety extends SpellBuff { + + public static final String HUNGER_POINTS = "hunger_points"; + public static final String SATURATION_MODIFIER = "saturation_modifier"; + + public Satiety(){ + super("satiety", 1, 0.7f, 0.3f); + this.soundValues(0.7f, 1.2f, 0.4f); + addProperties(HUNGER_POINTS, SATURATION_MODIFIER); + } + + @Override public boolean canBeCastByNPCs(){ return false; } + + @Override + protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ + return true; // In this case the best solution is to remove the functionality of this method and override cast. + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(caster.getFoodStats().needFood()){ + int foodAmount = (int)(getProperty(HUNGER_POINTS).floatValue() * modifiers.get(SpellModifiers.POTENCY)); + // Fixed issue #6: Changed to addStats, since setFoodLevel is client-side only + caster.getFoodStats().addStats(foodAmount, getProperty(SATURATION_MODIFIER).floatValue()); + return super.cast(world, caster, hand, ticksInUse, modifiers); + } + + return false; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/ShadowWard.java b/src/main/java/electroblob/wizardry/spell/ShadowWard.java index 7d2736ea..60e42bf2 100644 --- a/src/main/java/electroblob/wizardry/spell/ShadowWard.java +++ b/src/main/java/electroblob/wizardry/spell/ShadowWard.java @@ -1,24 +1,20 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.integration.DamageSafetyChecker; +import electroblob.wizardry.registry.Spells; import electroblob.wizardry.util.IElementalDamage; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WandHelper; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; -import net.minecraft.item.ItemStack; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.fml.common.Mod; @@ -27,8 +23,27 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber public class ShadowWard extends Spell { + public static final String REFLECTED_FRACTION = "reflected_fraction"; + public ShadowWard(){ - super("shadow_ward", Tier.ADVANCED, Element.NECROMANCY, SpellType.DEFENCE, 10, 0, EnumAction.BLOCK, true); + super("shadow_ward", EnumAction.BLOCK, true); + addProperties(REFLECTED_FRACTION); + soundValues(0.6f, 1, 0); + } + + @Override + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); } @Override @@ -42,7 +57,7 @@ public class ShadowWard extends Spell { } if(ticksInUse % 50 == 0){ - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_PORTAL_AMBIENT, 0.6f, 1.5f); + this.playSound(world, caster, ticksInUse, -1, modifiers); } return true; @@ -50,22 +65,24 @@ public class ShadowWard extends Spell { @SubscribeEvent public static void onLivingAttackEvent(LivingAttackEvent event){ + if(event.getSource() != null && event.getSource().getTrueSource() instanceof EntityLivingBase){ - // There used to be a check that the target was a player here, but I don't see any reason for it. - ItemStack wand = event.getEntityLiving().getActiveItemStack(); - if(wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand - && WandHelper.getCurrentSpell(wand) instanceof ShadowWard && !event.getSource().isUnblockable() + if(WizardryUtilities.isCasting(event.getEntityLiving(), Spells.shadow_ward) && !event.getSource().isUnblockable() && !(event.getSource() instanceof IElementalDamage && ((IElementalDamage)event.getSource()).isRetaliatory())){ event.setCanceled(true); + + float reflectedFraction = MathHelper.clamp(Spells.shadow_ward.getProperty(REFLECTED_FRACTION).floatValue(), 0, 1); + // Now we can preserve the original damage source (sort of) as long as we make it retaliatory. // For some reason this isn't working, so I've reverted to plain old magic damage for now. //event.getEntityLiving().attackEntityFrom( // MagicDamage.causeDirectMagicDamage(event.getSource().getTrueSource(), DamageType.MAGIC, true), event.getAmount() * 0.5f); - DamageSafetyChecker.attackEntitySafely(event.getEntity(), DamageSource.MAGIC, event.getAmount() * 0.5f, event.getSource().getDamageType()); - ((EntityLivingBase)event.getSource().getTrueSource()).attackEntityFrom( - MagicDamage.causeDirectMagicDamage(event.getEntityLiving(), DamageType.MAGIC, true), event.getAmount() * 0.5f); + DamageSafetyChecker.attackEntitySafely(event.getEntity(), DamageSource.MAGIC, event.getAmount() + * (1 - reflectedFraction), event.getSource().getDamageType()); + event.getSource().getTrueSource().attackEntityFrom(MagicDamage.causeDirectMagicDamage( + event.getEntityLiving(), DamageType.MAGIC, true), event.getAmount() * reflectedFraction); } } } diff --git a/src/main/java/electroblob/wizardry/spell/Shield.java b/src/main/java/electroblob/wizardry/spell/Shield.java index dac072c6..759ee3ed 100644 --- a/src/main/java/electroblob/wizardry/spell/Shield.java +++ b/src/main/java/electroblob/wizardry/spell/Shield.java @@ -1,40 +1,60 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.IVariable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.entity.EntityShield; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.world.World; public class Shield extends Spell { + public static final IVariable SHIELD_KEY = new IVariable.Variable<>(Persistence.NEVER); + public Shield(){ - super("shield", Tier.APPRENTICE, Element.HEALING, SpellType.DEFENCE, 5, 0, EnumAction.BLOCK, true); + super("shield", EnumAction.BLOCK, true); + addProperties(EFFECT_STRENGTH); + } + + @Override + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, 10, 0, false, false)); + caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, 10, + getProperty(EFFECT_STRENGTH).intValue(), false, false)); - if(WizardData.get(caster).shield == null){ - WizardData.get(caster).shield = new EntityShield(world, caster); + if(WizardData.get(caster).getVariable(SHIELD_KEY) == null){ + + EntityShield shield = new EntityShield(world, caster); + + WizardData.get(caster).setVariable(SHIELD_KEY, shield); if(!world.isRemote){ - world.spawnEntity(WizardData.get(caster).shield); + world.spawnEntity(shield); } } - if(ticksInUse == 0){ - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); - } + + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Shockwave.java b/src/main/java/electroblob/wizardry/spell/Shockwave.java index 5b970204..abfd6767 100644 --- a/src/main/java/electroblob/wizardry/spell/Shockwave.java +++ b/src/main/java/electroblob/wizardry/spell/Shockwave.java @@ -1,18 +1,11 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemArtefact; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; @@ -22,39 +15,59 @@ import net.minecraft.item.EnumAction; import net.minecraft.network.play.server.SPacketEntityVelocity; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; +import java.util.List; + public class Shockwave extends Spell { - private static final double BASE_RADIUS = 5; - private static final float BASE_DAMAGE = 8; + public static final String MAX_REPULSION_VELOCITY = "max_repulsion_velocity"; + /** The radius within which maximum damage is dealt and maximum repulsion velocity is applied. */ + private static final double EPICENTRE_RADIUS = 1; public Shockwave(){ - super("shockwave", Tier.MASTER, Element.SORCERY, SpellType.ATTACK, 65, 150, EnumAction.BOW, false); + super("shockwave", EnumAction.BOW, false); + this.soundValues(2, 0.5f, 0); + addProperties(BLAST_RADIUS, DAMAGE, MAX_REPULSION_VELOCITY); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - List targets = WizardryUtilities.getEntitiesWithinRadius( - BASE_RADIUS * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + double radius = getProperty(BLAST_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade); + + List targets = WizardryUtilities.getEntitiesWithinRadius(radius, caster.posX, caster.posY, caster.posZ, world); for(EntityLivingBase target : targets){ - if(WizardryUtilities.isValidTarget(caster, target)){ + + if(target instanceof EntityPlayer && (!Wizardry.settings.playersMoveEachOther + || ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring))){ + + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell.resist", + target.getName(), this.getNameForTranslationFormatted()), true); + return false; + } + + if(AllyDesignationSystem.isValidTarget(caster, target)){ + + // Produces a linear profile from 0 at the edge of the radius to 1 at the epicentre radius, then + // a constant value of 1 within the epicentre radius. + float proximity = (float)(1 - (Math.max(target.getDistance(caster) - EPICENTRE_RADIUS, 0))/(radius - EPICENTRE_RADIUS)); + // Damage increases closer to player up to a maximum of 4 hearts (at 1 block distance). - float damage = Math.min(BASE_DAMAGE / target.getDistance(caster), BASE_DAMAGE); target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST), - damage * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * proximity * modifiers.get(SpellModifiers.POTENCY)); if(!world.isRemote){ // Entity speed increases closer to the player to a maximum of 3 (at 1 block distance). // This is the entity's speed compared to its distance from the player. Used for a similar triangles // based x, y and z speed calculation. - double velocityFactor = Math.min(5 / target.getDistanceSq(caster), 3.0d); + double velocityFactor = proximity * getProperty(MAX_REPULSION_VELOCITY).floatValue(); double dx = target.posX - caster.posX; - double dy = target.posY + 1 - caster.posY; + double dy = target.getEntityBoundingBox().minY + 1 - caster.posY; double dz = target.posZ - caster.posZ; target.motionX = velocityFactor * dx; @@ -74,17 +87,17 @@ public class Shockwave extends Spell { double particleX, particleZ; for(int i = 0; i < 40; i++){ - - particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); - particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ) - .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.8f, 0.8f, 1).spawn(world); - - particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); - particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); - ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ) - .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.9f, 0.9f, 0.9f).spawn(world); - + +// particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); +// particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); +// ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ) +// .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.8f, 0.8f, 1).spawn(world); +// +// particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); +// particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); +// ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ) +// .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.9f, 0.9f, 0.9f).spawn(world); + particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); @@ -95,14 +108,19 @@ public class Shockwave extends Spell { } } + ParticleBuilder.create(Type.SPHERE) + .pos(caster.posX, caster.getEntityBoundingBox().minY + 0.1, caster.posZ) + .scale((float)radius * 0.8f) + .clr(0.8f, 0.9f, 1) + .spawn(world); + world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX, caster.getEntityBoundingBox().minY + 0.1, caster.posZ, 0, 0, 0); } caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 1.0f, 0.7f); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_SHOCKWAVE, 2.0f, 0.3f); + playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/ShulkerBullet.java b/src/main/java/electroblob/wizardry/spell/ShulkerBullet.java new file mode 100644 index 00000000..8b59fdf4 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/ShulkerBullet.java @@ -0,0 +1,101 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityArmorStand; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityShulkerBullet; +import net.minecraft.item.EnumAction; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.List; + +public class ShulkerBullet extends Spell { + + public ShulkerBullet(){ + super("shulker_bullet", EnumAction.NONE, false); + this.soundValues(2, 1, 0.3f); + addProperties(RANGE); + } + + @Override public boolean canBeCastByNPCs(){ return true; } + + @Override public boolean canBeCastByDispensers(){ return true; } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + if(!shoot(world, caster, caster.posX, caster.posY, caster.posZ, EnumFacing.UP, modifiers)) return false; + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + if(!shoot(world, caster, caster.posX, caster.posY, caster.posZ, EnumFacing.UP, modifiers)) return false; + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; + } + + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int duration, int ticksInUse, SpellModifiers modifiers){ + if(!shoot(world, null, x, y, z, direction, modifiers)) return false; + this.playSound(world, x, y, z, ticksInUse, -1, modifiers); + return true; + } + + private boolean shoot(World world, @Nullable EntityLivingBase caster, double x, double y, double z, EnumFacing direction, SpellModifiers modifiers){ + + if(!world.isRemote){ + + double range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + + List possibleTargets = WizardryUtilities.getEntitiesWithinRadius(range, x, y, z, world); + + possibleTargets.remove(caster); + possibleTargets.removeIf(t -> t instanceof EntityArmorStand); + + if(possibleTargets.isEmpty()) return false; + + // getDistanceSq doesn't require square-rooting so it's faster when only comparing + possibleTargets.sort(Comparator.comparingDouble(t -> t.getDistanceSq(x, y, z))); + + Entity target = possibleTargets.get(0); + + // Y axis because the player is always upright + if(caster != null){ + world.spawnEntity(new EntityShulkerBullet(world, caster, target, direction.getAxis())); + }else{ + // Can't use the normal constructor because doesn't accept null for the owner + EntityShulkerBullet bullet = new EntityShulkerBullet(world); + bullet.setLocationAndAngles(x, y, z, bullet.rotationYaw, bullet.rotationPitch); + + // Where there's a will there's a way... + NBTTagCompound nbt = new NBTTagCompound(); + bullet.writeToNBT(nbt); + nbt.setInteger("Dir", direction.getIndex()); + BlockPos pos = new BlockPos(target); + NBTTagCompound targetTag = NBTUtil.createUUIDTag(target.getUniqueID()); + targetTag.setInteger("X", pos.getX()); + targetTag.setInteger("Y", pos.getY()); + targetTag.setInteger("Z", pos.getZ()); + nbt.setTag("Target", targetTag); + bullet.readFromNBT(nbt); // LOL I just modified private fields without reflection + + world.spawnEntity(bullet); + } + } + + return true; + } +} diff --git a/src/main/java/electroblob/wizardry/spell/SixthSense.java b/src/main/java/electroblob/wizardry/spell/SixthSense.java index a7d731bf..b311c7cb 100644 --- a/src/main/java/electroblob/wizardry/spell/SixthSense.java +++ b/src/main/java/electroblob/wizardry/spell/SixthSense.java @@ -1,43 +1,60 @@ package electroblob.wizardry.spell; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Constants; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.event.entity.living.PotionEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +@Mod.EventBusSubscriber public class SixthSense extends Spell { + /** A {@code ResourceLocation} representing the shader file used when under the effects of sixth sense. */ + public static final ResourceLocation SHADER = new ResourceLocation(Wizardry.MODID, "shaders/post/sixth_sense.json"); + public SixthSense(){ - super("sixth_sense", Tier.APPRENTICE, Element.EARTH, SpellType.BUFF, 20, 100, EnumAction.BOW, false); + super("sixth_sense", EnumAction.BOW, false); + addProperties(EFFECT_DURATION, EFFECT_RADIUS); + soundValues(1, 1.1f, 0.2f); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // Cannot be cast when it has already been cast - if(!world.isRemote){ - caster.addPotionEffect(new PotionEffect(WizardryPotions.sixth_sense, - (int)(400 * modifiers.get(WizardryItems.duration_upgrade)), - (int)((modifiers.get(WizardryItems.range_upgrade) - 1f) / Constants.RANGE_INCREASE_PER_LEVEL))); + caster.addPotionEffect(new PotionEffect(WizardryPotions.sixth_sense, + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + (int)((modifiers.get(WizardryItems.range_upgrade) - 1f) / Constants.RANGE_INCREASE_PER_LEVEL))); + + if(world.isRemote && caster == net.minecraft.client.Minecraft.getMinecraft().player){ + if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER); + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); + + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } + @SubscribeEvent + public static void onPotionAddedEvent(PotionEvent.PotionAddedEvent event){ + if(event.getEntity().world.isRemote && event.getPotionEffect().getPotion() == WizardryPotions.sixth_sense + && event.getEntity() == net.minecraft.client.Minecraft.getMinecraft().player){ + if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER); + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); + } + } + } diff --git a/src/main/java/electroblob/wizardry/spell/Slime.java b/src/main/java/electroblob/wizardry/spell/Slime.java index 9b9e53fe..14bbfaf0 100644 --- a/src/main/java/electroblob/wizardry/spell/Slime.java +++ b/src/main/java/electroblob/wizardry/spell/Slime.java @@ -1,55 +1,32 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntityMagicSlime; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.monster.EntitySkeleton; import net.minecraft.entity.monster.EntitySlime; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class Slime extends SpellRay { - - private static final int BASE_DURATION = 200; public Slime(){ - super("slime", Tier.ADVANCED, Element.EARTH, SpellType.ATTACK, 20, 50, false, 8, WizardrySounds.SPELL_ICE); + super("slime", false, EnumAction.NONE); + addProperties(DURATION); } @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // This spell uses more than one sound, so this is required... - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SLIME_ATTACK, 1.0F, 0.5F); - return flag; - } - - @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag) caster.playSound(SoundEvents.ENTITY_SLIME_ATTACK, 1.0F, 0.5F); - return flag; - } - - @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target) && !(target instanceof EntityMagicSlime)){ @@ -58,29 +35,24 @@ public class Slime extends SpellRay { new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ - if(target instanceof EntitySkeleton && caster instanceof EntityPlayer) - WizardryAdvancementTriggers.slime_skeleton.triggerFor((EntityPlayer)caster); - if(!world.isRemote){ EntityMagicSlime slime = new EntityMagicSlime(world, caster, (EntityLivingBase)target, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade))); + (int)(getProperty(DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))); world.spawnEntity(slime); } } - - return true; } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/SlowTime.java b/src/main/java/electroblob/wizardry/spell/SlowTime.java new file mode 100644 index 00000000..04ce8150 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SlowTime.java @@ -0,0 +1,46 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +public class SlowTime extends SpellBuff { + + /** A {@code ResourceLocation} representing the shader file used when possessing an entity. */ + public static final ResourceLocation SHADER = new ResourceLocation(Wizardry.MODID, "shaders/post/slow_time.json"); + + public SlowTime(){ + super("slow_time", 0.2f, 0.8f, 0.8f, () -> WizardryPotions.slow_time); + addProperties(EFFECT_RADIUS); + soundValues(0.6f, 1.5f, 0); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(caster.world.isRemote && caster == net.minecraft.client.Minecraft.getMinecraft().player){ + if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER); + } + + return super.cast(world, caster, hand, ticksInUse, modifiers); + } + + @Override + public boolean requiresPacket(){ + return false; + } + + @Override + public boolean canBeCastByDispensers(){ + return false; + } + + @Override + public boolean canBeCastByNPCs(){ + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/spell/Snare.java b/src/main/java/electroblob/wizardry/spell/Snare.java index fa2259ea..4b70e60d 100644 --- a/src/main/java/electroblob/wizardry/spell/Snare.java +++ b/src/main/java/electroblob/wizardry/spell/Snare.java @@ -1,8 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.tileentity.TileEntityPlayerSave; import electroblob.wizardry.util.ParticleBuilder; @@ -11,26 +8,28 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Snare extends SpellRay { public Snare(){ - super("snare", Tier.BASIC, Element.EARTH, SpellType.ATTACK, 10, 10, false, 10, SoundEvents.BLOCK_GRASS_PLACE); + super("snare", false, EnumAction.NONE); this.soundValues(1, 1.4f, 0.4f); - this.ignoreEntities(true); + this.ignoreLivingEntities(true); + addProperties(DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(side == EnumFacing.UP && world.isSideSolid(pos, EnumFacing.UP) && WizardryUtilities.canBlockBeReplaced(world, pos.up())){ @@ -47,7 +46,7 @@ public class Snare extends SpellRay { } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Snowball.java b/src/main/java/electroblob/wizardry/spell/Snowball.java index 1e4e901a..500488fd 100644 --- a/src/main/java/electroblob/wizardry/spell/Snowball.java +++ b/src/main/java/electroblob/wizardry/spell/Snowball.java @@ -1,25 +1,24 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntitySnowball; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; public class Snowball extends Spell { public Snowball(){ - super("snowball", Tier.BASIC, Element.ICE, SpellType.ATTACK, 1, 1, EnumAction.NONE, false); + super("snowball", EnumAction.NONE, false); + addProperties(RANGE); + soundValues(0.5f, 0.4f, 0.2f); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @@ -27,13 +26,18 @@ public class Snowball extends Spell { public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(!world.isRemote){ + // Trajectory calculation - see SpellProjectile for a more detailed explanation + float g = 0.03f; + float launchHeight = caster.getEyeHeight(); + float range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + float velocity = MathHelper.sqrt(MathHelper.sqrt(g*g * (launchHeight*launchHeight + range*range)) - g*launchHeight); + EntitySnowball snowball = new EntitySnowball(world, caster); - snowball.shoot(caster, caster.rotationPitch, caster.rotationYaw, 0.0f, 1.5f, 1.0f); + snowball.shoot(caster, caster.rotationPitch, caster.rotationYaw, 0.0f, velocity, 1.0f); world.spawnEntity(snowball); } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_SNOWBALL_THROW, 0.5F, - 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + this.playSound(world, caster, ticksInUse, -1, modifiers); caster.swingArm(hand); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/SpectralPathway.java b/src/main/java/electroblob/wizardry/spell/SpectralPathway.java index 5591448b..adc6c73d 100644 --- a/src/main/java/electroblob/wizardry/spell/SpectralPathway.java +++ b/src/main/java/electroblob/wizardry/spell/SpectralPathway.java @@ -1,11 +1,7 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.tileentity.TileEntityTimer; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; @@ -19,13 +15,17 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class SpectralPathway extends Spell { + + /** The base length of the conjured bridge, in blocks. */ + public static final String LENGTH = "length"; public SpectralPathway(){ - super("spectral_pathway", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 40, 300, EnumAction.BOW, false); + super("spectral_pathway", EnumAction.BOW, false); + addProperties(LENGTH, DURATION); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @@ -44,8 +44,6 @@ public class SpectralPathway extends Spell { if(!world.isRemote){ - int baseLength = 15; - // Gets the coordinates of the nearest block intersection to the player's feet. // Remember that a block always takes the coordinates of its northwestern corner. BlockPos origin = new BlockPos(Math.round(caster.posX), (int)caster.getEntityBoundingBox().minY - 1, @@ -53,7 +51,7 @@ public class SpectralPathway extends Spell { int startPoint = direction.getAxisDirection() == AxisDirection.POSITIVE ? -1 : 0; - for(int i = 0; i < (int)(baseLength * modifiers.get(WizardryItems.range_upgrade)); i++){ + for(int i = 0; i < (int)(getProperty(LENGTH).floatValue() * modifiers.get(WizardryItems.range_upgrade)); i++){ // If either a block gets placed or one has already been placed, flag is set to true. flag = placePathwayBlockIfPossible(world, origin.offset(direction, startPoint + i), modifiers.get(WizardryItems.duration_upgrade)) || flag; @@ -63,17 +61,17 @@ public class SpectralPathway extends Spell { modifiers.get(WizardryItems.duration_upgrade)) || flag; } } - // TODO: There may be some client/server discrepancies here. - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION_LARGE, 1.0f, 1.0f); + + this.playSound(world, caster, ticksInUse, -1, modifiers); return flag; } - private static boolean placePathwayBlockIfPossible(World world, BlockPos pos, float durationMultiplier){ - if(WizardryUtilities.canBlockBeReplacedB(world, pos)){ + private boolean placePathwayBlockIfPossible(World world, BlockPos pos, float durationMultiplier){ + if(WizardryUtilities.canBlockBeReplaced(world, pos, true)){ world.setBlockState(pos, WizardryBlocks.spectral_block.getDefaultState()); if(world.getTileEntity(pos) instanceof TileEntityTimer){ - ((TileEntityTimer)world.getTileEntity(pos)).setLifetime((int)(1200 * durationMultiplier)); + ((TileEntityTimer)world.getTileEntity(pos)).setLifetime((int)(getProperty(DURATION).floatValue() * durationMultiplier)); } return true; } diff --git a/src/main/java/electroblob/wizardry/spell/SpeedTime.java b/src/main/java/electroblob/wizardry/spell/SpeedTime.java new file mode 100644 index 00000000..4692b176 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SpeedTime.java @@ -0,0 +1,133 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.SpellModifiers; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ITickable; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents a blank spell used to fill empty slots on wands. It is unobtainable in-game, except via + * commands, and does nothing when the player attempts to cast it. Its instance can be referenced directly using + * {@link electroblob.wizardry.registry.Spells#none Spells.none} + */ +public class SpeedTime extends Spell { + + /** The base number of ticks to add to the world time for each tick the spell is cast. */ + public static final String TIME_INCREMENT = "time_increment"; + /** The number of extra times to tick each nearby block, entity and tile entity each tick the spell is cast. */ + public static final String EXTRA_TICKS = "extra_ticks"; + + public SpeedTime(){ + super("speed_time", EnumAction.BOW, true); + addProperties(EFFECT_RADIUS, TIME_INCREMENT, EXTRA_TICKS); + } + + @Override + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); + } + + @Override + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + boolean flag = false; + + // Hold onto your hats ladies and gentlemen, this effect scales with potency modifiers! Speeeeeeeeed! + if(Wizardry.settings.worldTimeManipulation){ + world.setWorldTime(world.getWorldTime() + (long)(getProperty(TIME_INCREMENT).floatValue() * modifiers.get(SpellModifiers.POTENCY))); + flag = true; + } + + double radius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade); + + // Doubles the normal effect of the modifier + float potencyLevel = ((modifiers.get(SpellModifiers.POTENCY) - 1) * 2 + 1) * getProperty(EXTRA_TICKS).floatValue(); + + // Ticks all the entities near the caster + List entities = new ArrayList<>(world.loadedEntityList); + entities.removeIf(e -> e instanceof EntityPlayer); + entities.removeIf(e -> caster.getDistance(e) > radius); + + if(!entities.isEmpty()){ + for(int i = 0; i < potencyLevel; i++){ + entities.forEach(Entity::onUpdate); + } + flag = true; + } + + // Ticks all the tile entities near the caster + // Copy the list first! + List tileentities = new ArrayList<>(world.tickableTileEntities); + tileentities.removeIf(t -> caster.getDistanceSq(t.getPos()) > radius*radius); + + if(!tileentities.isEmpty()){ + for(int i = 0; i < potencyLevel; i++){ + tileentities.forEach(t -> ((ITickable)t).update()); + } + flag = true; + } + + if(!world.isRemote){ + + List sphere = WizardryUtilities.getBlockSphere(caster.getPosition(), radius); + + for(BlockPos pos : sphere){ + + if(world.getBlockState(pos).getBlock().getTickRandomly()){ + for(int i = 0; i < potencyLevel; i++){ + world.getBlockState(pos).getBlock().randomTick(world, pos, world.getBlockState(pos), world.rand); + flag = true; + } + } + } + } + + // Particle effects + if(world.isRemote){ + + for(int i=1; i<3; i++){ + + double particleSpread = 2; + double x = caster.posX + 2; + double y = caster.getEntityBoundingBox().minY + caster.height / 2; + double z = caster.posZ; + + ParticleBuilder.create(ParticleBuilder.Type.SPARKLE, world.rand, x, y, z, particleSpread, false) + .vel(-0.25, 0, 0).time(16).clr(1f, 1f, 1f).spawn(world); + + ParticleBuilder.create(ParticleBuilder.Type.FLASH, world.rand, x, y, z, particleSpread, false) + .vel(-0.25, 0, 0).time(16).scale(0.5f).clr(0.6f + world.rand.nextFloat() * 0.4f, + 0.6f + world.rand.nextFloat() * 0.4f, 0.6f + world.rand.nextFloat() * 0.4f).spawn(world); + } + } + + if(flag) playSound(world, caster, ticksInUse, -1, modifiers); + // Always return true if the world time was changed, otherwise return false if nothing was ticked. + return flag; + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Spell.java b/src/main/java/electroblob/wizardry/spell/Spell.java index e90f14b6..8ed6516e 100644 --- a/src/main/java/electroblob/wizardry/spell/Spell.java +++ b/src/main/java/electroblob/wizardry/spell/Spell.java @@ -1,26 +1,28 @@ package electroblob.wizardry.spell; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.item.ItemScroll; +import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.packet.PacketSpellProperties; +import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import net.minecraft.client.resources.I18n; +import electroblob.wizardry.util.SpellProperties; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; @@ -31,24 +33,30 @@ import net.minecraftforge.registries.ForgeRegistry; import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.IForgeRegistryEntry; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; + /** * Generic spell class which is the superclass to all spells in wizardry. When extending this class, you must do the * following: - *

    + *

    * - Have a constructor which passes all necessary constants into the super constructor. I define the constants here so * that the constructor for an individual spell has no parameters, but you may prefer to pass in the parameters when the * spell is registered, so all the mana costs etc. are in one place like a sort of sandbox. - *

    + *

    * - Implement the {@link Spell#cast(World, EntityPlayer, EnumHand, int, SpellModifiers)} method, in which you should * execute the code that makes the spell work, and return true or false depending on whether the spell succeeded and * therefore whether mana should be used up. - *

    + *

    * - Register the spell using {@link RegistryEvent.Register}, with {@link Spell} as the type parameter. Each spell * should have a single instance, like blocks and items. As of Wizardry 2.1, spells use the Forge registry system. - * Related methods such as {@link Spell#id()} and {@link Spell#get(int)} have been re-routed to use this system, leaving + * Related methods such as {@link Spell#metadata()} and {@link Spell#byMetadata(int)} have been re-routed to use this system, leaving * minimal external changes. Note also that the constructor automatically sets the registry name for you, though you may * change it afterwards if necessary. - *

    + *

    * Also note that you can override some other methods from this class. For example, to add a specific kind of formatting * to a spell name or description, you can override {@link Spell#getDisplayName()}, * {@link Spell#getDisplayNameWithFormatting()} or {@link Spell#getDescription()} and append the formatting code (though @@ -56,8 +64,8 @@ import net.minecraftforge.registries.IForgeRegistryEntry; * {@link SummonShadowWraith#getDescription()} for an example. *
    * This class is also home to some useful static methods for interacting with the spell registry: - *

    - * {@link Spell#get(int)} gets a spell instance from its integer id, which corresponds to the metadata of its spell + *

    + * {@link Spell#byMetadata(int)} gets a spell instance from its integer metadata, which corresponds to the metadata of its spell * book.
    * {@link Spell#get(String)} gets a spell instance from its unlocalised name.
    * {@link Spell#getSpells(Predicate)} returns a list of spell instances that match the given {@link Predicate}.
    @@ -68,31 +76,48 @@ import net.minecraftforge.registries.IForgeRegistryEntry; * the order of which is as defined in {@link Element} (i.e. magic, fire, ice, lightning, necromancy, earth, sorcery, * healing). *
    - * + * * @since Wizardry 1.0 - * @see electroblob.wizardry.item.ItemSpellBook ItemSpellBook - * @see electroblob.wizardry.item.ItemScroll ItemScroll + * @see ItemSpellBook ItemSpellBook + * @see ItemScroll ItemScroll * @see Spells */ public abstract class Spell extends IForgeRegistryEntry.Impl implements Comparable { + // Spell checklist: + // - Create and register spell, add texture and properties json file + // - Add name AND description to lang files + // - Add sound(s) to sounds.json + // - Add to advancements/all_spells.json + + // Common property identifiers + public static final String DAMAGE = "damage"; + public static final String RANGE = "range"; + public static final String DURATION = "duration"; + public static final String EFFECT_RADIUS = "effect_radius"; + public static final String BLAST_RADIUS = "blast_radius"; + public static final String EFFECT_DURATION = "effect_duration"; + public static final String EFFECT_STRENGTH = "effect_strength"; + public static final String BURN_DURATION = "burn_duration"; + public static final String DIRECT_DAMAGE = "direct_damage"; + public static final String SPLASH_DAMAGE = "splash_damage"; + public static final String HEALTH = "health"; + public static final String SEEKING_STRENGTH = "seeking_strength"; + public static final String DIRECT_EFFECT_DURATION = "direct_effect_duration"; + public static final String DIRECT_EFFECT_STRENGTH = "direct_effect_strength"; + public static final String SPLASH_EFFECT_DURATION = "splash_effect_duration"; + public static final String SPLASH_EFFECT_STRENGTH = "splash_effect_strength"; + /** Forge registry-based replacement for the internal spells list. */ public static IForgeRegistry registry; - /** Mod ID of the mod that added this spell; defaults to {@link Wizardry#MODID} if not specified. */ - private final String modID; /** The unlocalised name of the spell. */ private final String unlocalisedName; - /** The tier this spell belongs to. */ - public final Tier tier; - /** The element this spell belongs to. */ - public final Element element; - /** The type of spell this is classified as. */ - public final SpellType type; - /** Mana cost of the spell. If it is a continuous spell the cost is per second. */ - public final int cost; - /** Cooldown for the spell in ticks */ - public final int cooldown; + /** This spell's associated SpellProperties object. */ + private SpellProperties properties; + /** Used in initialisation. */ + private Set propertyKeys = new HashSet<>(); + /** The action the player does when this spell is cast. */ public final EnumAction action; /** Whether or not the spell is continuous (keeps going as long as the mouse button is held) */ @@ -101,32 +126,37 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C /** ResourceLocation of the spell icon. */ private final ResourceLocation icon; - /** - * False if the spell has been disabled in the config file, true otherwise. This is now encapsulated to stop it - * being fiddled with. - */ + /** False if the spell has been disabled in the config file, true otherwise. This is now encapsulated to stop it + * being fiddled with. */ private boolean enabled = true; + /** The sound(s) played when this spell is cast. */ + @Nullable + protected final SoundEvent[] sounds; + /** The volume of the sound played when this spell is cast. Defaults to 1. */ + protected float volume = 1; + /** The pitch of the sound played when this spell is cast. Defaults to 1. */ + protected float pitch = 1; + /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ + protected float pitchVariation = 0; + + private static int nextSpellId = 0; + /** The spell's integer ID, mainly used for networking. */ + // This was added after I learnt the hard way why you can't assume Forge's registry IDs are sequential... + private final int id; + /** * This constructor should be called from any subclasses, either feeding in the constants directly or through their * own constructor from wherever the spell is registered. This is the constructor for wizardry's own spells; spells * added by other mods should use - * {@link Spell#Spell(String, String, Tier, Element, SpellType, int, int, EnumAction, boolean)}. + * {@link Spell#Spell(String, String, EnumAction, boolean)}. * @param name The registry name of the spell. This will also be the name of the icon file. The spell's * unlocalised name will be a resource location with the format [modid]:[name]. - * @param tier The tier this spell belongs to. - * @param element The element this spell belongs to. - * @param type The type of spell this is classified as. - * @param cost The amount of mana used to cast the spell. If this is a continuous spell, it represents mana cost per - * second and should be a multiple of 5. - * @param cooldown The cooldown time for this spell in ticks. * @param action The vanilla usage action to be displayed when casting this spell. * @param isContinuous Whether this spell is continuous, meaning you cast it for a length of time by holding the - * right mouse button. */ - public Spell(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, - boolean isContinuous){ - this(Wizardry.MODID, name, tier, element, type, cost, cooldown, action, isContinuous); + public Spell(String name, EnumAction action, boolean isContinuous){ + this(Wizardry.MODID, name, action, isContinuous); } /** @@ -136,46 +166,153 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * the spell icon, and also more generally to distinguish between original and addon spells. * @param name The registry name of the spell, excluding the mod id. This will also be the name of the icon * file. The spell's unlocalised name will be a resource location with the format [modid]:[name]. - * @param tier The tier this spell belongs to. - * @param element The element this spell belongs to. - * @param type The type of spell this is classified as. - * @param cost The amount of mana used to cast the spell. If this is a continuous spell, it represents mana cost per - * second and should be a multiple of 5. - * @param cooldown The cooldown time for this spell in ticks. * @param action The vanilla usage action to be displayed when casting this spell (see {@link}EnumAction) * @param isContinuous Whether this spell is continuous, meaning you cast it for a length of time by holding the - * right mouse button. */ - public Spell(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, - EnumAction action, boolean isContinuous){ - this.modID = modID; + public Spell(String modID, String name, EnumAction action, boolean isContinuous){ this.setRegistryName(modID, name); this.unlocalisedName = this.getRegistryName().toString(); - this.tier = tier; - this.element = element; - this.type = type; - this.cost = cost; - this.cooldown = cooldown; this.action = action; this.isContinuous = isContinuous; - this.icon = new ResourceLocation(this.modID, "textures/spells/" + name + ".png"); + this.icon = new ResourceLocation(modID, "textures/spells/" + name + ".png"); + this.sounds = createSounds(); + this.id = nextSpellId++; } + // ========================================= Initialisation methods =========================================== + + /** Called from {@code init()} in the main mod class. Used to initialise spell fields and properties that depend on + * other things being registered (e.g. potions). Always initialise things in the constructor wherever possible. */ + public void init(){} + + /** + * Called from the constructor to initialise this spell's sounds. By default, this creates and returns a 1-element + * array containing a single sound event called {@code spell.[unlocalised name]}. Override this to add a custom + * sound array, perhaps using one of the convenience methods (see below). + * @return An array of sound events played by this spell. + * @see Spell#createSoundWithSuffix(String) + * @see Spell#createContinuousSpellSounds + * @see Spell#playSound(World, double, double, double, int, int, SpellModifiers, String...) + */ + protected SoundEvent[] createSounds(){ + return new SoundEvent[]{WizardrySounds.createSound("spell." + this.getRegistryName().getPath())}; + } + + // Note 1: The aim here is conciseness. Keeping the identifiers in the spell classes means we don't usually have to + // qualify them with a class name, we can simply type RANGE or whatever. + // Note 2: Identifiers should be named concisely but descriptively. Usually, "range" will suffice, but "duration" + // is somewhat ambiguous - is it the duration of a potion effect, a conjured item, a summoned mob or the casting + // itself? This is why it is qualified as "effect_duration", "minion_lifetime", etc. + + /** + * Adds the given JSON identifiers to the configurable base properties of this spell. This should be called from + * the constructor or {@link Spell#init()}. It is highly recommended that property keys be defined as constants, + * as they will be needed later to retrieve the properties during the casting methods. + *

    + * General spell classes will call this method to set any properties they require in order to work properly, and + * the relevant keys will be public constants. + * @param keys One or more spell property keys to add to the spell. By convention, these are lowercase_with_underscores. + * If any of these already exists, a warning will be printed to the console. + * @return The spell instance, allowing this method to be chained onto the constructor. + * @throws IllegalStateException if this method is called after the spell properties have been initialised. + */ + // Nobody can remove property keys, which guarantees that spell classes always have the properties they need. + // It also means that subclasses need not worry about properties already defined and used in their superclass. + // Conversely, general spell classes ONLY EVER define the properties they ACTUALLY USE. + public final Spell addProperties(String... keys){ + + if(properties != null) throw new IllegalStateException("Tried to add spell properties after they were initialised"); + + for(String key : keys) if(propertyKeys.contains(key)) Wizardry.logger.warn("Tried to add a duplicate property key '" + + key + "' to spell " + this.getRegistryName()); + + Collections.addAll(propertyKeys, keys); + + return this; + } + + /** Internal, do not use. */ + public final String[] getPropertyKeys(){ + return propertyKeys.toArray(new String[0]); + } + + /** Sets this spell's properties to the given {@link SpellProperties} object, but only if it doesn't already + * have one. This prevents spell properties from being changed after initialisation. */ + public void setProperties(@Nonnull SpellProperties properties){ + + if(this.properties == null){ + this.properties = properties; + }else{ + Wizardry.logger.info("A mod attempted to set a spell's properties, but they were already initialised."); + } + } + + /** Called from the event handler when a player logs in. */ + public static void syncProperties(EntityPlayer player){ + if(player instanceof EntityPlayerMP){ + // On the server side, send a packet to the player to synchronise their spell properties + // To avoid sending extra data unnecessarily, the spell properties are sent in order of spell ID + List spells = new ArrayList<>(registry.getValuesCollection()); + spells.sort(Comparator.comparingInt(Spell::networkID)); + WizardryPacketHandler.net.sendToAll(new PacketSpellProperties.Message(spells.stream() + .map(s -> s.properties).toArray(SpellProperties[]::new))); + }else{ + // On the client side, wipe the spell properties so the new ones can be set + for(Spell spell : registry){ + spell.properties = null; // TESTME: Can we guarantee this happens before the packet arrives? + } + } + } + + // These three methods are final because they are for use by subclasses (and are pseudo-static, so to speak). + + /** + * Convenience method that generates a sound event for this spell, with the given suffix. + * @param suffix The suffix to use in the name of the returned sound event (excluding the dot) + * @return A sound event called {@code spell.[unlocalised name].[suffix]}, where [suffix] is the given string. + * @see Spell#createSoundsWithSuffixes(String[]) + */ + public final SoundEvent createSoundWithSuffix(String suffix){ + return WizardrySounds.createSound("spell." + this.getRegistryName().getPath() + "." + suffix); + } + + /** + * Compact version of {@link Spell#createSoundWithSuffix(String)} which accepts multiple suffixes and packs them + * into an array. + * @param suffixes 1 or more suffixes to use in the names of the returned sound events (excluding dots) + * @return An array of the resulting sound events. + */ + public final SoundEvent[] createSoundsWithSuffixes(String... suffixes){ + return Arrays.stream(suffixes).map(this::createSoundWithSuffix).toArray(SoundEvent[]::new); + } + + /** + * Convenience method that generates an array of 3 sound events which can be fed directly into either of the + * continuous spell sound classes' constructors. + * @return An array of three sound events called {@code spell.[unlocalised name].start}, + * {@code spell.[unlocalised name].loop} and {@code spell.[unlocalised name].end} respectively. + */ + public final SoundEvent[] createContinuousSpellSounds(){ + return createSoundsWithSuffixes("start", "loop", "end"); + } + + // ============================================ Casting methods ============================================== + /** * Casts the spell. Each subclass must override this method and within it execute the code to make the spell work. * Returns a boolean so that the main onItemRightClick or onUsingItemTick method can check if the spell was actually * cast or whether a spell specific condition caused it not to be (for example, heal won't work if the player is on * full health), preventing unfair drain of mana. - *

    + *

    * Each spell must return true when it works or the spell will not use up mana. Note that (!world.isRemote) does not * count as a condition; return true should be outside it - in other words, return a value on both the client and * the server. - *

    + *

    * It's worth noting that on the client side, this method only gets called if the server side cast() method * succeeded, so you can put any particle spawning code outside of any success conditions if there are discrepancies * between client and server. - * - * @param world A reference to the world object. Again this is for convenience, you can also use caster.world. + * + * @param world The world in which the spell is being cast. * @param caster The EntityPlayer that cast the spell. * @param hand The hand that is holding the item used to cast the spell. If no item was used, this will be the main * hand. @@ -194,21 +331,21 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * within it execute the code to make the spell work. Returns a boolean to allow whatever calls this method to check * if the spell was actually cast or whether a spell specific condition caused it not to be (for example, heal won't * work if the caster is on full health). - *

    + *

    * This method is intended for use by NPCs (see {@link EntityWizard}) so that they can cast spells. Override it if * you want a spell to be cast by wizards. Note that you must also override {@link Spell#canBeCastByNPCs()} to * return true to allow wizards to select the spell. For some spells, this method may well be exactly the same as * the regular cast method; for others it won't be - for example, projectile-based spells are normally done using * the player's look vector, but NPCs need to use a target-based method instead. - *

    + *

    * Each spell must return true when it works. Note that (!world.isRemote) does not count as a condition; return true * should be outside it - in other words, return a value on both the client and the server. - *

    + *

    * It's worth noting that on the client side, this method only gets called if the server side cast() method * succeeded, so you can put any particle spawning code outside of any success conditions if there are discrepancies * between client and server. - * - * @param world A reference to the world object. This is for convenience, you can also use caster.world. + * + * @param world The world in which the spell is being cast. * @param caster The EntityLiving that cast the spell. * @param hand The hand that is holding the item used to cast the spell. This will almost certainly be the main * hand. @@ -225,6 +362,69 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C return false; } + /** + * Casts the spell, but with an origin and a direction instead of a caster. Each subclass can optionally override this + * method and within it execute the code to make the spell work. Returns a boolean to allow whatever calls this method + * to check if the spell was actually cast or whether a spell specific condition caused it not to be (for example, heal + * won't work if the caster is on full health). + *

    + * This method is intended for use by dispensers and command blocks so that they can cast spells. Override it if + * you want a spell to be cast by dispensers. Note that you must also override {@link Spell#canBeCastByDispensers()} to + * return true to allow dispensers to select the spell. For some spells, this method may well be exactly the same as + * the regular cast method; for others it won't be - for example, projectile-based spells are normally done using + * the player's look vector, but dispensers need to use a facing-based method instead. + *

    + * Each spell must return true when it works. Note that (!world.isRemote) does not count as a condition; return true + * should be outside it - in other words, return a value on both the client and the server. + *

    + * It's worth noting that on the client side, this method only gets called if the server side cast() method + * succeeded, so you can put any particle spawning code outside of any success conditions if there are discrepancies + * between client and server. + * + * @param world The world in which the spell is being cast. + * @param x The x coordinate of the origin point of the spell. + * @param y The y coordinate of the origin point of the spell. + * @param z The z coordinate of the origin point of the spell. + * @param direction The cardinal (UDNSEW) direction in which the spell is being cast. + * @param ticksInUse The number of ticks the spell has already been cast for. For all non-continuous spells, this is + * 0 and is not used. + * @param duration The duration this spell will be cast for, or -1 if it will be cast indefinitely. For all + * non-continuous spells, this is 0 and is not used. This is intended for use in sound loops; there + * should be no need to use it for anything else. + * @param modifiers A {@link SpellModifiers} object containing the modifiers that have been applied to the spell. + * See the javadoc for that class for more information. If no modifiers are required, pass in + * {@code new SpellModifiers()}. + * @return True if the spell succeeded, false if not. Returns false by default. + */ + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + return false; + } + + /** + * Called when the spell stops being cast, either from running out of mana, being stopped by the caster, or due + * to a stack of scrolls running out. Only ever called for continuous spells. This method is mostly used + * for adding particle effects and sounds on spell finish. + *

    + * Because this method is not used in the majority of cases, it was deemed excessive to have three separate + * methods for players, NPCs and dispensers. Instead, some parameters may be null depending on the circumstances, + * similar to the implementation in {@link electroblob.wizardry.event.SpellCastEvent SpellCastEvent}. + * Be sure to check for this before using them! + * + * @param world The world in which the spell was cast. + * @param caster The player or NPC that cast the spell, or null if it was cast from a dispenser. + * @param x The x coordinate of the origin point of the spell, or NaN if the spell wasn't cast from a dispenser. + * @param y The y coordinate of the origin point of the spell, or NaN if the spell wasn't cast from a dispenser. + * @param z The z coordinate of the origin point of the spell, or NaN if the spell wasn't cast from a dispenser. + * @param direction The cardinal (UDNSEW) direction in which the spell was cast, or null if the spell wasn't cast + * from a dispenser. + * @param duration The number of ticks the spell was cast for. + * @param modifiers The modifiers the spell was cast with. + */ + // Conveniently, we can't always get a reference to the target for NPC casting once the spell ends (because it + // might have died or run off, or the NPC might have lost interest...) - so let's just not bother! + public void finishCasting(World world, @Nullable EntityLivingBase caster, double x, double y, double z, + @Nullable EnumFacing direction, int duration, SpellModifiers modifiers){} + /** * Whether NPCs such as wizards can cast this spell. If you have overridden * {@link Spell#cast(World, EntityLiving, EnumHand, int, EntityLivingBase, SpellModifiers)}, you should override @@ -234,13 +434,22 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C return false; } + /** + * Whether dispensers can cast this spell. If you have overridden + * {@link Spell#cast(World, double, double, double, EnumFacing, int, int, SpellModifiers)}, you should override this + * to return true. + */ + public boolean canBeCastByDispensers(){ + return false; + } + /** * Whether this spell requires a packet to be sent when it is cast. Returns true by default, but can be overridden * to return false if the spell's cast() method does not use any code that must be executed client-side (i.e. - * particle spawning). Does nothing for continuous spells, because they never need to send packets. - *

    + * particle spawning). This is not checked for continuous spells, because they never need to send packets. + *

    * If in doubt, leave this method as is; it is purely an optimisation. - * + * * @return false if the spell code should only be run on the server and the client of the player casting * it
    * true if the spell code should be run on the server and all clients in the dimension @@ -250,26 +459,29 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C // Also, now I think about it, this method isn't going to make the slightest bit of difference to the item usage // actions since setItemInUse() is called in ItemWand, not the spell class - so the only thing that matters here is // the particles. - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return true; } - /** - * Returns this spell's id number, which now corresponds to its position in the spell registry. Returns -1 if the - * spell has not been registered. - */ - // This is final so nothing can override it, because that would cause all kinds of problems! - public final int id(){ + // ============================================ Getter methods ============================================== + + /** Returns the metadata for this spell, which corresponds to its registry ID, or -1 if the spell has not been + * registered.
    + *
    + * Because of how the registry system works, this won't change once assigned for a given world so is guaranteed to + * be backwards-compatible by design. However, for this reason if spells are removed there may be gaps in the ID + * numbers. If a continuous set of IDs is required (for networking), use {@link Spell#networkID()}. */ + public final int metadata(){ return ((ForgeRegistry)registry).getID(this); } - /** - * Returns the mod ID for this spell, which should be the ID of the mod that added it. The mod ID is used to tell - * wizardry which filepath to use for the spell's icon. As of Wizardry 1.2, the field itself is private, but this - * getter is provided for external use (though it is never called in the main Wizardry mod). - */ - public final String getModID(){ - return modID; + /** Returns this spell's network ID number, similar to mod-specific entity IDs.
    + *
    + * Unlike {@link Spell#metadata()}, this is guaranteed to be sequential so is suitable for indexed lookup. + * However, it may change if spells are removed so is not backwards-compatible. This means it should not be + * used for data storage. */ + public final int networkID(){ + return id; } /** Returns the {@code ResourceLocation} for this spell's icon. */ @@ -277,6 +489,70 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C return icon; } + /** Returns the {@code SoundEvent}s for this spell's sound. */ + public final SoundEvent[] getSounds(){ + return sounds; + } + + // Property getters - these are final to force addon devs to use the JSON system instead of just overriding them + + /** Returns the tier that this spell belongs to. */ + public final Tier getTier(){ + return properties.tier; + } + + /** Returns the element that this spell belongs to. */ + public final Element getElement(){ + return properties.element; + } + + /** Returns the type of spell this is classified as. */ + public final SpellType getType(){ + return properties.type; + } + + /** Returns the mana cost of the spell. If it is a continuous spell the cost is per second. */ + public final int getCost(){ + return properties.cost; + } + + /** Returns the charge-up time for the spell in ticks. */ + public final int getChargeup(){ + return properties.chargeup; + } + + /** Returns the cooldown for the spell in ticks. */ + public final int getCooldown(){ + return properties.cooldown; + } + + /** + * Returns the base value specified in JSON for the given identifier. This may be used from within the spell + * class, or from elsewhere (entities, items, etc.) via the spell's instance. + * + * @param identifier The JSON identifier for the required property. This must have been defined using + * {@link Spell#addProperties(String...)} or an exception will be thrown. + * @return The base value of the property, as a {@code Number} object. Internally this is handled as a float, but + * it is passed through as a {@code Number} to avoid casting. Be careful with rounding when extracting integer + * values! The JSON parser cannot guarantee that the property file has an integer value. + * @throws IllegalArgumentException if no property was defined with the given identifier. */ + public final Number getProperty(String identifier){ + return properties.getBaseValue(identifier); + } + + /** Returns whether the spell is enabled in any of the given {@link electroblob.wizardry.util.SpellProperties.Context Context}s. + * A spell may be disabled globally in the config, or it may be disabled for one or more specific contexts in + * its JSON file using a resource pack. If called with no arguments, defaults to any context, i.e. only returns + * false if the spell is completely disabled in all contexts. */ + public final boolean isEnabled(SpellProperties.Context... contexts){ + return enabled && (contexts.length == 0 || properties.isEnabled(contexts)); + } + + /** Sets whether the spell is enabled or not. */ + public final void setEnabled(boolean isEnabled){ + this.enabled = isEnabled; + } + /** * Returns the unlocalised name of the spell, without any prefixes or suffixes, e.g. "flame_ray". This should * only be used for translation purposes. @@ -285,6 +561,8 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C return unlocalisedName; } + // ========================================== Translation methods ============================================ + /* The general idea with translation is to use net.minecraft.client.resources.I18n directly on the client side (and * just prepend formatting codes where necessary), and to use TextComponentTranslation on the server (setting the * style as necessary). TextComponentTranslation effectively stores what needs to be translated, without actually @@ -297,14 +575,14 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C */ @SideOnly(Side.CLIENT) public String getDisplayName(){ - return I18n.format("spell." + unlocalisedName); + return net.minecraft.client.resources.I18n.format("spell." + unlocalisedName); } /** * Returns a {@code TextComponentTranslation} which will be translated to the display name of the spell, without * formatting (i.e. not coloured). */ - public TextComponentTranslation getNameForTranslation(){ + public ITextComponent getNameForTranslation(){ return new TextComponentTranslation("spell." + unlocalisedName); } @@ -314,7 +592,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C */ @SideOnly(Side.CLIENT) public String getDisplayNameWithFormatting(){ - return this.element.getFormattingCode() + I18n.format("spell." + unlocalisedName); + return this.getElement().getFormattingCode() + net.minecraft.client.resources.I18n.format("spell." + unlocalisedName); } /** @@ -322,7 +600,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * formatting (i.e. coloured). */ public ITextComponent getNameForTranslationFormatted(){ - return new TextComponentTranslation("spell." + unlocalisedName).setStyle(this.element.getColour()); + return new TextComponentTranslation("spell." + unlocalisedName).setStyle(this.getElement().getColour()); } /** @@ -331,17 +609,124 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C */ @SideOnly(Side.CLIENT) public String getDescription(){ - return I18n.format("spell." + unlocalisedName + ".desc"); + return net.minecraft.client.resources.I18n.format("spell." + unlocalisedName + ".desc"); } - /** Returns whether the spell is enabled in the config. */ - public final boolean isEnabled(){ - return enabled; + // ============================================ Sound methods ============================================== + + /** + * Sets the sound parameters for this spell. + * @param volume The volume of the sound played by this spell, relative to 1. + * @param pitch The pitch of the sound played by this spell, relative to 1. + * @param pitchVariation The random variation in the pitch of the sound played by this spell. The pitch at which the + * sound is played will be randomly chosen from the range: {@code pitch +/- pitchVariation}. + * @return The spell instance, allowing this method to be chained onto the constructor. Note that since this method + * only returns a {@code Spell}, if you are chaining multiple methods onto the constructor this should be called last. + */ + public Spell soundValues(float volume, float pitch, float pitchVariation){ + this.volume = volume; + this.pitch = pitch; + this.pitchVariation = pitchVariation; + return this; } - /** Sets whether the spell is enabled or not. */ - public final void setEnabled(boolean isEnabled){ - this.enabled = isEnabled; + // The general motivation for the spell-based sound system is as follows: + // - There are a lot of spells, and each spell has at least one sound event, which means a lot of sounds! + // - Blocks and entities also define their own sounds, though this system is a bit half-hearted because they + // still have to be registered manually + // - Most spell sounds are used only from within their respective spells + // - I don't want hundreds of simple spell sounds that aren't referenced elsewhere cluttering up WizardrySounds, + // so I'm keeping them in the spell instead - if you really want them you can use getSounds, but really it's bad + // practice to reuse other sound events (something I found out the hard way!) + // - The pitch variation thing is annoying to keep repeating so it's also centralised here + + /** + * Plays this spell's sound at the given entity in the given world. This calls {@link Spell#playSound(World, double, double, double, int, int, SpellModifiers, String...)}, passing in the given entity's position as the xyz coordinates. Also checks if the given entity + * is silent, and if so, does not play the sound. + *

    + * If you are overriding the {@code Spell.playSound} methods, it is recommended that you override the xyz version + * instead of this one, since this method calls that one anyway - unless you want different behaviour for entities. + * @param world The world to play the sound in. + * @param entity The entity to play the sound at, provided it is not silent. + * @param ticksInUse The number of ticks this spell has already been cast for, passed in from the {@code cast(...)} + * methods. Not used in the base method, but included for use by subclasses overriding this method. + * @param duration The number of ticks this spell will be cast for, passed in from the {@code cast(...)} + * methods. Not used in the base method, but included for use by subclasses overriding this method. + * @param modifiers The modifiers this spell was cast with, passed in from the {@code cast(...)} methods. + * @param sounds A number of strings representing the sounds to be played. If omitted, all of this spell's sounds + * will be played at once. String format is as passed to {@link Spell#createSoundWithSuffix(String)}. + */ + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + if(!entity.isSilent()){ + this.playSound(world, entity.posX, entity.posY, entity.posZ, ticksInUse, duration, modifiers, sounds); + } + } + + /** + * Plays this spell's sound at the given position in the given world. This is a vector-based wrapper for + * {@link Spell#playSound(World, double, double, double, int, int, SpellModifiers, String...)}. + *

    + * If you are overriding the {@code Spell.playSound} methods, it is recommended that you override the xyz version + * instead of this one, since this method calls that one anyway. + * @param world The world to play the sound in. + * @param pos A vector representing the position to play the sound at. + * @param ticksInUse The number of ticks this spell has already been cast for, passed in from the {@code cast(...)} + * methods. Not used in the base method, but included for use by subclasses overriding this method. + * @param duration The number of ticks this spell will be cast for, passed in from the {@code cast(...)} + * methods. Not used in the base method, but included for use by subclasses overriding this method. + * @param modifiers The modifiers this spell was cast with, passed in from the {@code cast(...)} methods. + */ + protected void playSound(World world, Vec3d pos, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSound(world, pos.x, pos.y, pos.z, ticksInUse, duration, modifiers, sounds); + } + + /** + * Plays this spell's sounds at the given position in the given world. This is not called automatically; subclasses + * should call it at the appropriate point(s) in the cast methods. By default, it checks whether each sound is null + * before playing, so callers shouldn't have to. + *

    + * Usually, this method will be called by the general spell classes; this is clearly stated in those classes. When + * extending such a class, it is also possible to override this method to add extra sounds or change the sound + * behaviour entirely (for example, playing a continuous spell sound). + * @param world The world to play the sound in. + * @param x The x position to play the sound at. + * @param y The y position to play the sound at. + * @param z The z position to play the sound at. + * @param ticksInUse The number of ticks this spell has already been cast for, passed in from the {@code cast(...)} + * methods. Not used in the base method, but included for use by subclasses overriding this method. + * @param duration The number of ticks this spell will be cast for, passed in from the {@code cast(...)} + * methods. Not used in the base method, but included for use by subclasses overriding this method. + * @param modifiers The modifiers this spell was cast with, passed in from the {@code cast(...)} methods. + */ + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + + List identifiers = Arrays.stream(sounds).map(s -> "spell." + this.getRegistryName().getPath() + "." + s) + .collect(Collectors.toList()); + + if(this.sounds != null){ + for(SoundEvent sound : this.sounds){ + ResourceLocation soundName = SoundEvent.REGISTRY.getNameForObject(sound); + if(soundName != null && (identifiers.size() == 0 || identifiers.contains(soundName.getPath()))){ + world.playSound(null, x, y, z, sound, WizardrySounds.SPELLS, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + } + } + } + } + + /** Helper method which plays a standard continuous spell sound loop on the first casting tick, which moves + * with the given entity. */ + protected final void playSoundLoop(World world, EntityLivingBase entity, int ticksInUse){ + if(ticksInUse == 0 && world.isRemote) Wizardry.proxy.playSpellSoundLoop(entity, this, this.sounds, + WizardrySounds.SPELLS, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + } + + /** Helper method which plays a standard continuous spell sound loop on the first casting tick, at the given + * coordinates. If the given duration is -1, the coordinates must be those of a dispenser. */ + protected final void playSoundLoop(World world, double x, double y, double z, int ticksInUse, int duration){ + if(ticksInUse == 0 && world.isRemote){ + Wizardry.proxy.playSpellSoundLoop(world, x, y, z, this, this.sounds, + WizardrySounds.SPELLS, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f), duration); + } } // Spells are sorted according to tier and element. Where several spells have the same tier and element, @@ -349,22 +734,16 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C @Override public final int compareTo(Spell spell){ - if(this.tier.ordinal() > spell.tier.ordinal()){ + if(this.getTier().ordinal() > spell.getTier().ordinal()){ return 1; - }else if(this.tier.ordinal() < spell.tier.ordinal()){ + }else if(this.getTier().ordinal() < spell.getTier().ordinal()){ return -1; }else{ - if(this.element.ordinal() > spell.element.ordinal()){ - return 1; - }else if(this.element.ordinal() < spell.element.ordinal()){ - return -1; - }else{ - return 0; - } + return Integer.compare(this.getElement().ordinal(), spell.getElement().ordinal()); } } - // ================================================ Static methods ================================================== + // ============================================ Static methods ============================================== /** * Returns the total number of registered spells, excluding the 'None' spell. Returns the same number that would be @@ -375,31 +754,34 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C } /** - * Gets a spell instance from its integer id, which now corresponds to its id in the spell registry. If the given id - * has no spell (i.e. is less than 0 or greater than the total number of spells - 1) then it will return the - * {@link None} spell. - *

    - * If you are calling this from inside a loop in which you are iterating through the spells, there is probably a - * better way; see {@link Spell#getSpells(Predicate)}. + * Gets a spell instance from its integer metadata, which corresponds to its ID in the spell registry. If the given + * metadata has no spell assigned then the {@link None} spell will be returned. */ - public static Spell get(int id){ - if(id < 0 || id >= registry.getValuesCollection().size()){ - return Spells.none; - } - Spell spell = ((ForgeRegistry)registry).getValue(id); + public static Spell byMetadata(int metadata){ + Spell spell = ((ForgeRegistry)registry).getValue(metadata); return spell == null ? Spells.none : spell; } + /** Gets a spell instance from its network ID. Or the {@link None} spell if no such spell exists. */ + public static Spell byNetworkID(int id){ + if(id < 0 || id >= registry.getValuesCollection().size()){ + return Spells.none; + } + return registry.getValuesCollection().stream().filter(s -> s.id == id).findAny().orElse(Spells.none); + } + /** - * Returns the spell with the given registry name, or null if no such spell exists. - * + * Returns the spell with the given registry name, or null if no such spell exists. This is really only intended + * for cases where the user has input a name (currently commands and loot functions) and may have omitted the mod + * ID for spells in the base mod. Otherwise, use {@code Spell.registry.getValue(ResourceLocation)}. + * * @param name The registry name of the spell, in the form [mod id]:[spell name]. If no mod id is specified, it * defaults to {@link Wizardry#MODID}. */ public static Spell get(String name){ ResourceLocation key = new ResourceLocation(name); if(key.getNamespace().equals("minecraft")) key = new ResourceLocation(Wizardry.MODID, name); - return ((ForgeRegistry)registry).getValue(key); + return registry.getValue(key); } /** Returns a list of all registered spells' registry names, excluding the 'none' spell. Used in commands. */ @@ -415,34 +797,30 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C * internal spells list; any changes you make to the returned list will have no effect on wizardry since the * returned list is local to this method. Never includes the {@link None} spell. For convenience, there are some * predefined predicates in the Spell class (some of these really aren't shortcuts any more): - *

    + *

    * {@link Spell#allSpells} will allow all spells to be returned
    - * {@link Spell#enabledSpells} will filter out any spells that are disabled in the config
    * {@link Spell#npcSpells} will only allow enabled spells that can be cast by NPCs (see * {@link Spell#canBeCastByNPCs()})
    * {@link Spell#nonContinuousSpells} will filter out continuous spells but not disabled spells
    - * {@link Spell.TierElementFilter} will only allow enabled spells of the specified tier and element - * + * {@link TierElementFilter} will only allow enabled spells of the specified tier and element + * * @param filter A Predicate<Spell> that the returned spells must satisfy. - * + * * @return A local, modifiable list of spells matching the given predicate. Note that this list may be * empty. */ public static List getSpells(Predicate filter){ - return registry.getValuesCollection().stream().filter(filter.and(p -> p != Spells.none)).collect(Collectors.toList()); + return registry.getValuesCollection().stream().filter(filter.and(s -> s != Spells.none)).collect(Collectors.toList()); } /** Predicate which allows all spells. */ public static Predicate allSpells = s -> true; - /** Predicate which allows all enabled spells. */ - public static Predicate enabledSpells = Spell::isEnabled; - /** Predicate which allows all non-continuous spells, even those that have been disabled. */ public static Predicate nonContinuousSpells = s -> !s.isContinuous; /** Predicate which allows all enabled spells for which {@link Spell#canBeCastByNPCs()} returns true. */ - public static Predicate npcSpells = s -> s.isEnabled() && s.canBeCastByNPCs(); + public static Predicate npcSpells = s -> s.isEnabled(SpellProperties.Context.NPCS) && s.canBeCastByNPCs(); /** * Predicate which allows all enabled spells of the given tier and element (create an instance of this class each @@ -453,23 +831,29 @@ public abstract class Spell extends IForgeRegistryEntry.Impl implements C private Tier tier; private Element element; + private SpellProperties.Context[] contexts; /** * Creates a new TierElementFilter that checks for the given tier and element. Does not allow spells that have - * been disabled in the config. - * + * been disabled in the config or in their JSON files. + * * @param tier The EnumTier to check for. Pass in null to allow all tiers. * @param element The EnumElement to check for. Pass in null to allow all elements. + * @param contexts The {@link electroblob.wizardry.util.SpellProperties.Context Context}s in which to check + * for enabled spells. The spell must be enabled in at least one of these contexts to pass + * the filter. If omitted, defaults to all contexts i.e. only completely disabled spells are + * filtered out. */ - public TierElementFilter(Tier tier, Element element){ + public TierElementFilter(Tier tier, Element element, SpellProperties.Context... contexts){ this.tier = tier; this.element = element; + this.contexts = contexts; } @Override public boolean test(Spell spell){ - return spell.isEnabled() && (this.tier == null || spell.tier == this.tier) - && (this.element == null || spell.element == this.element); + return spell.isEnabled(contexts) && (this.tier == null || spell.getTier() == this.tier) + && (this.element == null || spell.getElement() == this.element); } } } diff --git a/src/main/java/electroblob/wizardry/spell/SpellAreaEffect.java b/src/main/java/electroblob/wizardry/spell/SpellAreaEffect.java index 3194da2d..f310ee2f 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellAreaEffect.java +++ b/src/main/java/electroblob/wizardry/spell/SpellAreaEffect.java @@ -1,67 +1,36 @@ package electroblob.wizardry.spell; -import java.util.List; - -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + +/** [NYI] */ public abstract class SpellAreaEffect extends Spell { // TODO: This class doesn't really work as it is right now, it needs rethinking. The aim is to try and have all the // different casting methods call a single (abstract) positional method to do the actual AoE. - - /** The base radius of this spell's area of effect. */ - protected final double baseRadius; - /** The sound that gets played when this spell is cast. */ - @Nullable - protected final SoundEvent sound; - + /** The average number of particles to spawn per block in this spell's area of effect. */ protected float particleDensity = 0.65f; - /** The volume of the sound played when this spell is cast. Defaults to 1. */ - protected float volume = 1; - /** The pitch of the sound played when this spell is cast. Defaults to 1. */ - protected float pitch = 1; - /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ - protected float pitchVariation = 0; - - public SpellAreaEffect(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, double baseRadius, SoundEvent sound){ - this(Wizardry.MODID, name, tier, element, type, cost, cooldown, action, baseRadius, sound); - } - - public SpellAreaEffect(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, double baseRadius, SoundEvent sound){ - super(modID, name, tier, element, type, cost, cooldown, action, false); - this.baseRadius = baseRadius; - this.sound = sound; - } - /** - * Sets the sound parameters for this spell. - * @param volume - * @param pitch - * @param pitchVariation - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellAreaEffect soundValues(float volume, float pitch, float pitchVariation) { - this.volume = volume; - this.pitch = pitch; - this.pitchVariation = pitchVariation; - return this; - } + public SpellAreaEffect(String name, EnumAction action){ + this(Wizardry.MODID, name, action); + } + + public SpellAreaEffect(String modID, String name, EnumAction action){ + super(modID, name, action, false); + this.addProperties(EFFECT_RADIUS); + } /** * Sets the number of particles to spawn per block for this spell. @@ -76,10 +45,10 @@ public abstract class SpellAreaEffect extends Spell { @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - List targets = WizardryUtilities.getEntitiesWithinRadius( - baseRadius * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); + List targets = WizardryUtilities.getEntitiesWithinRadius(getProperty(EFFECT_RADIUS).floatValue() + * modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world); - targets.removeIf(target -> !WizardryUtilities.isValidTarget(caster, target)); + targets.removeIf(target -> !AllyDesignationSystem.isValidTarget(caster, target)); for(EntityLivingBase target : targets){ affectEntity(world, caster, target, modifiers); @@ -89,7 +58,7 @@ public abstract class SpellAreaEffect extends Spell { spawnParticleEffect(world, caster, modifiers); } - if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -107,13 +76,13 @@ public abstract class SpellAreaEffect extends Spell { * Called to spawn the spell's particle effect. By default, this generates a set of random points within the spell's * area of effect and calls {@link SpellAreaEffect#spawnParticle(World, double, double, double)} at each to spawn * the individual particles. Only called client-side. Override to add a custom particle effect. - * @param world - * @param caster - * @param modifiers - */ + * @param world The world to spawn the particles in. + * @param caster The caster of the spell. + * @param modifiers The modifiers the spell was cast with. + */ protected void spawnParticleEffect(World world, EntityLivingBase caster, SpellModifiers modifiers){ - double maxRadius = baseRadius * modifiers.get(WizardryItems.blast_upgrade); + double maxRadius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade); int particleCount = (int)Math.round(particleDensity * Math.PI * maxRadius * maxRadius); for(int i=0; i + *

    + * Properties added by this type of spell: {@link Spell#RANGE} + *

    * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} - *

    - * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + *

    + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + *

    + * By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 */ -public class SpellArrow extends Spell { +public class SpellArrow extends Spell { + + private static final float DISPENSER_INACCURACY = 1; // This is the same as for players + private static final float FALLBACK_VELOCITY = 2; // 2 seems to be a pretty standard value // The general contract for these spell subtypes is that any required parameters are set via the constructor and are // final, whereas any non-critical parameters are set via chainable setters with sensible defaults if not. For example, // the actual sound to play is required, but it makes sense for its volume and pitch to default to 1 if unspecified. /** A factory that creates projectile entities. */ - protected final Function arrowFactory; - /** The base range (projectile speed) of this spell. */ - protected final float baseRange; - /** The sound that gets played when this spell is cast, or null if the spell plays no sound. */ - @Nullable - protected final SoundEvent sound; + protected final Function arrowFactory; - /** The volume of the sound played when this spell is cast. Defaults to 1. */ - protected float volume = 1; - /** The pitch of the sound played when this spell is cast. Defaults to 1. */ - protected float pitch = 1; - /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ - protected float pitchVariation = 0; - - public SpellArrow(String name, Tier tier, Element element, int cost, int cooldown, Function arrowFactory, float baseRange, SoundEvent sound) { - this(Wizardry.MODID, name, tier, element, cost, cooldown, arrowFactory, baseRange, sound); + public SpellArrow(String name, Function arrowFactory){ + this(Wizardry.MODID, name, arrowFactory); } - public SpellArrow(String modID, String name, Tier tier, Element element, int cost, int cooldown, Function arrowFactory, float baseRange, SoundEvent sound){ - super(modID, name, tier, element, SpellType.PROJECTILE, cost, cooldown, EnumAction.NONE, false); + public SpellArrow(String modID, String name, Function arrowFactory){ + super(modID, name, EnumAction.NONE, false); this.arrowFactory = arrowFactory; - this.baseRange = baseRange; - this.sound = sound; + this.addProperties(RANGE); } - /** - * Sets the sound parameters for this spell. - * @param volume - * @param pitch - * @param pitchVariation - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellArrow soundValues(float volume, float pitch, float pitchVariation) { - this.volume = volume; - this.pitch = pitch; - this.pitchVariation = pitchVariation; - return this; - } - - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override public boolean canBeCastByNPCs(){ return true; } + + @Override public boolean canBeCastByDispensers() { return true; } + + /** Computes the velocity the projectile should be launched at to achieve the required range. */ + // Long story short, it doesn't make much sense to me to have the JSON file specify the velocity - even less so if + // the velocity is masquerading under the tag 'range' - so we'll let the code do the heavy lifting so people can + // input something meaningful. + protected float calculateVelocity(EntityMagicArrow projectile, SpellModifiers modifiers, float launchHeight){ + // The required range + float range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + + if(!projectile.doGravity()){ + // No sensible spell will do this - range is meaningless if the particle has no gravity or lifetime + if(projectile.getLifetime() <= 0) return FALLBACK_VELOCITY; + // Speed = distance/time (trivial, I know, but I've put it here for the sake of completeness) + return range / projectile.getLifetime(); + }else{ + // Arrows have gravity 0.05 + float g = 0.05f; + // Assume horizontal projection + return range / MathHelper.sqrt(2 * launchHeight/g); + } + } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(!world.isRemote){ // Creates a projectile from the supplied factory - EntityMagicArrow projectile = arrowFactory.apply(world); + T projectile = arrowFactory.apply(world); // Sets the necessary parameters - projectile.aim(caster, baseRange * modifiers.get(WizardryItems.range_upgrade)); + projectile.aim(caster, calculateVelocity(projectile, modifiers, caster.getEyeHeight() + - (float)EntityMagicArrow.LAUNCH_Y_OFFSET)); projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + addArrowExtras(projectile, caster, modifiers); // Spawns the projectile in the world world.spawnEntity(projectile); } caster.swingArm(hand); - if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -112,19 +116,21 @@ public class SpellArrow extends Spell { if(!world.isRemote){ // Creates a projectile from the supplied factory - EntityMagicArrow projectile = arrowFactory.apply(world); + T projectile = arrowFactory.apply(world); // Sets the necessary parameters int aimingError = caster instanceof ISpellCaster ? ((ISpellCaster)caster).getAimingError(world.getDifficulty()) : WizardryUtilities.getDefaultAimingError(world.getDifficulty()); - projectile.aim(caster, target, baseRange * modifiers.get(WizardryItems.range_upgrade), aimingError); + projectile.aim(caster, target, calculateVelocity(projectile, modifiers, caster.getEyeHeight() + - (float)EntityMagicProjectile.LAUNCH_Y_OFFSET), aimingError); projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + addArrowExtras(projectile, caster, modifiers); // Spawns the projectile in the world world.spawnEntity(projectile); } caster.swingArm(hand); - if(sound != null) caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -132,4 +138,38 @@ public class SpellArrow extends Spell { return false; } + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + + if(!world.isRemote){ + // Creates a projectile from the supplied factory + T projectile = arrowFactory.apply(world); + // Sets the necessary parameters + projectile.setPosition(x, y, z); + Vec3i vec = direction.getDirectionVec(); + projectile.shoot(vec.getX(), vec.getY(), vec.getZ(), calculateVelocity(projectile, modifiers, + 0.375f), DISPENSER_INACCURACY); // 0.375 is the height of the hole in a dispenser + projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + addArrowExtras(projectile, null, modifiers); + // Spawns the projectile in the world + world.spawnEntity(projectile); + } + + // This MUST be the coordinates of the actual dispenser, so we need to offset it + this.playSound(world, x - direction.getXOffset(), y - direction.getYOffset(), z - direction.getZOffset(), ticksInUse, duration, modifiers); + + return true; + } + + /** + * Called just before the arrow is spawned. Does nothing by default, but subclasses can override to call extra + * methods on the spawned arrow. This method is only called server-side so cannot be used to spawn particles directly. + * @param arrow The entity being spawned. + * @param caster The caster of this spell, or null if it was cast by a dispenser. + * @param modifiers The modifiers this spell was cast with. + */ + protected void addArrowExtras(T arrow, @Nullable EntityLivingBase caster, SpellModifiers modifiers){ + // Subclasses can put spell-specific stuff here + } + } diff --git a/src/main/java/electroblob/wizardry/spell/SpellBuff.java b/src/main/java/electroblob/wizardry/spell/SpellBuff.java index f4277c69..5a7273a5 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellBuff.java +++ b/src/main/java/electroblob/wizardry/spell/SpellBuff.java @@ -1,96 +1,98 @@ package electroblob.wizardry.spell; -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.tuple.Triple; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; + /** * Generic superclass for all spells which buff their caster. * This allows all the relevant code to be centralised, since these spells all work in the same way. Usually, a simple * instantiation of this class is sufficient to create a buff spell; if something extra needs to be done, such as * applying a non-potion buff, then methods can be overridden (perhaps using an anonymous class) to add the required * functionality. - *

    + *

    + * Properties added by this type of spell: {@link SpellBuff#getDurationKey(Potion)}, {@link SpellBuff#getStrengthKey(Potion)} + *

    * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} - *

    - * By default, this type of spell requires a packet to be sent. {@link Spell#doesSpellRequirePacket()} + *

    + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + *

    + * By default, this type of spell requires a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 */ public class SpellBuff extends Spell { - /** An array of triples representing the parameters of the status effects that this spell applies to its caster. - * These are of the form [effect, base duration, base amplifier]. */ - protected final Triple[] effects; - /** A set of all the different potions (status effects) that this spell applies to its caster. */ - protected final Set potionSet; - /** The sound that gets played when this spell is cast. */ - protected final SoundEvent sound; + /** An array of factories for the status effects that this spell applies to its caster. The effect factory + * avoids the issue of the potions being registered after the spell. */ + protected final Supplier[] effects; + /** A set of all the different potions (status effects) that this spell applies to its caster. Loaded during + * init(). */ + protected Set potionSet; /** The RGB colour values of the particles spawned when this spell is cast. */ protected final float r, g, b; - /** The volume of the sound played when this spell is cast. Defaults to 1. */ - protected float volume = 1; - /** The pitch of the sound played when this spell is cast. Defaults to 1. */ - protected float pitch = 1; - /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ - protected float pitchVariation = 0; - /** The number of sparkle particles spawned when this spell is cast. Defualts to 10. */ + /** The number of sparkle particles spawned when this spell is cast. Defaults to 10. */ protected float particleCount = 10; @SafeVarargs - public SpellBuff(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, SoundEvent sound, float r, float g, float b, Triple... effects){ - this(Wizardry.MODID, name, tier, element, type, cost, cooldown, sound, r, g, b, effects); + public SpellBuff(String name, float r, float g, float b, Supplier... effects){ + this(Wizardry.MODID, name, r, g, b, effects); } @SafeVarargs - public SpellBuff(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, SoundEvent sound, float r, float g, float b, Triple... effects){ - super(modID, name, tier, element, type, cost, cooldown, EnumAction.BOW, false); - this.sound = sound; + public SpellBuff(String modID, String name, float r, float g, float b, Supplier... effects){ + super(modID, name, EnumAction.BOW, false); this.effects = effects; this.r = r; this.g = g; this.b = b; - // Pretty sure this is better than iterating over (or streaming) all the elements each time the spell is cast. - this.potionSet = Arrays.stream(effects).map(Triple::getLeft).collect(Collectors.toSet()); } - - /** - * Sets the sound parameters for this spell. - * @param volume - * @param pitch - * @param pitchVariation - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellBuff soundValues(float volume, float pitch, float pitchVariation) { - this.volume = volume; - this.pitch = pitch; - this.pitchVariation = pitchVariation; - return this; + + @Override + public void init(){ + // Loads the potion set + this.potionSet = Arrays.stream(effects).map(Supplier::get).collect(Collectors.toSet()); + + for(Potion potion : potionSet){ + // I don't like having this for all buff spells when some potions aren't affected by amplifiers + // TODO: Find a way of only adding the strength key if the potion is affected by amplifiers (dynamically if possible) + // BrewingRecipeRegistry#getOutput might be a good place to start + addProperties(getStrengthKey(potion)); + if(!potion.isInstant()) addProperties(getDurationKey(potion)); + } } - + + // Potion-specific equivalent to defining the identifiers as constants + + protected static String getDurationKey(Potion potion){ + return potion.getRegistryName().getPath() + "_duration"; + } + + protected static String getStrengthKey(Potion potion){ + return potion.getRegistryName().getPath() + "_strength"; + } + /** * Sets the number of sparkle particles spawned when this spell is cast. * @param particleCount The number of particles. @@ -102,13 +104,15 @@ public class SpellBuff extends Spell { } @Override public boolean canBeCastByNPCs(){ return true; } + + @Override public boolean canBeCastByDispensers() { return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - - if(!this.applyEffects(caster, modifiers)) return false; + // Only return on the server side or the client probably won't spawn particles + if(!this.applyEffects(caster, modifiers) && !world.isRemote) return false; if(world.isRemote) this.spawnParticles(world, caster, modifiers); - WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -116,9 +120,38 @@ public class SpellBuff extends Spell { public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ // Wizards can only cast a buff spell if they don't already have its effects. if(caster.getActivePotionMap().keySet().containsAll(potionSet)) return false; - if(!this.applyEffects(caster, modifiers)) return false; + // Only return on the server side or the client probably won't spawn particles + if(!this.applyEffects(caster, modifiers) && !world.isRemote) return false; if(world.isRemote) this.spawnParticles(world, caster, modifiers); - caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; + } + + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + // Gets a 1x1x1 bounding box corresponding to the block in front of the dispenser + AxisAlignedBB boundingBox = new AxisAlignedBB(new BlockPos(x, y, z)); + List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, boundingBox); + + float distance = -1; + EntityLivingBase nearestEntity = null; + // Finds the nearest entity within the bounding box + for(EntityLivingBase entity : entities){ + float newDistance = (float)entity.getDistance(x, y, z); + if(distance == -1 || newDistance < distance){ + distance = newDistance; + nearestEntity = entity; + } + } + + if(nearestEntity == null) return false; + + // Only return on the server side or the client probably won't spawn particles + if(!this.applyEffects(nearestEntity, modifiers) && !world.isRemote) return false; + if(world.isRemote) this.spawnParticles(world, nearestEntity, modifiers); + // This MUST be the coordinates of the actual dispenser, so we need to offset it + this.playSound(world, x - direction.getXOffset(), y - direction.getYOffset(), z - direction.getZOffset(), ticksInUse, duration, modifiers); + return true; } @@ -128,14 +161,34 @@ public class SpellBuff extends Spell { * Returns a boolean to allow subclasses to cause the spell to fail if for some reason the effect cannot be applied * (for example, {@link Heal} fails if the caster is on full health). */ protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){ - // TODO: Find a good way (if any) of implementing potency modifiers - for(Triple effect : effects){ - caster.addPotionEffect(new PotionEffect(effect.getLeft(), (int)(effect.getMiddle() - * modifiers.get(WizardryItems.duration_upgrade)), effect.getRight(), false, false)); + // This will generate 0 for novice and apprentice, and 1 for advanced and master + // TODO: Once we've found a way of detecting if amplifiers actually affect the potion type, implement it here. + int bonusAmplifier = getBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)); + + for(Potion potion : potionSet){ + caster.addPotionEffect(new PotionEffect(potion, potion.isInstant() ? 1 : + (int)(getProperty(getDurationKey(potion)).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + (int)getProperty(getStrengthKey(potion)).floatValue() + bonusAmplifier, + false, true)); } return true; } + + /** Returns the number to be added to the potion amplifier(s) based on the given potency modifier. Override + * to define custom modifier handling. Delegates to {@link SpellBuff#getStandardBonusAmplifier(float)} by + * default. */ + protected int getBonusAmplifier(float potencyModifier){ + return getStandardBonusAmplifier(potencyModifier); + } + + /** Returns a number to be added to potion amplifiers based on the given potency modifier. This method uses + * a standard calculation which results in zero extra levels for novice and apprentice wands and one extra + * level for advanced and master wands (this generally seems to give about the right weight to potency + * modifiers). This is public static because it is useful in a variety of places. */ + public static int getStandardBonusAmplifier(float potencyModifier){ + return (int)((potencyModifier - 1) / 0.4); + } /** Spawns buff particles around the caster. Override to add a custom particle effect. Only called client-side. */ protected void spawnParticles(World world, EntityLivingBase caster, SpellModifiers modifiers){ diff --git a/src/main/java/electroblob/wizardry/spell/SpellConjuration.java b/src/main/java/electroblob/wizardry/spell/SpellConjuration.java index c339932a..b982f9ea 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellConjuration.java +++ b/src/main/java/electroblob/wizardry/spell/SpellConjuration.java @@ -1,12 +1,8 @@ package electroblob.wizardry.spell; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.item.IConjuredItem; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -17,7 +13,6 @@ import net.minecraft.item.EnumAction; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; import net.minecraft.world.World; /** @@ -26,53 +21,36 @@ import net.minecraft.world.World; * instantiation of this class is sufficient to create a conjuration spell; if something extra needs to be done, such as * a custom particle effect or conjuring the item in a specific slot, then methods can be overridden (perhaps using an * anonymous class) to add the required functionality. - *

    + *

    + * Properties added by this type of spell: {@link SpellConjuration#ITEM_LIFETIME} + *

    * By default, this type of spell cannot be cast by NPCs. {@link Spell#canBeCastByNPCs()} - *

    - * By default, this type of spell requires a packet to be sent. {@link Spell#doesSpellRequirePacket()} + *

    + * By default, this type of spell cannot be cast by dispensers. {@link Spell#canBeCastByDispensers()} + *

    + * By default, this type of spell requires a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 * @see IConjuredItem */ public class SpellConjuration extends Spell { - + + public static final String ITEM_LIFETIME = "item_lifetime"; + /** The item that is conjured by this spell. Should implement {@link IConjuredItem}. */ protected final Item item; - /** The sound that gets played when this spell is cast. */ - protected final SoundEvent sound; - /** The volume of the sound played when this spell is cast. Defaults to 1. */ - protected float volume = 1; - /** The pitch of the sound played when this spell is cast. Defaults to 1. */ - protected float pitch = 1; - /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ - protected float pitchVariation = 0; - - public SpellConjuration(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, Item item, SoundEvent sound){ - this(Wizardry.MODID, name, tier, element, type, cost, cooldown, item, sound); + public SpellConjuration(String name, Item item){ + this(Wizardry.MODID, name, item); } - public SpellConjuration(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, Item item, SoundEvent sound){ - super(modID, name, tier, element, type, cost, cooldown, EnumAction.BOW, false); + public SpellConjuration(String modID, String name, Item item){ + super(modID, name, EnumAction.BOW, false); this.item = item; - this.sound = sound; + addProperties(ITEM_LIFETIME); } - /** - * Sets the sound parameters for this spell. - * @param volume - * @param pitch - * @param pitchVariation - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellConjuration soundValues(float volume, float pitch, float pitchVariation) { - this.volume = volume; - this.pitch = pitch; - this.pitchVariation = pitchVariation; - return this; - } - @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ @@ -80,7 +58,7 @@ public class SpellConjuration extends Spell { if(world.isRemote) spawnParticles(world, caster, modifiers); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1, 1); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -106,6 +84,7 @@ public class SpellConjuration extends Spell { ItemStack stack = new ItemStack(item); IConjuredItem.setDurationMultiplier(stack, modifiers.get(WizardryItems.duration_upgrade)); + IConjuredItem.setDamageMultiplier(stack, modifiers.get(SpellModifiers.POTENCY)); if(WizardryUtilities.doesPlayerHaveItem(caster, item)) return false; diff --git a/src/main/java/electroblob/wizardry/spell/SpellConstruct.java b/src/main/java/electroblob/wizardry/spell/SpellConstruct.java index dce473e5..62483f62 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellConstruct.java +++ b/src/main/java/electroblob/wizardry/spell/SpellConstruct.java @@ -1,13 +1,6 @@ package electroblob.wizardry.spell; -import java.util.function.Function; - -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityMagicConstruct; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; @@ -16,23 +9,31 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import javax.annotation.Nullable; +import java.util.function.Function; + /** * Generic superclass for all spells which conjure constructs (i.e. instances of {@link EntityMagicConstruct}). * This allows all the relevant code to be centralised, since these spells all work in a similar way. Usually, a simple * instantiation of this class is sufficient to create a construct spell; if something extra needs to be done, such as * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. * It is encouraged, however, to put extra functionality in the construct entity class instead whenever possible. - *

    + *

    * This class spawns the construct entity at the caster's feet, like ring of fire and healing aura. Use * {@link SpellConstructRanged} (which extends this class) for spells that spawn constructs at an aimed-at position. - *

    + *

    + * Properties added by this type of spell: {@link Spell#DURATION} (if the construct is not permanent) + *

    * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} - *

    - * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + *

    + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + *

    + * By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 @@ -42,53 +43,30 @@ public class SpellConstruct extends Spell { /** A factory that creates construct entities. */ protected final Function constructFactory; - /** The base lifetime of the construct created by this spell, or -1 if the construct does not despawn. */ - protected final int baseDuration; - /** The sound that gets played when this spell is cast, or null if the spell plays no sound. */ - @Nullable - protected final SoundEvent sound; - - /** The volume of the sound played when this spell is cast. Defaults to 1. */ - protected float volume = 1; - /** The pitch of the sound played when this spell is cast. Defaults to 1. */ - protected float pitch = 1; - /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ - protected float pitchVariation = 0; + /** Whether the construct lasts indefinitely, i.e. does not disappear after a set time. */ + protected final boolean permanent; /** Whether the construct must be spawned on the ground. Defaults to false. */ protected boolean requiresFloor = false; /** Whether constructs spawned by this spell may overlap. Defaults to false. */ protected boolean allowOverlap = false; - public SpellConstruct(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, Function constructFactory, int baseDuration, SoundEvent sound){ - this(Wizardry.MODID, name, tier, element, type, cost, cooldown, action, constructFactory, baseDuration, sound); + public SpellConstruct(String name, EnumAction action, Function constructFactory, boolean permanent){ + this(Wizardry.MODID, name, action, constructFactory, permanent); } - public SpellConstruct(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, EnumAction action, Function constructFactory, int baseDuration, SoundEvent sound){ - super(modID, name, tier, element, type, cost, cooldown, action, false); + public SpellConstruct(String modID, String name, EnumAction action, Function constructFactory, boolean permanent){ + super(modID, name, action, false); this.constructFactory = constructFactory; - this.baseDuration = baseDuration; - this.sound = sound; + this.permanent = permanent; + if(!permanent) this.addProperties(DURATION); } - /** - * Sets the sound parameters for this spell. - * @param volume The volume of the sound, relative to 1. - * @param pitch The pitch of the sound, relative to 1. - * @param pitchVariation The pitch variation. The pitch will be set to a random value within this range either side - * of the set pitch value. - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellConstruct soundValues(float volume, float pitch, float pitchVariation) { - this.volume = volume; - this.pitch = pitch; - this.pitchVariation = pitchVariation; - return this; - } - - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override public boolean canBeCastByNPCs(){ return true; } + @Override public boolean canBeCastByDispensers() { return true; } + /** * Sets whether the construct must be spawned on the ground. * @param requiresFloor True to require that the construct be spawned on the ground, false to allow it in mid-air. @@ -114,8 +92,9 @@ public class SpellConstruct extends Spell { public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(caster.onGround || !requiresFloor){ - if(!spawnConstruct(world, caster.posX, caster.posY, caster.posZ, caster, modifiers)) return false; - if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + if(!spawnConstruct(world, caster.posX, caster.posY, caster.posZ, caster.onGround ? EnumFacing.UP : null, + caster, modifiers)) return false; + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -127,8 +106,9 @@ public class SpellConstruct extends Spell { if(target != null){ if(caster.onGround || !requiresFloor){ - if(!spawnConstruct(world, caster.posX, caster.posY, caster.posZ, caster, modifiers)) return false; - if(sound != null) caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + if(!spawnConstruct(world, caster.posX, caster.posY, caster.posZ, caster.onGround ? EnumFacing.UP : null, + caster, modifiers)) return false; + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } } @@ -136,6 +116,26 @@ public class SpellConstruct extends Spell { return false; } + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + + Integer floor = (int)y; + + if(requiresFloor){ + floor = WizardryUtilities.getNearestFloor(world, new BlockPos(x, y, z), 1); + direction = EnumFacing.UP; + } + + if(floor != null){ + if(!spawnConstruct(world, x, floor, z, direction, null, modifiers)) return false; + // This MUST be the coordinates of the actual dispenser, so we need to offset it + this.playSound(world, x - direction.getXOffset(), y - direction.getYOffset(), z - direction.getZOffset(), ticksInUse, duration, modifiers); + return true; + } + + return false; + } + /** * Actually spawns the construct. By default, spawns the construct at the position of the caster and always returns * true. Returning false will cause the spell to fail. @@ -143,27 +143,30 @@ public class SpellConstruct extends Spell { * @param x The x coordinate to spawn the construct at. * @param y The y coordinate to spawn the construct at. * @param z The z coordinate to spawn the construct at. + * @param side The side of a block that was hit, or null if the construct is being spawned in mid-air (only happens + * if {@link SpellConstruct#requiresFloor} is true). * @param caster The EntityLivingBase that cast this spell. * @param modifiers The modifiers with which the spell was cast. * @return false to cause the spell to fail, true to continue with casting. */ - protected boolean spawnConstruct(World world, double x, double y, double z, EntityLivingBase caster, SpellModifiers modifiers){ + protected boolean spawnConstruct(World world, double x, double y, double z, @Nullable EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ if(!world.isRemote){ - // Creates a new constuct using the supplied factory + // Creates a new construct using the supplied factory T construct = constructFactory.apply(world); // Sets the position of the construct (and initialises its bounding box) construct.setPosition(x, y, z); + // Sets the various parameters + construct.setCaster(caster); + construct.lifetime = permanent ? -1 : (int)(getProperty(DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)); + construct.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + addConstructExtras(construct, side, caster, modifiers); // Prevents overlapping of multiple constructs of the same type. Since we have an instance here this is // very simple. The trade-off is that we have to create the entity before the spell fails, but unless // world.spawnEntity(...) is called, its scope is limited to this method so it should be fine. - if(!allowOverlap && !world.getEntitiesWithinAABB(construct.getClass(), caster.getEntityBoundingBox()).isEmpty()) return false; - // Sets the various parameters - construct.setCaster(caster); - construct.lifetime = baseDuration == -1 ? -1 : (int)(baseDuration * modifiers.get(WizardryItems.duration_upgrade)); - construct.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); - addConstructExtras(construct, caster, modifiers); - // Spawns the construct in the world + // Needs to be last in case addConstructExtras modifies the bounding box + if(!allowOverlap && !world.getEntitiesWithinAABB(construct.getClass(), construct.getEntityBoundingBox()).isEmpty()) return false; + // Spawns the construct in the world world.spawnEntity(construct); } @@ -175,11 +178,13 @@ public class SpellConstruct extends Spell { * extra methods on the spawned entity. This method is only called server-side so cannot be used to spawn particles * directly. * @param construct The entity being spawned. - * @param caster The caster of this spell. + * @param side The side of a block that was hit, or null if the construct is being spawned in mid-air (only happens + * if {@link SpellConstruct#requiresFloor} is true). + * @param caster The caster of this spell, or null if it was cast by a dispenser. * @param modifiers The modifiers this spell was cast with. */ // This is the reason this class is generic: it allows subclasses to do whatever they want to their specific entity, // without needing to cast to it. - protected void addConstructExtras(T construct, EntityLivingBase caster, SpellModifiers modifiers){} + protected void addConstructExtras(T construct, EnumFacing side, @Nullable EntityLivingBase caster, SpellModifiers modifiers){} } diff --git a/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java b/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java index cac214de..05d1b618 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java +++ b/src/main/java/electroblob/wizardry/spell/SpellConstructRanged.java @@ -1,13 +1,9 @@ package electroblob.wizardry.spell; -import java.util.function.Function; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityMagicConstruct; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; @@ -16,12 +12,13 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import java.util.function.Function; + /** * Generic superclass for all spells which conjure constructs (i.e. instances of {@link EntityMagicConstruct}) at an * aimed-at position (players and dispensers) or target (non-player spell casters). @@ -29,40 +26,69 @@ import net.minecraft.world.World; * instantiation of this class is sufficient to create a construct spell; if something extra needs to be done, such as * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. * It is encouraged, however, to put extra functionality in the construct entity class instead whenever possible. - *

    + *

    + * Properties added by this type of spell: {@link Spell#RANGE}, {@link Spell#DURATION} (if the construct is not + * permanent) + *

    * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} - *

    - * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + *

    + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + *

    + * By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 * @see SpellConstruct */ public class SpellConstructRanged extends SpellConstruct { - - /** The base range of this spell. */ - protected final double baseRange; - public SpellConstructRanged(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, - Function constructFactory, int baseDuration, double baseRange, SoundEvent sound){ - this(Wizardry.MODID, name, tier, element, type, cost, cooldown, constructFactory, baseDuration, baseRange, sound); + /** Whether liquids count as blocks when raytracing. Defaults to false. */ + protected boolean hitLiquids = false; + /** Whether to ignore uncollidable blocks when raytracing. Defaults to false. */ + protected boolean ignoreUncollidables = false; + + public SpellConstructRanged(String name, Function constructFactory, boolean permanent){ + this(Wizardry.MODID, name, constructFactory, permanent); } - public SpellConstructRanged(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, - Function constructFactory, int baseDuration, double baseRange, SoundEvent sound){ - super(modID, name, tier, element, type, cost, cooldown, EnumAction.NONE, constructFactory, baseDuration, sound); - this.baseRange = baseRange; + public SpellConstructRanged(String modID, String name, Function constructFactory, boolean permanent){ + super(modID, name, EnumAction.NONE, constructFactory, permanent); + this.addProperties(RANGE); } - @Override public boolean doesSpellRequirePacket(){ return false; } + /** + * Sets whether liquids count as blocks when raytracing. + * @param hitLiquids Whether to hit liquids when raytracing. If this is false, the spell will pass through + * liquids as if they weren't there. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public Spell hitLiquids(boolean hitLiquids){ + this.hitLiquids = hitLiquids; + return this; + } + + /** + * Sets whether uncollidable blocks are ignored when raytracing. + * @param ignoreUncollidables Whether to hit uncollidable blocks when raytracing. If this is false, the spell will + * pass through uncollidable blocks as if they weren't there. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public Spell ignoreUncollidables(boolean ignoreUncollidables){ + this.ignoreUncollidables = ignoreUncollidables; + return this; + } + + @Override public boolean requiresPacket(){ return false; } @Override public boolean canBeCastByNPCs(){ return true; } + @Override public boolean canBeCastByDispensers() { return true; } + @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - double range = baseRange * modifiers.get(WizardryItems.range_upgrade); - RayTraceResult rayTrace = WizardryUtilities.standardBlockRayTrace(world, caster, range, false); + double range = getProperty(RANGE).doubleValue() * modifiers.get(WizardryItems.range_upgrade); + RayTraceResult rayTrace = RayTracer.standardBlockRayTrace(world, caster, range, hitLiquids, ignoreUncollidables, false); if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && (rayTrace.sideHit == EnumFacing.UP || !requiresFloor)){ @@ -73,7 +99,7 @@ public class SpellConstructRanged extends SpellC double y = rayTrace.hitVec.y; double z = rayTrace.hitVec.z; - if(!spawnConstruct(world, x, y, z, caster, modifiers)) return false; + if(!spawnConstruct(world, x, y, z, rayTrace.sideHit, caster, modifiers)) return false; } }else if(!requiresFloor){ @@ -86,7 +112,7 @@ public class SpellConstructRanged extends SpellC double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() + look.y * range; double z = caster.posZ + look.z * range; - if(!spawnConstruct(world, x, y, z, caster, modifiers)) return false; + if(!spawnConstruct(world, x, y, z, null, caster, modifiers)) return false; } }else{ @@ -94,7 +120,7 @@ public class SpellConstructRanged extends SpellC } caster.swingArm(hand); - if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -102,7 +128,7 @@ public class SpellConstructRanged extends SpellC public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - double range = baseRange * modifiers.get(WizardryItems.range_upgrade); + double range = getProperty(RANGE).doubleValue() * modifiers.get(WizardryItems.range_upgrade); if(target != null && caster.getDistance(target) <= range){ @@ -111,23 +137,63 @@ public class SpellConstructRanged extends SpellC double x = target.posX; double y = target.posY; double z = target.posZ; + + EnumFacing side = null; // If the target is not on the ground but the construct must be placed on the floor, searches for the // floor under the caster and returns false if it does not find one within 3 blocks. if(!target.onGround && requiresFloor){ - y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(x, y, z), 3); - if(y < 0) return false; + Integer floor = WizardryUtilities.getNearestFloor(world, new BlockPos(x, y, z), 3); + if(floor == null) return false; + y = floor; + side = EnumFacing.UP; } - if(!spawnConstruct(world, x, y, z, caster, modifiers)) return false; + if(!spawnConstruct(world, x, y, z, side, caster, modifiers)) return false; } caster.swingArm(hand); - if(sound != null) caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } return false; } + + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + + double range = getProperty(RANGE).doubleValue() * modifiers.get(WizardryItems.range_upgrade); + Vec3d origin = new Vec3d(x, y, z); + Vec3d endpoint = origin.add(new Vec3d(direction.getDirectionVec()).scale(range)); + RayTraceResult rayTrace = world.rayTraceBlocks(origin, endpoint, hitLiquids, ignoreUncollidables, false); + + if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK && (rayTrace.sideHit == EnumFacing.UP || + !requiresFloor)){ + + if(!world.isRemote){ + + double x1 = rayTrace.hitVec.x; + double y1 = rayTrace.hitVec.y; + double z1 = rayTrace.hitVec.z; + + if(!spawnConstruct(world, x1, y1, z1, rayTrace.sideHit, null, modifiers)) return false; + } + + }else if(!requiresFloor){ + + if(!world.isRemote){ + + if(!spawnConstruct(world, endpoint.x, endpoint.y, endpoint.z, null, null, modifiers)) return false; + } + + }else{ + return false; + } + + // This MUST be the coordinates of the actual dispenser, so we need to offset it + this.playSound(world, x - direction.getXOffset(), y - direction.getYOffset(), z - direction.getZOffset(), ticksInUse, duration, modifiers); + return true; + } } diff --git a/src/main/java/electroblob/wizardry/spell/SpellMinion.java b/src/main/java/electroblob/wizardry/spell/SpellMinion.java index d7971d27..f492b07a 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellMinion.java +++ b/src/main/java/electroblob/wizardry/spell/SpellMinion.java @@ -1,114 +1,94 @@ package electroblob.wizardry.spell; -import java.util.function.Function; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import net.minecraft.entity.Entity; +import electroblob.wizardry.util.WizardryUtilities.Operations; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.DifficultyInstance; import net.minecraft.world.World; +import javax.annotation.Nullable; +import java.util.function.Function; + /** * Generic superclass for all spells which summon minions (i.e. instances of {@link ISummonedCreature}). * This allows all the relevant code to be centralised, since these spells all work in the same way. Usually, a simple - * instantiation of this class is sufficient to create a projectile spell; if something extra needs to be done, such as + * instantiation of this class is sufficient to create a minion spell; if something extra needs to be done, such as * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. * It is encouraged, however, to put extra functionality in the summoned creature class instead whenever possible. - *

    + *

    + * Properties added by this type of spell: {@link SpellMinion#MINION_LIFETIME} + *

    * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} - *

    - * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + *

    + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + *

    + * By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 */ -// Adding a type parameter to this class seems to work very nicely! -public class SpellMinion extends Spell { +public class SpellMinion extends Spell { + + public static final String MINION_LIFETIME = "minion_lifetime"; + public static final String MINION_COUNT = "minion_count"; + public static final String SUMMON_RADIUS = "summon_radius"; + + /** The string identifier for the minion health spell modifier, which doubles as the identifier for the + * entity attribute modifier. */ + public static final String HEALTH_MODIFIER = "minion_health"; + /** The string identifier for the potency attribute modifier. */ + private static final String POTENCY_ATTRIBUTE_MODIFIER = "potency"; /** A factory that creates summoned creature entities. */ protected final Function minionFactory; - /** The base lifetime of the summoned creature. */ - protected final int baseDuration; - /** The sound that gets played when this spell is cast. */ - protected final SoundEvent sound; - - /** The volume of the sound played when this spell is cast. Defaults to 1. */ - protected float volume = 1; - /** The pitch of the sound played when this spell is cast. Defaults to 1. */ - protected float pitch = 1; - /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ - protected float pitchVariation = 0; - /** The number of minions to summon. Defaults to 1. */ - protected int quantity = 1; - /** The maximum number of blocks from the caster in a single direction that the minions can spawn, defaults to 2. */ - protected int range = 2; + /** Whether the minions are spawned in mid-air. Defaults to false. */ + protected boolean flying = false; - public SpellMinion(String name, Tier tier, Element element, int cost, int cooldown, Function minionFactory, int baseDuration, SoundEvent sound){ - this(Wizardry.MODID, name, tier, element, cost, cooldown, minionFactory, baseDuration, sound); + public SpellMinion(String name, Function minionFactory){ + this(Wizardry.MODID, name, minionFactory); } - public SpellMinion(String modID, String name, Tier tier, Element element, int cost, int cooldown, Function minionFactory, int baseDuration, SoundEvent sound){ - super(modID, name, tier, element, SpellType.MINION, cost, cooldown, EnumAction.BOW, false); + public SpellMinion(String modID, String name, Function minionFactory){ + super(modID, name, EnumAction.BOW, false); this.minionFactory = minionFactory; - this.baseDuration = baseDuration; - this.sound = sound; + addProperties(MINION_LIFETIME, MINION_COUNT, SUMMON_RADIUS); } - + /** - * Sets the sound parameters for this spell. - * @param volume - * @param pitch - * @param pitchVariation + * Sets whether the minions are spawned in mid-air. + * @param flying True to spawn the minions in mid-air, false to spawn them on the ground. * @return The spell instance, allowing this method to be chained onto the constructor. */ - public SpellMinion soundValues(float volume, float pitch, float pitchVariation) { - this.volume = volume; - this.pitch = pitch; - this.pitchVariation = pitchVariation; + public SpellMinion flying(boolean flying){ + this.flying = flying; return this; } - /** - * Sets the number of minions this spell will summon. - * @param quantity The number of minions to summon. - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellMinion quantity(int quantity){ - this.quantity = quantity; - return this; - } - - /** - * Sets the range within which minions can spawn. - * @param range The maximum number of blocks from the caster that minions can be spawned. - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellMinion range(int range){ - this.range = range; - return this; - } - - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override public boolean canBeCastByNPCs(){ return true; } + + @Override public boolean canBeCastByDispensers() { return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(!this.spawnMinions(world, caster, modifiers)) return false; - WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -117,31 +97,90 @@ public class SpellMinion extends Spell { SpellModifiers modifiers){ if(!this.spawnMinions(world, caster, modifiers)) return false; - caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } - /** Actually spawns the minions. By default, this spawns the number of minions specified by - * {@link SpellMinion#quantity} within a number of blocks of the caster specified by {@link SpellMinion#range}, - * returning false if there is no space to spawn the minions. Returning false from this method causes the spell to - * fail. Override to do something special, like spawning mnions in a specific position. - * @see SpellMinion#addMinionExtras(Entity, EntityLivingBase, SpellModifiers, int) */ + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + + BlockPos pos = new BlockPos(x, y, z); + + // In this case it looks nice to have them all explode out from one position! (It also makes the code simpler...) + if(!world.isRemote){ + for(int i=0; i extends Spell { return true; } + + /** + * Creates and returns a new instance of this spell's minion entity. By default, this simply calls the apply + * method in {@link SpellMinion#minionFactory}. Override to add logic for changing the type of entity summoned. + * + * @param world The world in which to spawn the minion. + * @param caster The entity that cast this spell, or null if it was cast by a dispenser. + * @param modifiers The spell modifiers this spell was cast with. + * @return The resulting minion entity. + */ + protected T createMinion(World world, @Nullable EntityLivingBase caster, SpellModifiers modifiers){ + return minionFactory.apply(world); + } /** - * Called just before each minion is spawned. Does nothing by default, but is provided to allow subclasses to call - * extra methods on the summoned entity, for example to add equipment. This method is only called server-side so - * cannot be used to spawn particles directly. + * Called just before each minion is spawned. Calls {@link EntityLiving#onInitialSpawn(DifficultyInstance, IEntityLivingData)} + * by default, but subclasses can override to call extra methods on the summoned entity, for example to add + * special equipment. This method is only called server-side so cannot be used to spawn particles directly. * @param minion The entity being spawned. - * @param caster The caster of this spell. + * @param pos The position at which the entity was spawned. + * @param caster The caster of this spell, or null if it was cast by a dispenser. * @param modifiers The modifiers this spell was cast with. - * @param alreadySpawned The number of minions already spawned, before this one. Always less than - * {@link SpellMinion#quantity}. + * @param alreadySpawned The number of minions already spawned, before this one. Always less than the property + * {@link SpellMinion#MINION_COUNT}. */ - protected void addMinionExtras(T minion, EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){} + protected void addMinionExtras(T minion, BlockPos pos, @Nullable EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){ + minion.onInitialSpawn(minion.world.getDifficultyForLocation(pos), null); + } } diff --git a/src/main/java/electroblob/wizardry/spell/SpellProjectile.java b/src/main/java/electroblob/wizardry/spell/SpellProjectile.java index 09f011ff..1e8562e0 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellProjectile.java +++ b/src/main/java/electroblob/wizardry/spell/SpellProjectile.java @@ -1,11 +1,6 @@ package electroblob.wizardry.spell; -import java.util.function.Function; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.ISpellCaster; import electroblob.wizardry.entity.projectile.EntityBomb; import electroblob.wizardry.entity.projectile.EntityMagicProjectile; @@ -16,90 +11,109 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3i; import net.minecraft.world.World; +import javax.annotation.Nullable; +import java.util.function.Function; + /** * Generic superclass for all spells which launch non-directed projectiles (i.e. instances of {@link EntityMagicProjectile}). * This allows all the relevant code to be centralised, since these spells all work in the same way. Usually, a simple * instantiation of this class is sufficient to create a projectile spell; if something extra needs to be done, such as * particle spawning, then methods can be overridden (perhaps using an anonymous class) to add the required functionality. * It is encouraged, however, to put extra functionality in the projectile class instead whenever possible. - *

    + *

    + * Properties added by this type of spell: {@link Spell#RANGE} + *

    * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} - *

    - * By default, this type of spell does not require a packet to be sent. {@link Spell#doesSpellRequirePacket()} + *

    + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + *

    + * By default, this type of spell does not require a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 */ -public class SpellProjectile extends Spell { +public class SpellProjectile extends Spell { + private static final float DISPENSER_INACCURACY = 1; // This is the same as for players + private static final float FALLBACK_VELOCITY = 1.5f; // 1.5 seems to be a pretty standard value + // The general contract for these spell subtypes is that any required parameters are set via the constructor and are // final, whereas any non-critical parameters are set via chainable setters with sensible defaults if not. For example, // the actual sound to play is required, but it makes sense for its volume and pitch to default to 1 if unspecified. /** A factory that creates projectile entities. */ - protected final Function projectileFactory; - /** The base range (projectile speed) of this spell. */ - protected final float baseRange; - /** The sound that gets played when this spell is cast. */ - protected final SoundEvent sound; + protected final Function projectileFactory; - /** The volume of the sound played when this spell is cast. Defaults to 1. */ - protected float volume = 1; - /** The pitch of the sound played when this spell is cast. Defaults to 1. */ - protected float pitch = 1; - /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ - protected float pitchVariation = 0; - - public SpellProjectile(String name, Tier tier, Element element, int cost, int cooldown, Function projectileFactory, float baseRange, SoundEvent sound) { - this(Wizardry.MODID, name, tier, element, cost, cooldown, projectileFactory, baseRange, sound); + public SpellProjectile(String name, Function projectileFactory) { + this(Wizardry.MODID, name, projectileFactory); } - public SpellProjectile(String modID, String name, Tier tier, Element element, int cost, int cooldown, Function projectileFactory, float baseRange, SoundEvent sound){ - super(modID, name, tier, element, SpellType.PROJECTILE, cost, cooldown, EnumAction.NONE, false); + public SpellProjectile(String modID, String name, Function projectileFactory){ + super(modID, name, EnumAction.NONE, false); this.projectileFactory = projectileFactory; - this.baseRange = baseRange; - this.sound = sound; + addProperties(RANGE); } - /** - * Sets the sound parameters for this spell. - * @param volume - * @param pitch - * @param pitchVariation - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellProjectile soundValues(float volume, float pitch, float pitchVariation) { - this.volume = volume; - this.pitch = pitch; - this.pitchVariation = pitchVariation; - return this; - } - - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override public boolean canBeCastByNPCs(){ return true; } + + @Override public boolean canBeCastByDispensers() { return true; } + + /** Computes the velocity the projectile should be launched at to achieve the required range. */ + // Long story short, it doesn't make much sense to me to have the JSON file specify the velocity - even less so if + // the velocity is masquerading under the tag 'range' - so we'll let the code do the heavy lifting so people can + // input something meaningful. + protected float calculateVelocity(EntityMagicProjectile projectile, SpellModifiers modifiers, float launchHeight){ + // The required range + float range = getProperty(RANGE).floatValue() * modifiers.get(WizardryItems.range_upgrade); + + if(projectile.hasNoGravity()){ + // No sensible spell will do this - range is meaningless if the projectile has no gravity or lifetime + if(projectile.getLifetime() <= 0) return FALLBACK_VELOCITY; + // Speed = distance/time (trivial, I know, but I've put it here for the sake of completeness) + return range / projectile.getLifetime(); + }else{ + // It seems that in Minecraft, g is usually* 0.03 - the getter method is protected unfortunately + // * Potions and xp bottles seem to have more gravity (because that makes sense...) + float g = 0.03f; + // Assume horizontal projection + return range / MathHelper.sqrt(2 * launchHeight/g); + } + } + + // Previously we assumed the base range specified refers to the absolute maximum possible range + // when launched at the ideal angle of projection. See the following: + // https://math.stackexchange.com/questions/127300/maximum-range-of-a-projectile-launched-from-an-elevation + // The above link gives the formula: Rmax = u/g * sqrt(u^2 + 2gH), so u = sqrt(sqrt(g^2*(h^2+r^2)) - gh) + // This is probably overkill on the accuracy front, but... hey, I'm a perfectionist, what can I say? + //return MathHelper.sqrt(MathHelper.sqrt(g*g * (launchHeight*launchHeight + range*range)) - g*launchHeight); @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ if(!world.isRemote){ // Creates a projectile from the supplied factory - EntityMagicProjectile projectile = projectileFactory.apply(world); + T projectile = projectileFactory.apply(world); // Sets the necessary parameters - projectile.aim(caster, baseRange * modifiers.get(WizardryItems.range_upgrade)); + projectile.aim(caster, calculateVelocity(projectile, modifiers, caster.getEyeHeight() + - (float)EntityMagicProjectile.LAUNCH_Y_OFFSET)); projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); if(projectile instanceof EntityBomb) ((EntityBomb)projectile).blastMultiplier = modifiers.get(WizardryItems.blast_upgrade); + addProjectileExtras(projectile, caster, modifiers); // Spawns the projectile in the world world.spawnEntity(projectile); } caster.swingArm(hand); - WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -111,20 +125,22 @@ public class SpellProjectile extends Spell { if(!world.isRemote){ // Creates a projectile from the supplied factory - EntityMagicProjectile projectile = projectileFactory.apply(world); + T projectile = projectileFactory.apply(world); // Sets the necessary parameters int aimingError = caster instanceof ISpellCaster ? ((ISpellCaster)caster).getAimingError(world.getDifficulty()) : WizardryUtilities.getDefaultAimingError(world.getDifficulty()); - projectile.aim(caster, target, baseRange * modifiers.get(WizardryItems.range_upgrade), aimingError); + projectile.aim(caster, target, calculateVelocity(projectile, modifiers, caster.getEyeHeight() + - (float)EntityMagicProjectile.LAUNCH_Y_OFFSET), aimingError); projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); if(projectile instanceof EntityBomb) ((EntityBomb)projectile).blastMultiplier = modifiers.get(WizardryItems.blast_upgrade); + addProjectileExtras(projectile, caster, modifiers); // Spawns the projectile in the world world.spawnEntity(projectile); } caster.swingArm(hand); - caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -132,4 +148,38 @@ public class SpellProjectile extends Spell { return false; } + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ + + if(!world.isRemote){ + // Creates a projectile from the supplied factory + T projectile = projectileFactory.apply(world); + // Sets the necessary parameters + projectile.setPosition(x, y, z); + Vec3i vec = direction.getDirectionVec(); + projectile.shoot(vec.getX(), vec.getY(), vec.getZ(), calculateVelocity(projectile, modifiers, + 0.375f), DISPENSER_INACCURACY); // 0.375 is the height of the hole in a dispenser + projectile.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + if(projectile instanceof EntityBomb) ((EntityBomb)projectile).blastMultiplier = modifiers.get(WizardryItems.blast_upgrade); + addProjectileExtras(projectile, null, modifiers); + // Spawns the projectile in the world + world.spawnEntity(projectile); + } + // This MUST be the coordinates of the actual dispenser, so we need to offset it + this.playSound(world, x - direction.getXOffset(), y - direction.getYOffset(), z - direction.getZOffset(), ticksInUse, duration, modifiers); + + return true; + } + + /** + * Called just before the projectile is spawned. Does nothing by default, but subclasses can override to call extra + * methods on the spawned projectile. This method is only called server-side so cannot be used to spawn particles directly. + * @param projectile The entity being spawned. + * @param caster The caster of this spell, or null if it was cast by a dispenser. + * @param modifiers The modifiers this spell was cast with. + */ + protected void addProjectileExtras(T projectile, @Nullable EntityLivingBase caster, SpellModifiers modifiers){ + // Subclasses can put spell-specific stuff here + } + } diff --git a/src/main/java/electroblob/wizardry/spell/SpellRay.java b/src/main/java/electroblob/wizardry/spell/SpellRay.java index 0ac28b72..1dc46232 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellRay.java +++ b/src/main/java/electroblob/wizardry/spell/SpellRay.java @@ -1,12 +1,8 @@ package electroblob.wizardry.spell; -import javax.annotation.Nullable; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; @@ -16,13 +12,14 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; -import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import javax.annotation.Nullable; + /** * Generic superclass for all spells which use a raytrace to do something and (optionally) spawn particles along that * trajectory. This is for both continuous ('stream') spells and non-continuous ('bolt') spells This allows all the @@ -30,111 +27,95 @@ import net.minecraft.world.World; * such must be subclassed to define what the spell actually does. This is because ray-like spells do a wider variety of * different things, so it does not make sense to define more specific functions in this class since they would be * redundant in the majority of cases. - *

    + *

    + * N.B. The three abstract methods in this class have a {@link Nullable} caster parameter (the caster is null when + * the spell is cast by a dispenser). When implementing these methods, be sure to check whether the caster is + * {@code null} and deal with it appropriately. + *

    + * Properties added by this type of spell: {@link Spell#RANGE} + *

    * By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastByNPCs()} - *

    - * By default, this type of spell requires a packet to be sent. {@link Spell#doesSpellRequirePacket()} + *

    + * By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastByDispensers()} + *

    + * By default, this type of spell requires a packet to be sent. {@link Spell#requiresPacket()} * * @author Electroblob * @since Wizardry 4.2 - * @see SpellStream */ public abstract class SpellRay extends Spell { - // TODO: Implement the 'aim assist' (borderSize) effect for rayTracing - /** The distance below the caster's eyes that the bolt particles start from. */ - private static final double Y_OFFSET = 0.4; - - /** The base range of this spell. */ - protected final double baseRange; - /** The sound that gets played when this spell is cast. */ - @Nullable - protected final SoundEvent sound; - - /** The volume of the sound played when this spell is cast. Defaults to 1. */ - protected float volume = 1; - /** The pitch of the sound played when this spell is cast. Defaults to 1. */ - protected float pitch = 1; - /** The pitch variation of the sound played when this spell is cast. Defaults to 0. */ - protected float pitchVariation = 0; + protected static final double Y_OFFSET = 0.25; + /** The distance between spawned particles. Defaults to 0.85. */ // 0.85 was chosen to keep it similar to the most common method used previously, which gave an effective spacing of // 10/12 = 0.8333 when the spell did not hit anything. protected double particleSpacing = 0.85; - /** The maximum dither (random position offset) for spawned particles. Defaults to 0.1. */ - protected double particleDither = 0.1; + /** The maximum jitter (random position offset) for spawned particles. Defaults to 0.1. */ + protected double particleJitter = 0.1; /** The velocity of spawned particles in the direction the caster is aiming, can be negative. Defaults to 0. */ protected double particleVelocity = 0; - /** Whether entities are ignored when raytracing. Defaults to false. */ - protected boolean ignoreEntities = false; + /** Whether living entities are ignored when raytracing. Defaults to false. */ + protected boolean ignoreLivingEntities = false; /** Whether liquids count as blocks when raytracing. Defaults to false. */ protected boolean hitLiquids = false; + /** Whether to ignore uncollidable blocks when raytracing. Defaults to true. */ + protected boolean ignoreUncollidables = true; /** The aim assist to use when raytracing. Defaults to 0. */ protected float aimAssist = 0; - public SpellRay(String name, Tier tier, Element element, SpellType type, int cost, int cooldown, boolean isContinuous, double baseRange, SoundEvent sound){ - this(Wizardry.MODID, name, tier, element, type, cost, cooldown, isContinuous, baseRange, sound); + public SpellRay(String name, boolean isContinuous, EnumAction action){ + this(Wizardry.MODID, name, isContinuous, action); } - public SpellRay(String modID, String name, Tier tier, Element element, SpellType type, int cost, int cooldown, boolean isContinuous, double baseRange, SoundEvent sound){ - super(modID, name, tier, element, type, cost, cooldown, EnumAction.NONE, isContinuous); - this.baseRange = baseRange; - this.sound = sound; + public SpellRay(String modID, String name, boolean isContinuous, EnumAction action){ + super(modID, name, action, isContinuous); + this.addProperties(RANGE); } - /** - * Sets the sound parameters for this spell. - * @param volume - * @param pitch - * @param pitchVariation - * @return The spell instance, allowing this method to be chained onto the constructor. - */ - public SpellRay soundValues(float volume, float pitch, float pitchVariation) { - this.volume = volume; - this.pitch = pitch; - this.pitchVariation = pitchVariation; - return this; - } + // Although this class is abstract, someone might instantiate one of its subclasses more than once to make two + // different spells, which may require different parameters. These methods allow such instances to neatly set any + // relevant parameters by chaining them onto the constructor. /** * Sets the distance between spawned particles. * @param particleSpacing The distance between particles in the ray effect. * @return The spell instance, allowing this method to be chained onto the constructor. */ - public SpellRay particleSpacing(double particleSpacing){ + public Spell particleSpacing(double particleSpacing){ this.particleSpacing = particleSpacing; return this; } /** - * Sets the maximum dither (random position offset) for spawned particles. - * @param particleDither The maximum dither for particles in the ray effect. + * Sets the maximum jitter (random position offset) for spawned particles. + * @param particleJitter The maximum jitter for particles in the ray effect. * @return The spell instance, allowing this method to be chained onto the constructor. */ - public SpellRay particleDither(double particleDither){ - this.particleDither = particleDither; + public Spell particleJitter(double particleJitter){ + this.particleJitter = particleJitter; return this; } /** - * Sets the velocity of spawned particles. + * Sets the velocity of spawned particles; usually used for continuous spells. * @param particleVelocity The velocity of spawned particles in the direction the caster is aiming, can be negative. * @return The spell instance, allowing this method to be chained onto the constructor. */ - public SpellRay particleVelocity(double particleVelocity){ + public Spell particleVelocity(double particleVelocity){ this.particleVelocity = particleVelocity; return this; } /** * Sets whether entities are ignored when raytracing. - * @param ignoreEntities Whether to ignore entities when raytracing. If this is true, the spell will pass through - * entities as if they weren't there. + * @param ignoreLivingEntities Whether to ignore living entities when raytracing. If this is true, the spell + * will pass through living entities as if they weren't there. * @return The spell instance, allowing this method to be chained onto the constructor. */ - public SpellRay ignoreEntities(boolean ignoreEntities){ - this.ignoreEntities = ignoreEntities; + public Spell ignoreLivingEntities(boolean ignoreLivingEntities){ + this.ignoreLivingEntities = ignoreLivingEntities; return this; } @@ -144,36 +125,47 @@ public abstract class SpellRay extends Spell { * liquids as if they weren't there. * @return The spell instance, allowing this method to be chained onto the constructor. */ - public SpellRay hitLiquids(boolean hitLiquids){ + public Spell hitLiquids(boolean hitLiquids){ this.hitLiquids = hitLiquids; return this; } + + /** + * Sets whether uncollidable blocks are ignored when raytracing. + * @param ignoreUncollidables Whether to hit uncollidable blocks when raytracing. If this is true, the spell will + * pass through uncollidable blocks as if they weren't there. + * @return The spell instance, allowing this method to be chained onto the constructor. + */ + public Spell ignoreUncollidables(boolean ignoreUncollidables){ + this.ignoreUncollidables = ignoreUncollidables; + return this; + } /** * Sets the aim assist to use when raytracing. - * @param particleVelocity The aim assist to use when raytracing. See {@link WizardryUtilities#rayTrace(World, Vec3d, - * Vec3d, float, boolean, Class, java.util.function.Predicate)} for more details. + * @param aimAssist The aim assist to use when raytracing. See {@link RayTracer#rayTrace(World, Vec3d, Vec3d, float, boolean, boolean, boolean, Class, java.util.function.Predicate)} for more details. * @return The spell instance, allowing this method to be chained onto the constructor. */ - public SpellRay aimAssist(float aimAssist){ + public Spell aimAssist(float aimAssist){ this.aimAssist = aimAssist; return this; } @Override public boolean canBeCastByNPCs(){ return true; } + + @Override public boolean canBeCastByDispensers() { return true; } // Finally everything in here is standardised and written in a form that's actually readable - it was long overdue! @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ Vec3d look = caster.getLookVec(); - Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight() - Y_OFFSET, - caster.posZ); + Vec3d origin = new Vec3d(caster.posX, caster.getEntityBoundingBox().minY + caster.getEyeHeight() - Y_OFFSET, caster.posZ); if(!shootSpell(world, origin, look, caster, ticksInUse, modifiers)) return false; - if(!isContinuous) caster.swingArm(hand); // Bit of a dirty fix but I don't think it'll be a problem! - if(sound != null) WizardryUtilities.playSoundAtPlayer(caster, sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + if(casterSwingsArm(world, caster, hand, ticksInUse, modifiers)) caster.swingArm(hand); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } @@ -187,7 +179,8 @@ public abstract class SpellRay extends Spell { if(target != null){ - if(!ignoreEntities && onEntityHit(world, target, caster, ticksInUse, modifiers)){ + if((!ignoreLivingEntities || !WizardryUtilities.isLiving(target)) + && onEntityHit(world, target, null, caster, origin, ticksInUse, modifiers)){ direction = new Vec3d(target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ) .subtract(origin); @@ -203,7 +196,7 @@ public abstract class SpellRay extends Spell { // This works as if the NPC had actually aimed at the floor beneath the target, so it needs to check // that the block is not air and (optionally) not a liquid. if(!world.isAirBlock(pos) && (!world.getBlockState(pos).getMaterial().isLiquid() || hitLiquids) - && onBlockHit(world, pos, EnumFacing.UP, caster, ticksInUse, modifiers)){ + && onBlockHit(world, pos, EnumFacing.UP, null, caster, origin, ticksInUse, modifiers)){ direction = new Vec3d(x + 0.5, y + 1, z + 0.5).subtract(origin); flag = true; @@ -214,118 +207,196 @@ public abstract class SpellRay extends Spell { // Wizards don't miss... yet if(!flag) return false; - // Particle spawning (direction should never be null at this point but no harm in checking) - if(world.isRemote && direction != null){ - spawnParticleRay(world, origin, direction.normalize(), direction.lengthVector()); + // Particle spawning + if(world.isRemote){ + spawnParticleRay(world, origin, direction.normalize(), caster, direction.length()); } - - if(!isContinuous) caster.swingArm(hand); // Bit of a dirty fix but I don't think it'll be a problem! - if(sound != null) caster.playSound(sound, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f)); + + if(casterSwingsArm(world, caster, hand, ticksInUse, modifiers)) caster.swingArm(hand); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } - /** Player and dispenser casting are almost identical so this takes care of the shared stuff. */ - private boolean shootSpell(World world, Vec3d origin, Vec3d direction, @Nullable EntityPlayer caster, int ticksInUse, SpellModifiers modifiers){ + @Override + public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){ - double range = baseRange * modifiers.get(WizardryItems.range_upgrade); + Vec3d vec = new Vec3d(direction.getDirectionVec()); + Vec3d origin = new Vec3d(x, y, z); + + if(!shootSpell(world, origin, vec, null, ticksInUse, modifiers)) return false; + // This MUST be the coordinates of the actual dispenser, so we need to offset it + this.playSound(world, x - direction.getXOffset(), y - direction.getYOffset(), z - direction.getZOffset(), ticksInUse, duration, modifiers); + return true; + } + + /** + * Hook allowing subclasses to override the default range calculation on a per-cast basis. For example, grapple + * overrides this to change the range based on casting time so that its vine attaches to entities/blocks at the + * correct point and moves them accordingly. + * + * @param world The world in which the spell is being cast. + * @param origin A vector representing the coordinates of the origin point of the spell. + * @param direction A normalised vector representing the direction in which the spell is being cast. + * @param caster The entity casting the spell, or null if the spell is being cast from a dispenser. + * @param ticksInUse The number of ticks the spell has already been cast for. For all non-continuous spells, + * this is 0 and is not used. + * @param modifiers The SpellModifiers object with which this spell is being cast. + * @return The range to be used for this particular casting of the spell. + */ + // Technically you could alter the range in the SpellModifiers object by overriding the cast method but that + // would be a bit of a hack since it's not really what spell modifiers are for. + protected double getRange(World world, Vec3d origin, Vec3d direction, @Nullable EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + return getProperty(RANGE).doubleValue() * modifiers.get(WizardryItems.range_upgrade); + } + + /** + * Hook allowing subclasses to determine whether the caster swings their arm when casting the spell. By default, + * returns false for continuous spells and true for all others. + * + * @param world A reference to the world object. This is for convenience, you can also use caster.world. + * @param caster The EntityLivingBase that cast the spell. + * @param hand The hand that is holding the item used to cast the spell. If no item was used, this will be the + * main hand. + * @param ticksInUse The number of ticks the spell has already been cast for. For all non-continuous spells, this is + * 0 and is not used. For continuous spells, it is passed in as the maximum use duration of the item minus + * the count parameter in onUsingItemTick and therefore it increases by 1 each tick. + * @return True if the caster should swing their arm when casting this spell, false if not. + */ + protected boolean casterSwingsArm(World world, EntityLivingBase caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + return !this.isContinuous; + } + + /** Player and dispenser casting are almost identical so this takes care of the shared stuff. This is mainly for internal use. */ + protected boolean shootSpell(World world, Vec3d origin, Vec3d direction, @Nullable EntityPlayer caster, int ticksInUse, SpellModifiers modifiers){ + + double range = getRange(world, origin, direction, caster, ticksInUse, modifiers); Vec3d endpoint = origin.add(direction.scale(range)); - // The first method will hit the first block it touches, passing through entities as if they weren't there. - // The second method will hit the first thing it touches, whether that's a block or an entity. This method now - // returns the exact hit position for entities as well as blocks. - RayTraceResult rayTrace = WizardryUtilities.rayTrace(world, origin, endpoint, aimAssist, hitLiquids, Entity.class, e -> e == caster); + // Change the filter depending on whether living entities are ignored or not + RayTraceResult rayTrace = RayTracer.rayTrace(world, origin, endpoint, aimAssist, hitLiquids, + ignoreUncollidables, false, Entity.class, ignoreLivingEntities ? WizardryUtilities::isLiving + : RayTracer.ignoreEntityFilter(caster)); boolean flag = false; - + if(rayTrace != null){ // Doesn't matter which way round these are, they're mutually exclusive if(rayTrace.typeOfHit == RayTraceResult.Type.ENTITY){ // Do whatever the spell does when it hits an entity - flag = onEntityHit(world, rayTrace.entityHit, caster, ticksInUse, modifiers); + flag = onEntityHit(world, rayTrace.entityHit, rayTrace.hitVec, caster, origin, ticksInUse, modifiers); // If the spell succeeded, clip the particles to the correct distance so they don't go through the entity if(flag) range = origin.distanceTo(rayTrace.hitVec); }else if(rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ // Do whatever the spell does when it hits an block - flag = onBlockHit(world, rayTrace.getBlockPos(), rayTrace.sideHit, caster, ticksInUse, modifiers); - // If the spell succeeded, clip the particles to the correct distance so they don't go through the block - if(flag) range = origin.distanceTo(rayTrace.hitVec); + flag = onBlockHit(world, rayTrace.getBlockPos(), rayTrace.sideHit, rayTrace.hitVec, caster, origin, ticksInUse, modifiers); + // Clip the particles to the correct distance so they don't go through the block + // Unlike with entities, this is done regardless of whether the spell succeeded, since no spells go + // through blocks (and in fact, even the ray tracer itself doesn't do that) + range = origin.distanceTo(rayTrace.hitVec); } } // If flag is false, either the spell missed or the relevant entity/block hit method returned false - if(!flag && !onMiss(world, caster, ticksInUse, modifiers)) return false; + if(!flag && !onMiss(world, caster, origin, direction, ticksInUse, modifiers)) return false; // Particle spawning if(world.isRemote){ - spawnParticleRay(world, origin, direction, range); + spawnParticleRay(world, origin, direction, caster, range); } return true; } - // Private helper method, no-one will need to override it since it's pretty much the whole point of this class. - private void spawnParticleRay(World world, Vec3d origin, Vec3d direction, double distance){ - - Vec3d velocity = direction.scale(particleVelocity); - - for(double d = particleSpacing; d <= distance; d += particleSpacing){ - double x = origin.x + d*direction.x + particleDither * (world.rand.nextDouble()*2 - 1); - double y = origin.y + d*direction.y + particleDither * (world.rand.nextDouble()*2 - 1); - double z = origin.z + d*direction.z + particleDither * (world.rand.nextDouble()*2 - 1); - spawnParticle(world, x, y, z, velocity.x, velocity.y, velocity.z); - } - } // The exact behaviour of the returned values of the following three methods can be a little confusing. Normally, // either onEntityHit or onBlockHit (or both) will return true when the spell succeeded in hitting the block or // entity, and false if not (note that those two methods are mutually exclusive). If false is returned, onMiss will - // be called - onMiss will never be called if either of the other methods returns true. + // be called - if either of the other methods returns true, onMiss will only be called for a complete miss. /** - * Called when the spell hits an entity. Will never be called if ignoreEntities is true. + * Called when the spell hits an entity. Will never be called if ignoreLivingEntities is true. * @param world The world the entity is in. * @param target The entity that was hit. - * @param caster The caster of this spell, or null if this spell was cast from a dispenser. + * @param hit A vector representing the exact position at which the spell first hit the entity. Usually used for + * particle spawning. + * @param caster The caster of this spell, or null if this spell was cast from a dispenser. N.B. It is strongly + * recommended that the origin parameter is used instead of taking the caster's position directly. + * @param origin The position at which this spell originated. If the caster is not null, this will be at the caster's + * eyes. * @param ticksInUse The number of ticks the spell has already been cast for (used only for continuous spells). * @param modifiers The modifiers this spell was cast with. * @return True to continue with spell casting and spawn particles, false to trigger a miss (N.B. you will need to - * return false from {@link SpellRay#onMiss(World, EntityLivingBase, int, SpellModifiers)} if a miss should not consume - * mana). + * return false from {@link SpellRay#onMiss(World, EntityLivingBase, Vec3d, Vec3d, int, SpellModifiers)} if a miss + * should not consume mana). Returning false from this method will make it look as if the spell passed right + * through it, so if a spell spawns particles when it misses this method should return true even for non-living + * entities. */ - protected abstract boolean onEntityHit(World world, Entity target, @Nullable EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers); + protected abstract boolean onEntityHit(World world, Entity target, Vec3d hit, @Nullable EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers); /** * Called when the spell hits a block. * @param world The world the block is in. * @param pos The BlockPos of the block that was hit. * @param side The side of the block that was hit. + * @param hit A vector representing the exact position at which the spell first hit the block. Usually used for + * particle spawning. * @param caster The caster of this spell, or null if this spell was cast from a dispenser. + * @param origin The position at which this spell originated. If the caster is not null, this will be at the caster's + * eyes. * @param ticksInUse The number of ticks the spell has already been cast for (used only for continuous spells). * @param modifiers The modifiers this spell was cast with. * @return True to continue with spell casting and spawn particles, false to trigger a miss (N.B. you will need to - * return false from {@link SpellRay#onMiss(World, EntityLivingBase, int, SpellModifiers)} if a miss should not consume + * return false from {@link SpellRay#onMiss(World, EntityLivingBase, Vec3d, Vec3d, int, SpellModifiers)} if a miss should not consume * mana). */ - protected abstract boolean onBlockHit(World world, BlockPos pos, EnumFacing side, @Nullable EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers); + protected abstract boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, @Nullable EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers); /** * Called when the spell does not hit anything or when the spell hits something it has no effect on. Most of the time - * this will just return true or false, but some spells may, for example, display a chat readout. + * this will just return true or false, but some spells may, for example, display a chat readout or spawn custom + * particles. It is worth noting that this can affect how easy the spell is to identify. * @param world The world the spell is in. * @param caster The caster of this spell, or null if this spell was cast from a dispenser. + * @param origin The position at which this spell originated. If the caster is not null, this will be at the caster's + * eyes. + * @param direction A normalised vector in the direction this spell was cast (useful for custom particle effects). * @param ticksInUse The number of ticks the spell has already been cast for (used only for continuous spells). * @param modifiers The modifiers this spell was cast with. * @return True to continue with spell casting and spawn particles, false to cause the spell to fail. */ - protected abstract boolean onMiss(World world, @Nullable EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers); + protected abstract boolean onMiss(World world, @Nullable EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers); + + /** + * Highest-level particle spawning method, only called client-side. 'Normal' subclasses should not need to override + * this method; by default it spawns a line of particles, applying jitter and then calling + * {@link SpellRay#spawnParticle(World, double, double, double, double, double, double)} at each point. Override to replace this with + * an entirely custom particle effect - this is done by a few spells in the main mod to spawn beam-type particles. + * @param world The world in which to spawn the particles. + * @param origin A vector representing the start point of the line of particles. + * @param direction A normalised vector representing the direction of the line of particles. + * @param caster The entity that cast this spell, or null if it was cast by a dispenser. + * @param distance The length of the line of particles, already set to the appropriate distance based on the spell's + */ + // The caster argument is only really useful for spawning targeted particles continuously + protected void spawnParticleRay(World world, Vec3d origin, Vec3d direction, EntityLivingBase caster, double distance){ + + Vec3d velocity = direction.scale(particleVelocity); + + for(double d = particleSpacing; d <= distance; d += particleSpacing){ + double x = origin.x + d*direction.x + particleJitter * (world.rand.nextDouble()*2 - 1); + double y = origin.y + d*direction.y + particleJitter * (world.rand.nextDouble()*2 - 1); + double z = origin.z + d*direction.z + particleJitter * (world.rand.nextDouble()*2 - 1); + spawnParticle(world, x, y, z, velocity.x, velocity.y, velocity.z); + } + } /** * Called at each point along the spell trajectory to spawn one or more particles at that point. Only called * client-side. Does nothing by default. * @param world The world in which to spawn the particle. - * @param x The x-coordinate to spawn the particle at, with dither already applied. - * @param y The y-coordinate to spawn the particle at, with dither already applied. - * @param z The z-coordinate to spawn the particle at, with dither already applied. + * @param x The x-coordinate to spawn the particle at, with jitter already applied. + * @param y The y-coordinate to spawn the particle at, with jitter already applied. + * @param z The z-coordinate to spawn the particle at, with jitter already applied. * @param vx The x velocity to spawn the particle with. Usually this is only non-zero for continuous spells. * @param vy The y velocity to spawn the particle with. Usually this is only non-zero for continuous spells. * @param vz The z velocity to spawn the particle with. Usually this is only non-zero for continuous spells. diff --git a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java index 5166d9ba..9feaca7d 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java @@ -1,15 +1,11 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.monster.EntityIronGolem; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; @@ -18,19 +14,24 @@ import net.minecraft.world.World; public class SummonIronGolem extends Spell { public SummonIronGolem(){ - super("summon_iron_golem", Tier.MASTER, Element.SORCERY, SpellType.MINION, 175, 400, EnumAction.BOW, false); + super("summon_iron_golem", EnumAction.BOW, false); + addProperties(SpellMinion.SUMMON_RADIUS); + soundValues(1, 1.1f, 0.2f); } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, getProperty(SpellMinion.SUMMON_RADIUS).intValue(), + getProperty(SpellMinion.SUMMON_RADIUS).intValue()); + if(pos == null) return false; if(!world.isRemote){ EntityIronGolem golem = new EntityIronGolem(world); golem.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + golem.setPlayerCreated(true); world.spawnEntity(golem); }else{ @@ -43,7 +44,7 @@ public class SummonIronGolem extends Spell { } } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SPAWN, 1, 1 + 0.2f * world.rand.nextFloat()); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java b/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java index 8dac0d1c..46f58165 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java +++ b/src/main/java/electroblob/wizardry/spell/SummonShadowWraith.java @@ -1,16 +1,13 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntityShadowWraith; -import net.minecraft.init.SoundEvents; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class SummonShadowWraith extends SpellMinion { public SummonShadowWraith(){ - super("summon_shadow_wraith", Tier.MASTER, Element.NECROMANCY, 100, 400, EntityShadowWraith::new, 600, SoundEvents.ENTITY_WITHER_AMBIENT); + super("summon_shadow_wraith", EntityShadowWraith::new); this.soundValues(1, 1.1f, 0.1f); } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java b/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java index 4bec5e60..095be078 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSkeleton.java @@ -1,24 +1,36 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntitySkeletonMinion; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.entity.living.EntityStrayMinion; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; public class SummonSkeleton extends SpellMinion { public SummonSkeleton(){ - super("summon_skeleton", Tier.APPRENTICE, Element.NECROMANCY, 15, 50, EntitySkeletonMinion::new, 600, WizardrySounds.SPELL_SUMMONING); + super("summon_skeleton", EntitySkeletonMinion::new); this.soundValues(7, 0.6f, 0); } - + @Override - protected void addMinionExtras(EntitySkeletonMinion minion, EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){ + protected EntitySkeletonMinion createMinion(World world, EntityLivingBase caster, SpellModifiers modifiers){ + if(caster instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)caster, WizardryItems.charm_minion_variants)){ + return new EntityStrayMinion(world); + }else{ + return super.createMinion(world, caster, modifiers); + } + } + + @Override + protected void addMinionExtras(EntitySkeletonMinion minion, BlockPos pos, EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){ minion.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.BOW)); minion.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java b/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java index f7fb9c4c..72ecd26f 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSkeletonLegion.java @@ -1,26 +1,36 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.EntitySkeletonMinion; +import electroblob.wizardry.entity.living.EntityStrayMinion; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; -import net.minecraft.init.SoundEvents; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; public class SummonSkeletonLegion extends SpellMinion { public SummonSkeletonLegion(){ - super("summon_skeleton_legion", Tier.MASTER, Element.NECROMANCY, 100, 400, EntitySkeletonMinion::new, 1200, SoundEvents.ENTITY_WITHER_SPAWN); + super("summon_skeleton_legion", EntitySkeletonMinion::new); this.soundValues(1, 1.1f, 0.1f); - this.quantity(3); - this.range(3); } - + @Override - protected void addMinionExtras(EntitySkeletonMinion minion, EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){ + protected EntitySkeletonMinion createMinion(World world, EntityLivingBase caster, SpellModifiers modifiers){ + if(caster instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)caster, WizardryItems.charm_minion_variants)){ + return new EntityStrayMinion(world); + }else{ + return super.createMinion(world, caster, modifiers); + } + } + + @Override + protected void addMinionExtras(EntitySkeletonMinion minion, BlockPos pos, EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){ if(alreadySpawned % 2 == 0){ // Archers diff --git a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java index 3be56349..2f77947c 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java @@ -1,9 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; @@ -18,7 +14,9 @@ import net.minecraft.world.World; public class SummonSnowGolem extends Spell { public SummonSnowGolem(){ - super("summon_snow_golem", Tier.APPRENTICE, Element.ICE, SpellType.MINION, 15, 20, EnumAction.BOW, false); + super("summon_snow_golem", EnumAction.BOW, false); + this.soundValues(1, 1, 0.4f); + addProperties(SpellMinion.SUMMON_RADIUS); } @Override @@ -43,7 +41,7 @@ public class SummonSnowGolem extends Spell { } } - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7f, 1 + 0.4f * world.rand.nextFloat()); + playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java b/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java index a256d880..a9f02984 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSpiritHorse.java @@ -1,53 +1,83 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.IStoredVariable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.entity.living.EntitySpiritHorse; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.WizardryUtilities.Operations; +import net.minecraft.entity.Entity; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.ai.attributes.IAttribute; +import net.minecraft.entity.passive.AbstractHorse; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; + +import java.util.UUID; public class SummonSpiritHorse extends Spell { + /** The string identifier for the potency attribute modifier. */ + private static final String POTENCY_ATTRIBUTE_MODIFIER = "potency"; + + private static final IAttribute JUMP_STRENGTH; + // Why is this protected? Doesn't that defeat the point of the attribute system? + static { + // Great, now I have to reflect into this class too. + JUMP_STRENGTH = ObfuscationReflectionHelper.getPrivateValue(AbstractHorse.class, null, "field_110271_bv"); + } + + public static final IStoredVariable UUID_KEY = IStoredVariable.StoredVariable.ofUUID("spiritHorseUUID", Persistence.ALWAYS); + public SummonSpiritHorse(){ - super("summon_spirit_horse", Tier.ADVANCED, Element.EARTH, SpellType.MINION, 50, 150, EnumAction.BOW, false); + super("summon_spirit_horse", EnumAction.BOW, false); + addProperties(SpellMinion.SUMMON_RADIUS); + soundValues(0.7f, 1.2f, 0.4f); + WizardData.registerStoredVariables(UUID_KEY); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - WizardData properties = WizardData.get(caster); + WizardData data = WizardData.get(caster); - if(!properties.hasSpiritHorse){ - if(!world.isRemote){ + if(!world.isRemote){ - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; + Entity oldHorse = WizardryUtilities.getEntityByUUID(world, data.getVariable(UUID_KEY)); - EntitySpiritHorse horse = new EntitySpiritHorse(world); - horse.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - horse.setTamedBy(caster); - horse.setHorseSaddled(true); - world.spawnEntity(horse); - } - properties.hasSpiritHorse = true; - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; + if(oldHorse != null) oldHorse.setDead(); + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntitySpiritHorse horse = new EntitySpiritHorse(world); + horse.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + horse.setTamedBy(caster); + horse.setHorseSaddled(true); + world.spawnEntity(horse); + + horse.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).applyModifier( + new AttributeModifier(POTENCY_ATTRIBUTE_MODIFIER, modifiers.get(SpellModifiers.POTENCY) - 1, Operations.MULTIPLY_CUMULATIVE)); + // Jump strength increases ridiculously fast, so we're reducing the effect of the modifier by 75% + horse.getEntityAttribute(JUMP_STRENGTH).applyModifier(new AttributeModifier(POTENCY_ATTRIBUTE_MODIFIER, + modifiers.amplified(SpellModifiers.POTENCY, 0.25f) - 1, Operations.MULTIPLY_CUMULATIVE)); + + data.setVariable(UUID_KEY, horse.getUniqueID()); } - return false; + + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; } } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java b/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java index f3896c7f..f4a8d6eb 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSpiritWolf.java @@ -1,53 +1,75 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.IStoredVariable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; import electroblob.wizardry.entity.living.EntitySpiritWolf; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; +import electroblob.wizardry.util.WizardryUtilities.Operations; +import net.minecraft.entity.Entity; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import java.util.UUID; + public class SummonSpiritWolf extends Spell { + /** The string identifier for the potency attribute modifier. */ + private static final String POTENCY_ATTRIBUTE_MODIFIER = "potency"; + + public static final IStoredVariable UUID_KEY = IStoredVariable.StoredVariable.ofUUID("spiritWolfUUID", Persistence.ALWAYS); + public SummonSpiritWolf(){ - super("summon_spirit_wolf", Tier.APPRENTICE, Element.EARTH, SpellType.MINION, 25, 100, EnumAction.BOW, false); + super("summon_spirit_wolf", EnumAction.BOW, false); + addProperties(SpellMinion.SUMMON_RADIUS); + soundValues(0.7f, 1.2f, 0.4f); + WizardData.registerStoredVariables(UUID_KEY); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - WizardData properties = WizardData.get(caster); + WizardData data = WizardData.get(caster); - if(!properties.hasSpiritWolf){ - if(!world.isRemote){ + if(!world.isRemote){ - BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); - if(pos == null) return false; + Entity oldWolf = WizardryUtilities.getEntityByUUID(world, data.getVariable(UUID_KEY)); - EntitySpiritWolf wolf = new EntitySpiritWolf(world); - wolf.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - wolf.setTamed(true); - wolf.setOwnerId(caster.getUniqueID()); - world.spawnEntity(wolf); - } - properties.hasSpiritWolf = true; - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, - world.rand.nextFloat() * 0.4F + 1.0F); - return true; + if(oldWolf != null) oldWolf.setDead(); + + BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, 2, 4); + if(pos == null) return false; + + EntitySpiritWolf wolf = new EntitySpiritWolf(world); + wolf.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + wolf.setTamed(true); + wolf.setOwnerId(caster.getUniqueID()); + // Potency gives the wolf more strength AND more health + wolf.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).applyModifier( + new AttributeModifier(POTENCY_ATTRIBUTE_MODIFIER, modifiers.get(SpellModifiers.POTENCY) - 1, Operations.MULTIPLY_CUMULATIVE)); + wolf.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).applyModifier( + new AttributeModifier(POTENCY_ATTRIBUTE_MODIFIER, modifiers.amplified(SpellModifiers.POTENCY, 1.5f) - 1, Operations.MULTIPLY_CUMULATIVE)); + wolf.setHealth(wolf.getMaxHealth()); + + world.spawnEntity(wolf); + + data.setVariable(UUID_KEY, wolf.getUniqueID()); } - return false; + + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; + } } diff --git a/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java b/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java new file mode 100644 index 00000000..d452c83c --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonWitherSkeleton.java @@ -0,0 +1,24 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Items; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; + +public class SummonWitherSkeleton extends SpellMinion { + + public SummonWitherSkeleton(){ + super("summon_wither_skeleton", EntityWitherSkeletonMinion::new); + this.soundValues(7, 0.6f, 0); + } + + @Override + protected void addMinionExtras(EntityWitherSkeletonMinion minion, BlockPos pos, EntityLivingBase caster, SpellModifiers modifiers, int alreadySpawned){ + minion.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.STONE_SWORD)); + minion.setDropChance(EntityEquipmentSlot.MAINHAND, 0.0f); + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/SummonZombie.java b/src/main/java/electroblob/wizardry/spell/SummonZombie.java new file mode 100644 index 00000000..1663b329 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/SummonZombie.java @@ -0,0 +1,28 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.entity.living.EntityHuskMinion; +import electroblob.wizardry.entity.living.EntityZombieMinion; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +public class SummonZombie extends SpellMinion { + + public SummonZombie(){ + super("summon_zombie", EntityZombieMinion::new); + this.soundValues(7, 0.6f, 0); + } + + @Override + protected EntityZombieMinion createMinion(World world, EntityLivingBase caster, SpellModifiers modifiers){ + if(caster instanceof EntityPlayer && ItemArtefact.isArtefactActive((EntityPlayer)caster, WizardryItems.charm_minion_variants)){ + return new EntityHuskMinion(world); + }else{ + return super.createMinion(world, caster, modifiers); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/spell/Telekinesis.java b/src/main/java/electroblob/wizardry/spell/Telekinesis.java index 13dbe35c..9d97aaa6 100644 --- a/src/main/java/electroblob/wizardry/spell/Telekinesis.java +++ b/src/main/java/electroblob/wizardry/spell/Telekinesis.java @@ -1,38 +1,36 @@ package electroblob.wizardry.spell; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Telekinesis extends SpellRay { public Telekinesis(){ - super("telekinesis", Tier.BASIC, Element.SORCERY, SpellType.UTILITY, 5, 5, false, 8, WizardrySounds.SPELL_CONJURATION); + super("telekinesis", false, EnumAction.NONE); } - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(target instanceof EntityItem){ - target.motionX = (caster.posX - target.posX) / 6; - target.motionY = (caster.posY + caster.getEyeHeight() - target.posY) / 6; - target.motionZ = (caster.posZ - target.posZ) / 6; + target.motionX = (origin.x - target.posX) / 6; + target.motionY = (origin.y - target.posY) / 6; + target.motionZ = (origin.z - target.posZ) / 6; return true; }else if(target instanceof EntityPlayer && (Wizardry.settings.telekineticDisarmament || !(caster instanceof EntityPlayer))){ @@ -46,8 +44,8 @@ public class Telekinesis extends SpellRay { if(!world.isRemote){ EntityItem item = player.entityDropItem(player.getHeldItemMainhand(), 0); // Makes the item move towards the caster - item.motionX = (caster.posX - player.posX) / 20; - item.motionZ = (caster.posZ - player.posZ) / 20; + item.motionX = (origin.x - player.posX) / 20; + item.motionZ = (origin.z - player.posZ) / 20; } player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY); @@ -60,7 +58,7 @@ public class Telekinesis extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(caster instanceof EntityPlayer){ @@ -76,7 +74,7 @@ public class Telekinesis extends SpellRay { } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java index 06ca648b..05e7884f 100644 --- a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java +++ b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java @@ -1,18 +1,9 @@ package electroblob.wizardry.spell; -import java.util.List; - -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.MagicDamage; +import electroblob.wizardry.util.*; import electroblob.wizardry.util.MagicDamage.DamageType; -import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; -import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.effect.EntityLightningBolt; @@ -20,12 +11,31 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import java.util.List; + public class Thunderstorm extends Spell { + public static final String LIGHTNING_BOLTS = "lightning_bolts"; + + public static final String SECONDARY_DAMAGE = "secondary_damage"; + public static final String TERTIARY_DAMAGE = "tertiary_damage"; + + public static final String SECONDARY_RANGE = "secondary_range"; + public static final String TERTIARY_RANGE = "tertiary_range"; + + public static final String SECONDARY_MAX_TARGETS = "secondary_max_targets"; + public static final String TERTIARY_MAX_TARGETS = "tertiary_max_targets"; // This is per secondary target + + private static final float CENTRE_RADIUS_FRACTION = 0.5f; + public Thunderstorm(){ - super("thunderstorm", Tier.MASTER, Element.LIGHTNING, SpellType.ATTACK, 100, 250, EnumAction.BOW, false); + super("thunderstorm", EnumAction.BOW, false); + this.soundValues(1, 1.7f, 0.2f); + addProperties(EFFECT_RADIUS, LIGHTNING_BOLTS, SECONDARY_DAMAGE, TERTIARY_DAMAGE, SECONDARY_RANGE, + TERTIARY_RANGE, SECONDARY_MAX_TARGETS, TERTIARY_MAX_TARGETS); } @Override @@ -43,77 +53,80 @@ public class Thunderstorm extends Spell { if(world.canBlockSeeSky(new BlockPos(caster))){ - for(int r = 0; r < 10; r++){ + double maxRadius = getProperty(EFFECT_RADIUS).doubleValue(); - double radius = 4 + world.rand.nextDouble() * 6 * modifiers.get(WizardryItems.blast_upgrade); - double angle = world.rand.nextDouble() * Math.PI * 2; + for(int i = 0; i < getProperty(LIGHTNING_BOLTS).intValue(); i++){ - double x = caster.posX + radius * Math.cos(angle); - double z = caster.posZ + radius * Math.sin(angle); - double y = WizardryUtilities.getNearestFloorLevel(world, new BlockPos(x, caster.posY, z), 10); + double radius = maxRadius * CENTRE_RADIUS_FRACTION + world.rand.nextDouble() * maxRadius + * (1 - CENTRE_RADIUS_FRACTION) * modifiers.get(WizardryItems.blast_upgrade); + float angle = world.rand.nextFloat() * (float)Math.PI * 2; - if(!world.isRemote){ - EntityLightningBolt entitylightning = new EntityLightningBolt(world, x, y, z, false); - world.addWeatherEffect(entitylightning); - } + double x = caster.posX + radius * MathHelper.cos(angle); + double z = caster.posZ + radius * MathHelper.sin(angle); + Integer y = WizardryUtilities.getNearestFloor(world, new BlockPos(x, caster.posY, z), (int)maxRadius); - // Code for eventhandler recognition; for achievements and such like. Left in for future use. - // NBTTagCompound entityNBT = entitylightning.getEntityData(); - // entityNBT.setInteger("summoningPlayer", entityplayer.entityId); + if(y != null){ - // Secondary chaining effect - double seekerRange = 10.0d; + if(!world.isRemote){ + EntityLightningBolt entitylightning = new EntityLightningBolt(world, x, y, z, false); + world.addWeatherEffect(entitylightning); + } - List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, x, - y + 1, z, world); + // Code for eventhandler recognition; for achievements and such like. Left in for future use. + // NBTTagCompound entityNBT = entitylightning.getEntityData(); + // entityNBT.setInteger("summoningPlayer", entityplayer.entityId); - // For this spell there is no limit to the amount of secondary targets! - for(EntityLivingBase secondaryTarget : secondaryTargets){ + // Secondary chaining effect + List secondaryTargets = WizardryUtilities.getEntitiesWithinRadius( + getProperty(SECONDARY_RANGE).doubleValue(), x, y + 1, z, world); - if(WizardryUtilities.isValidTarget(caster, secondaryTarget)){ + for(int j = 0; j < Math.min(secondaryTargets.size(), getProperty(SECONDARY_MAX_TARGETS).intValue()); j++){ - if(world.isRemote){ + EntityLivingBase secondaryTarget = secondaryTargets.get(j); - ParticleBuilder.create(Type.LIGHTNING).pos(x, y, z).target(secondaryTarget).spawn(world); - - ParticleBuilder.spawnShockParticles(world, secondaryTarget.posX, - secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2, - secondaryTarget.posZ); - } + if(AllyDesignationSystem.isValidTarget(caster, secondaryTarget)){ - secondaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, - world.rand.nextFloat() * 0.4F + 1.5F); + if(world.isRemote){ - secondaryTarget.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 10.0f * modifiers.get(SpellModifiers.POTENCY)); + ParticleBuilder.create(Type.LIGHTNING).pos(x, y, z).target(secondaryTarget).spawn(world); - // Tertiary chaining effect + ParticleBuilder.spawnShockParticles(world, secondaryTarget.posX, + secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2, + secondaryTarget.posZ); + } - List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, - secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, - secondaryTarget.posZ, world); + playSound(world, secondaryTarget, 0, -1, modifiers); - for(int j = 0; j < Math.min(tertiaryTargets.size(), 3); j++){ + secondaryTarget.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), + getProperty(SECONDARY_DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); - EntityLivingBase tertiaryTarget = (EntityLivingBase)tertiaryTargets.get(j); + // Tertiary chaining effect - if(!secondaryTargets.contains(tertiaryTarget) - && WizardryUtilities.isValidTarget(caster, tertiaryTarget)){ + List tertiaryTargets = WizardryUtilities.getEntitiesWithinRadius( + getProperty(TERTIARY_RANGE).doubleValue(), secondaryTarget.posX, + secondaryTarget.posY + secondaryTarget.height / 2, secondaryTarget.posZ, world); - if(world.isRemote){ - ParticleBuilder.create(Type.LIGHTNING).entity(secondaryTarget) - .pos(0, secondaryTarget.height/2, 0).target(tertiaryTarget).spawn(world); - ParticleBuilder.spawnShockParticles(world, tertiaryTarget.posX, - tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2, - tertiaryTarget.posZ); + for(int k = 0; k < Math.min(tertiaryTargets.size(), getProperty(TERTIARY_MAX_TARGETS).intValue()); k++){ + + EntityLivingBase tertiaryTarget = tertiaryTargets.get(k); + + if(!secondaryTargets.contains(tertiaryTarget) + && AllyDesignationSystem.isValidTarget(caster, tertiaryTarget)){ + + if(world.isRemote){ + ParticleBuilder.create(Type.LIGHTNING).entity(secondaryTarget) + .pos(0, secondaryTarget.height / 2, 0).target(tertiaryTarget).spawn(world); + ParticleBuilder.spawnShockParticles(world, tertiaryTarget.posX, + tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2, + tertiaryTarget.posZ); + } + + playSound(world, tertiaryTarget, 0, -1, modifiers); + + tertiaryTarget.attackEntityFrom( + MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), + getProperty(TERTIARY_DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); } - - tertiaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, - world.rand.nextFloat() * 0.4F + 1.5F); - - tertiaryTarget.attackEntityFrom( - MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), - 8.0f * modifiers.get(SpellModifiers.POTENCY)); } } } diff --git a/src/main/java/electroblob/wizardry/spell/Tornado.java b/src/main/java/electroblob/wizardry/spell/Tornado.java index 166b071e..f5045b05 100644 --- a/src/main/java/electroblob/wizardry/spell/Tornado.java +++ b/src/main/java/electroblob/wizardry/spell/Tornado.java @@ -1,23 +1,25 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.construct.EntityTornado; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.EnumAction; +import net.minecraft.util.EnumFacing; public class Tornado extends SpellConstruct { + public static final String SPEED = "speed"; + public static final String UPWARD_ACCELERATION = "upward_acceleration"; + public Tornado(){ - super("tornado", Tier.ADVANCED, Element.EARTH, SpellType.ATTACK, 35, 80, EnumAction.NONE, EntityTornado::new, 200, WizardrySounds.SPELL_ICE); + super("tornado", EnumAction.NONE, EntityTornado::new, false); + addProperties(EFFECT_RADIUS, SPEED, DAMAGE, UPWARD_ACCELERATION); } @Override - protected void addConstructExtras(EntityTornado construct, EntityLivingBase caster, SpellModifiers modifiers){ - construct.setHorizontalVelocity(caster.getLookVec().x / 3, caster.getLookVec().z / 3); + protected void addConstructExtras(EntityTornado construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ + float speed = getProperty(SPEED).floatValue(); + construct.setHorizontalVelocity(caster.getLookVec().x * speed, caster.getLookVec().z * speed); } } diff --git a/src/main/java/electroblob/wizardry/spell/Transience.java b/src/main/java/electroblob/wizardry/spell/Transience.java index 07bcc516..b47fdfcf 100644 --- a/src/main/java/electroblob/wizardry/spell/Transience.java +++ b/src/main/java/electroblob/wizardry/spell/Transience.java @@ -1,48 +1,60 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.Wizardry; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingAttackEvent; -import net.minecraftforge.event.world.BlockEvent; +import net.minecraftforge.event.entity.living.PotionEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber public class Transience extends Spell { + /** A {@code ResourceLocation} representing the shader file used when under the effects of transience. */ + public static final ResourceLocation SHADER = new ResourceLocation(Wizardry.MODID, "shaders/post/transience.json"); + public Transience(){ - super("transience", Tier.ADVANCED, Element.HEALING, SpellType.BUFF, 50, 100, EnumAction.BOW, false); + super("transience", EnumAction.BOW, false); + addProperties(EFFECT_DURATION); } @Override - public boolean doesSpellRequirePacket(){ - return false; + public boolean requiresPacket(){ + return true; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + if(world.isRemote && caster == net.minecraft.client.Minecraft.getMinecraft().player){ + if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER); + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); + } + if(!caster.isPotionActive(WizardryPotions.transience)){ + if(!world.isRemote){ - caster.addPotionEffect(new PotionEffect(WizardryPotions.transience, - (int)(400 * modifiers.get(WizardryItems.duration_upgrade)), 0)); - caster.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, - (int)(400 * modifiers.get(WizardryItems.duration_upgrade)), 0, false, false)); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_CONJURATION, 1.0f, 1.0f); + + int duration = (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)); + + caster.addPotionEffect(new PotionEffect(WizardryPotions.transience, duration, 0)); + caster.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, duration, 0, false, false)); + + this.playSound(world, caster, ticksInUse, duration, modifiers); } + return true; } return false; @@ -53,7 +65,7 @@ public class Transience extends Spell { if(event.getSource() != null){ // Prevents all blockable damage while transience is active if(event.getEntityLiving().isPotionActive(WizardryPotions.transience) - && !event.getSource().isUnblockable()){ + && event.getSource() != DamageSource.OUT_OF_WORLD){ event.setCanceled(true); } // Prevents transient entities from causing any damage @@ -65,20 +77,19 @@ public class Transience extends Spell { } @SubscribeEvent - public static void onBlockPlaceEvent(BlockEvent.PlaceEvent event){ - // Prevents transient players from placing blocks - if(event.getPlayer().isPotionActive(WizardryPotions.transience)){ + public static void onPlayerInteractEvent(PlayerInteractEvent event){ + // Prevents transient players from interacting with the world in any way + if(event.isCancelable() && event.getEntityPlayer().isPotionActive(WizardryPotions.transience)){ event.setCanceled(true); - return; } } @SubscribeEvent - public static void onBlockBreakEvent(BlockEvent.BreakEvent event){ - // Prevents transient players from breaking blocks - if(event.getPlayer().isPotionActive(WizardryPotions.transience)){ - event.setCanceled(true); - return; + public static void onPotionAddedEvent(PotionEvent.PotionAddedEvent event){ + if(event.getEntity().world.isRemote && event.getPotionEffect().getPotion() == WizardryPotions.transience + && event.getEntity() == net.minecraft.client.Minecraft.getMinecraft().player){ + if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER); + electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); } } diff --git a/src/main/java/electroblob/wizardry/spell/Transportation.java b/src/main/java/electroblob/wizardry/spell/Transportation.java index cbb838d0..07e7d9a6 100644 --- a/src/main/java/electroblob/wizardry/spell/Transportation.java +++ b/src/main/java/electroblob/wizardry/spell/Transportation.java @@ -1,63 +1,197 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.WizardData; import electroblob.wizardry.block.BlockTransportationStone; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.data.IStoredVariable; +import electroblob.wizardry.data.Persistence; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.packet.PacketTransportation; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.Location; +import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; +import net.minecraft.nbt.NBTTagList; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; public class Transportation extends Spell { + public static final String TELEPORT_COUNTDOWN = "teleport_countdown"; + + public static final int MAX_REMEMBERED_LOCATIONS = 4; + + // For some reason 'the diamond' doesn't work if I chain methods onto this. Type inference is weird. + public static final IStoredVariable> LOCATIONS_KEY = new IStoredVariable.StoredVariable, NBTTagList>("stoneCirclePos", + s -> NBTExtras.listToNBT(s, Location::toNBT), t -> new ArrayList<>(NBTExtras.NBTToList(t, Location::fromNBT)), Persistence.ALWAYS).setSynced(); + public static final IStoredVariable COUNTDOWN_KEY = IStoredVariable.StoredVariable.ofInt("tpCountdown", Persistence.NEVER).withTicker(Transportation::update); + public Transportation(){ - super("transportation", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 100, 100, EnumAction.BOW, false); + super("transportation", EnumAction.BOW, false); + addProperties(TELEPORT_COUNTDOWN); + WizardData.registerStoredVariables(LOCATIONS_KEY, COUNTDOWN_KEY); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - WizardData properties = WizardData.get(caster); + WizardData data = WizardData.get(caster); // Fixes the sound not playing in first person. - if(world.isRemote) WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_PORTAL_TRIGGER, 1.0f, 1.0f); + if(world.isRemote) this.playSound(world, caster, ticksInUse, -1, modifiers); // Only works when the caster is in the same dimension. - if(properties != null && properties.getTpCountdown() == 0){ - if(caster.dimension == properties.getStoneCircleDimension()){ - // Has to be y since x and z could reasonably be -1. - if(properties.getStoneCircleLocation() != null){ - if(BlockTransportationStone.testForCircle(world, properties.getStoneCircleLocation())){ - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_PORTAL_TRIGGER, 1.0f, 1.0f); - caster.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, 150, 0)); - properties.setTpCountdown(75); - return true; - }else{ - if(!world.isRemote) - caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".missing"), true); - } - }else{ - if(!world.isRemote) - caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".undefined"), true); + if(data != null){ + + Integer countdown = data.getVariable(COUNTDOWN_KEY); + + if(countdown == null || countdown == 0){ + + List locations = data.getVariable(Transportation.LOCATIONS_KEY); + + if(locations == null) data.setVariable(Transportation.LOCATIONS_KEY, locations = new ArrayList<>(Transportation.MAX_REMEMBERED_LOCATIONS)); + + if(locations.isEmpty()){ + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".undefined"), true); + return false; + } + + if(ItemArtefact.isArtefactActive(caster, WizardryItems.charm_transportation)){ + + List locationsInDimension = locations.stream().filter(l -> l.dimension == caster.dimension).collect(Collectors.toList()); + + if(locationsInDimension.isEmpty()){ + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".wrongdimension"), true); + return false; + } + + Location destination = getLocationAimedAt(caster, locationsInDimension, 1); + + if(destination == null) return false; // None of them were aimed at + + if(attemptTravelTo(caster, world, destination.pos, modifiers)){ + // Move the selected destination to the end of the list, making it the 'most recent' one + // This makes my life easier in update() below, and is a kind of useful feature too + locations.remove(destination); + locations.add(destination); + if(!world.isRemote) data.sync(); + return true; + } + + }else{ + + Location destination = locations.get(locations.size() - 1); // The most recent one, or the only one + + if(destination.dimension == caster.dimension){ + return attemptTravelTo(caster, world, destination.pos, modifiers); + }else{ + if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".wrongdimension"), true); + } + } - }else{ - if(!world.isRemote) - caster.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".wrongdimension"), true); } } + return false; } + // The following four methods centralise and neaten up the code + // Since the deviation angle is also used by the UI renderer, this also ensures they use the same calculation + + /** Returns the location from the given list that the give player is aiming at, or null if they are not aiming + * at any of them. */ + public static Location getLocationAimedAt(EntityPlayer player, List locations, float partialTicks){ + return locations.stream() + .filter(l -> isLocationAimedAt(player, l.pos, partialTicks)) + .min(Comparator.comparingDouble(l -> getLookDeviationAngle(player, l.pos, partialTicks))) + .orElse(null); + } + + public static boolean isLocationAimedAt(EntityPlayer player, BlockPos pos, float partialTicks){ + + Vec3d origin = player.getPositionEyes(partialTicks); + Vec3d centre = WizardryUtilities.getCentre(pos); + Vec3d direction = centre.subtract(origin); + double distance = direction.length(); + + return getLookDeviationAngle(player, pos, partialTicks) < getIconSize(distance); + } + + public static double getLookDeviationAngle(EntityPlayer player, BlockPos pos, float partialTicks){ + + Vec3d origin = player.getPositionEyes(partialTicks); + Vec3d look = player.getLook(partialTicks); + Vec3d centre = WizardryUtilities.getCentre(pos); + Vec3d direction = centre.subtract(origin); + double distance = direction.length(); + + return Math.acos(direction.dotProduct(look) / distance); // Angle between a and b = acos((a.b) / (|a|*|b|)) + } + + public static double getIconSize(double distance){ + return 0.05 + 2/(distance + 5); + } + + private boolean attemptTravelTo(EntityPlayer player, World world, BlockPos destination, SpellModifiers modifiers){ + + WizardData data = WizardData.get(player); + + if(BlockTransportationStone.testForCircle(world, destination)){ + this.playSound(world, player, 0, -1, modifiers); + player.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, 150, 0)); + data.setVariable(COUNTDOWN_KEY, getProperty(TELEPORT_COUNTDOWN).intValue()); + return true; + }else{ + if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".missing"), true); + return false; + } + } + + private static int update(EntityPlayer player, Integer countdown){ + + if(countdown == null) return 0; + + if(!player.world.isRemote){ + + WizardData data = WizardData.get(player); + + List locations = data.getVariable(Transportation.LOCATIONS_KEY); + if(locations == null || locations.isEmpty()) return 0; + + // If the location was selected, either it was already at the end of the list or it was moved there + Location destination = locations.get(locations.size() - 1); + + if(countdown == 1 && destination.dimension == player.dimension){ + player.setPositionAndUpdate(destination.pos.getX() + 0.5, destination.pos.getY(), destination.pos.getZ() + 0.5); + player.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, 50, 0)); + IMessage msg = new PacketTransportation.Message(player.getEntityId()); + WizardryPacketHandler.net.sendToDimension(msg, player.world.provider.getDimension()); + } + + if(countdown > 0){ + countdown--; + } + } + + return countdown; + } + } diff --git a/src/main/java/electroblob/wizardry/spell/VanishingBox.java b/src/main/java/electroblob/wizardry/spell/VanishingBox.java index 24ea13df..471450de 100644 --- a/src/main/java/electroblob/wizardry/spell/VanishingBox.java +++ b/src/main/java/electroblob/wizardry/spell/VanishingBox.java @@ -1,12 +1,7 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.inventory.InventoryEnderChest; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; @@ -15,10 +10,10 @@ import net.minecraft.world.World; public class VanishingBox extends Spell { public VanishingBox(){ - super("vanishing_box", Tier.ADVANCED, Element.SORCERY, SpellType.UTILITY, 45, 70, EnumAction.BOW, false); + super("vanishing_box", EnumAction.BOW, false); } - @Override public boolean doesSpellRequirePacket(){ return false; } + @Override public boolean requiresPacket(){ return false; } @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ @@ -32,7 +27,7 @@ public class VanishingBox extends Spell { } } - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.BLOCK_ENDERCHEST_OPEN, 1, 1); + this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/WallOfFrost.java b/src/main/java/electroblob/wizardry/spell/WallOfFrost.java index 1ab2670d..2c059bef 100644 --- a/src/main/java/electroblob/wizardry/spell/WallOfFrost.java +++ b/src/main/java/electroblob/wizardry/spell/WallOfFrost.java @@ -1,83 +1,69 @@ package electroblob.wizardry.spell; import electroblob.wizardry.block.BlockStatue; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.tileentity.TileEntityStatue; import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; -import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class WallOfFrost extends SpellRay { - private static final int BASE_DURATION = 600; + private static final int MINIMUM_PLACEMENT_RANGE = 2; public WallOfFrost(){ - super("wall_of_frost", Tier.MASTER, Element.ICE, SpellType.UTILITY, 15, 0, true, 10, null); + super("wall_of_frost", true, EnumAction.NONE); this.particleVelocity(1); this.particleSpacing(0.5); - } - - @Override - public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - // TODO: Temporary solution until I implement a better continuous sound system - boolean flag = super.cast(world, caster, hand, ticksInUse, modifiers); - if(flag){ - if(ticksInUse % 12 == 0){ - if(ticksInUse == 0) WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_ICE, 0.5f, 1); - WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_LOOP_ICE, 0.5f, 1); - } - } - return flag; + addProperties(DURATION); + soundValues(0.5f, 1, 0); } @Override - public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ - boolean flag = super.cast(world, caster, hand, ticksInUse, target, modifiers); - if(flag){ - if(ticksInUse % 12 == 0){ - if(ticksInUse == 0) caster.playSound(WizardrySounds.SPELL_ICE, 0.5f, 1); - caster.playSound(WizardrySounds.SPELL_LOOP_ICE, 0.5f, 1); - } - } - return flag; + protected SoundEvent[] createSounds(){ + return this.createContinuousSpellSounds(); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, entity, ticksInUse); + } + + @Override + protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){ + this.playSoundLoop(world, x, y, z, ticksInUse, duration); + } + + @Override + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ // Wall of frost now freezes entities solid too! if(target instanceof EntityLiving && !world.isRemote){ // Unchecked cast is fine because the block is a static final field if(((BlockStatue)WizardryBlocks.ice_statue).convertToStatue((EntityLiving)target, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)))){ + (int)(getProperty(DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)))){ - target.playSound(WizardrySounds.SPELL_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); - return true; + target.playSound(WizardrySounds.MISC_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F); } } - return false; + return true; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - - // IDEA: Use frosted ice instead of ice statue blocks - - if(!world.isRemote){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(!world.isRemote && WizardryUtilities.canDamageBlocks(caster, world)){ // Stops the ice being placed floating above snow and grass. Directions other than up included for // completeness. @@ -86,20 +72,16 @@ public class WallOfFrost extends SpellRay { pos = pos.offset(side.getOpposite()); } - if(caster.getDistance(pos.getX(), pos.getY(), pos.getZ()) > 2 - && world.getBlockState(pos).getBlock() != WizardryBlocks.ice_statue){ + if(origin.squareDistanceTo(pos.getX(), pos.getY(), pos.getZ()) > MINIMUM_PLACEMENT_RANGE * MINIMUM_PLACEMENT_RANGE + && world.getBlockState(pos).getBlock() != WizardryBlocks.ice_statue && world.getBlockState(pos).getBlock() != WizardryBlocks.dry_frosted_ice){ pos = pos.offset(side); - int duration = (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)); + int duration = (int)(getProperty(DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)); if(WizardryUtilities.canBlockBeReplaced(world, pos)){ - - world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); - - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration); - } + world.setBlockState(pos, WizardryBlocks.dry_frosted_ice.getDefaultState()); + world.scheduleUpdate(pos.toImmutable(), WizardryBlocks.dry_frosted_ice, duration); } // Builds a 2 block high wall if it hits the ground @@ -107,12 +89,8 @@ public class WallOfFrost extends SpellRay { pos = pos.offset(side); if(WizardryUtilities.canBlockBeReplaced(world, pos)){ - - world.setBlockState(pos, WizardryBlocks.ice_statue.getDefaultState()); - - if(world.getTileEntity(pos) instanceof TileEntityStatue){ - ((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration); - } + world.setBlockState(pos, WizardryBlocks.dry_frosted_ice.getDefaultState()); + world.scheduleUpdate(pos.toImmutable(), WizardryBlocks.dry_frosted_ice, duration); } } } @@ -122,7 +100,7 @@ public class WallOfFrost extends SpellRay { } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/Whirlwind.java b/src/main/java/electroblob/wizardry/spell/Whirlwind.java index c3ff793e..733c891a 100644 --- a/src/main/java/electroblob/wizardry/spell/Whirlwind.java +++ b/src/main/java/electroblob/wizardry/spell/Whirlwind.java @@ -1,37 +1,55 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.item.ItemArtefact; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.EnumAction; import net.minecraft.network.play.server.SPacketEntityVelocity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class Whirlwind extends SpellRay { + public static final String REPULSION_VELOCITY = "repulsion_velocity"; + public Whirlwind(){ - super("whirlwind", Tier.APPRENTICE, Element.EARTH, SpellType.DEFENCE, 10, 15, false, 10, WizardrySounds.SPELL_ICE); + super("whirlwind", false, EnumAction.NONE); this.soundValues(0.8f, 0.7f, 0.2f); + addProperties(REPULSION_VELOCITY); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ + + if(target instanceof EntityPlayer && ((caster instanceof EntityPlayer && !Wizardry.settings.playersMoveEachOther) + || ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring))){ + + if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage( + new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); + return false; + } + // Left as EntityLivingBase because why not be able to move armour stands around? if(target instanceof EntityLivingBase){ + + Vec3d vec = target.getPositionVector().add(0, target.getEyeHeight(), 0).subtract(origin).normalize(); if(!world.isRemote){ - target.motionX = caster.getLookVec().x * 2; - target.motionY = caster.getLookVec().y * 2 + 1; - target.motionZ = caster.getLookVec().z * 2; + float velocity = getProperty(REPULSION_VELOCITY).floatValue() * modifiers.get(SpellModifiers.POTENCY); + + target.motionX = vec.x * velocity; + target.motionY = vec.y * velocity + 1; + target.motionZ = vec.z * velocity; // Player motion is handled on that player's client so needs packets if(target instanceof EntityPlayerMP){ @@ -40,15 +58,14 @@ public class Whirlwind extends SpellRay { } if(world.isRemote){ + + double distance = target.getDistance(origin.x, origin.y, origin.z); + for(int i = 0; i < 10; i++){ - double x = (double)(caster.posX + world.rand.nextFloat() - 0.5F - + caster.getLookVec().x * caster.getDistance(target) * 0.5); - double y = (double)(caster.getEntityBoundingBox().minY + caster.getEyeHeight() + world.rand.nextFloat() - 0.5F - + caster.getLookVec().y * caster.getDistance(target) * 0.5); - double z = (double)(caster.posZ + world.rand.nextFloat() - 0.5F - + caster.getLookVec().z * caster.getDistance(target) * 0.5); - world.spawnParticle(EnumParticleTypes.CLOUD, x, y, z, caster.getLookVec().x, - caster.getLookVec().y, caster.getLookVec().z); + double x = origin.x + world.rand.nextDouble() - 0.5 + vec.x * distance * 0.5; + double y = origin.y + world.rand.nextDouble() - 0.5 + vec.y * distance * 0.5; + double z = origin.z + world.rand.nextDouble() - 0.5 + vec.z * distance * 0.5; + world.spawnParticle(EnumParticleTypes.CLOUD, x, y, z, vec.x, vec.y, vec.z); } } @@ -59,12 +76,12 @@ public class Whirlwind extends SpellRay { } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return false; } diff --git a/src/main/java/electroblob/wizardry/spell/Wither.java b/src/main/java/electroblob/wizardry/spell/Wither.java index 9055c0c4..f649d9b8 100644 --- a/src/main/java/electroblob/wizardry/spell/Wither.java +++ b/src/main/java/electroblob/wizardry/spell/Wither.java @@ -1,8 +1,5 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; @@ -12,26 +9,26 @@ import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.MobEffects; -import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumAction; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; public class Wither extends SpellRay { - - private static final int BASE_DURATION = 200; - private static final int BASE_DAMAGE = 1; public Wither(){ - super("wither", Tier.APPRENTICE, Element.NECROMANCY, SpellType.ATTACK, 10, 20, false, 10, SoundEvents.ENTITY_WITHER_HURT); + super("wither", false, EnumAction.NONE); this.soundValues(1, 1.1f, 0.2f); + addProperties(DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH); } @Override - protected boolean onEntityHit(World world, Entity target, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ if(WizardryUtilities.isLiving(target)){ @@ -41,24 +38,23 @@ public class Wither extends SpellRay { new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true); }else{ target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER), - BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); + getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY)); ((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.WITHER, - (int)(BASE_DURATION * modifiers.get(WizardryItems.duration_upgrade)), 1)); + (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), + getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY)))); } - - return true; } + return true; + } + + @Override + protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ return false; } @Override - protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ - return false; - } - - @Override - protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ + protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){ return true; } diff --git a/src/main/java/electroblob/wizardry/spell/WitherSkull.java b/src/main/java/electroblob/wizardry/spell/WitherSkull.java index 85a8b363..8370ad26 100644 --- a/src/main/java/electroblob/wizardry/spell/WitherSkull.java +++ b/src/main/java/electroblob/wizardry/spell/WitherSkull.java @@ -1,46 +1,63 @@ package electroblob.wizardry.spell; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.SpellType; -import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.SpellModifiers; -import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntityWitherSkull; -import net.minecraft.init.SoundEvents; import net.minecraft.item.EnumAction; import net.minecraft.util.EnumHand; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.event.entity.EntityMobGriefingEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.Event; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +@Mod.EventBusSubscriber public class WitherSkull extends Spell { + public static final String ACCELERATION = "acceleration"; + public WitherSkull(){ - super("wither_skull", Tier.ADVANCED, Element.NECROMANCY, SpellType.ATTACK, 20, 30, EnumAction.NONE, false); + super("wither_skull", EnumAction.NONE, false); + addProperties(ACCELERATION); + soundValues(1, 1.1f, 0.2f); } @Override - public boolean doesSpellRequirePacket(){ + public boolean requiresPacket(){ return false; } + @Override + public boolean canBeCastByNPCs(){ + return true; + } + @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ Vec3d look = caster.getLookVec(); if(!world.isRemote){ + EntityWitherSkull witherskull = new EntityWitherSkull(world, caster, 1, 1, 1); - witherskull.setPosition(caster.posX + look.x, caster.posY + look.y + 1.3, - caster.posZ + look.z); - witherskull.accelerationX = look.x * 0.1; - witherskull.accelerationY = look.y * 0.1; - witherskull.accelerationZ = look.z * 0.1; + + witherskull.setPosition(caster.posX + look.x, caster.posY + look.y + 1.3, caster.posZ + look.z); + + double acceleration = getProperty(ACCELERATION).doubleValue() * modifiers.get(WizardryItems.range_upgrade); + + witherskull.accelerationX = look.x * acceleration; + witherskull.accelerationY = look.y * acceleration; + witherskull.accelerationZ = look.z * acceleration; + + witherskull.shootingEntity = caster; world.spawnEntity(witherskull); - WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, - world.rand.nextFloat() * 0.2F + 1.0F); + + this.playSound(world, caster, ticksInUse, -1, modifiers); } caster.swingArm(hand); return true; @@ -65,10 +82,11 @@ public class WitherSkull extends Spell { witherskull.accelerationY = dy / caster.getDistance(target) * 0.1; witherskull.accelerationZ = dz / caster.getDistance(target) * 0.1; + witherskull.shootingEntity = caster; witherskull.setPosition(caster.posX, caster.posY + caster.getEyeHeight(), caster.posZ); world.spawnEntity(witherskull); - caster.playSound(SoundEvents.ENTITY_WITHER_SHOOT, 1.0F, world.rand.nextFloat() * 0.2F + 1.0F); + this.playSound(world, caster, ticksInUse, -1, modifiers); } caster.swingArm(hand); @@ -78,9 +96,12 @@ public class WitherSkull extends Spell { return false; } - @Override - public boolean canBeCastByNPCs(){ - return true; + @SubscribeEvent + public static void onEntityMobGriefingEvent(EntityMobGriefingEvent event){ + if(event.getEntity() instanceof EntityPlayer){ + // If a player shot the wither skull, it should ignore the mob griefing gamerule and use playerBlockDamage instead + event.setResult(Wizardry.settings.playerBlockDamage ? Event.Result.ALLOW : Event.Result.DENY); + } } } diff --git a/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java b/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java index 8bd2d63f..7582ba0e 100644 --- a/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/tileentity/ContainerArcaneWorkbench.java @@ -1,17 +1,14 @@ package electroblob.wizardry.tileentity; -import java.util.HashSet; -import java.util.Set; - import electroblob.wizardry.Wizardry; import electroblob.wizardry.event.SpellBindEvent; import electroblob.wizardry.item.IWorkbenchItem; -import electroblob.wizardry.item.ItemArcaneTome; -import electroblob.wizardry.item.ItemArmourUpgrade; import electroblob.wizardry.item.ItemSpellBook; +import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.WandHelper; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.inventory.Container; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; @@ -21,6 +18,9 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; import net.minecraftforge.common.MinecraftForge; +import java.util.HashSet; +import java.util.Set; + public class ContainerArcaneWorkbench extends Container { /** The arcane workbench tile entity associated with this container. */ @@ -42,20 +42,21 @@ public class ContainerArcaneWorkbench extends Container { ItemStack wand = tileentity.getStackInSlot(CENTRE_SLOT); for(int i = 0; i < 8; i++){ - Slot slot = new SlotItemList(tileentity, i, -999, -999, 1, WizardryItems.spell_book); + Slot slot = new SlotItemClassList(tileentity, i, -999, -999, 1, ItemSpellBook.class); this.addSlotToContainer(slot); } - this.addSlotToContainer(new SlotItemList(tileentity, CRYSTAL_SLOT, 8, 88, 64, WizardryItems.magic_crystal)) + this.addSlotToContainer(new SlotItemList(tileentity, CRYSTAL_SLOT, 13, 101, 64, + WizardryItems.magic_crystal, WizardryItems.crystal_shard, WizardryItems.grand_crystal)) .setBackgroundName(EMPTY_SLOT_CRYSTAL.toString()); this.addSlotToContainer(new SlotWorkbenchItem(tileentity, CENTRE_SLOT, 80, 64, this)); - Set upgrades = new HashSet(WandHelper.getSpecialUpgrades()); // Can't be done statically. + Set upgrades = new HashSet<>(WandHelper.getSpecialUpgrades()); // Can't be done statically. upgrades.add(WizardryItems.arcane_tome); upgrades.add(WizardryItems.armour_upgrade); - this.addSlotToContainer(new SlotItemList(tileentity, UPGRADE_SLOT, 8, 106, 1, upgrades.toArray(new Item[0]))) + this.addSlotToContainer(new SlotItemList(tileentity, UPGRADE_SLOT, 147, 17, 1, upgrades.toArray(new Item[0]))) .setBackgroundName(EMPTY_SLOT_UPGRADE.toString()); for(int x = 0; x < 9; x++){ @@ -142,9 +143,9 @@ public class ContainerArcaneWorkbench extends Container { for(int i = 0; i < spellSlots; i++){ float angle = i * (2 * (float)Math.PI)/spellSlots; - int x = centreX + (int)(Math.round(SLOT_RADIUS * MathHelper.sin(angle))); + int x = centreX + Math.round(SLOT_RADIUS * MathHelper.sin(angle)); // -cos because +y is downwards - int y = centreY + (int)(Math.round(SLOT_RADIUS * -MathHelper.cos(angle))); + int y = centreY + Math.round(SLOT_RADIUS * -MathHelper.cos(angle)); showSlot(i, x, y); } @@ -159,17 +160,22 @@ public class ContainerArcaneWorkbench extends Container { } // FIXME: It only seems to be syncing correctly when a stack is put into the slot, not taken out. - // This is because markDirty isn't called in the tileentity, I think. + // This is because markDirty isn't called in the tileentity, I think. this.tileentity.sync(); } + // FIXME: Shift-clicking a stack of special upgrades when in the arcane workbench causes the whole stack to be + // transferred when it should be just one (this is a bug with vanilla as well - try putting a stack of + // bottles into a brewing stand). I have at least made it so only one gets used now, so it has no impact on + // the game. @Override public ItemStack transferStackInSlot(EntityPlayer player, int clickedSlotId){ ItemStack remainder = ItemStack.EMPTY; - Slot slot = (Slot)this.inventorySlots.get(clickedSlotId); + Slot slot = this.inventorySlots.get(clickedSlotId); if(slot != null && slot.getHasStack()){ + ItemStack stack = slot.getStack(); // The stack that was there originally remainder = stack.copy(); // A copy of that stack @@ -189,14 +195,13 @@ public class ContainerArcaneWorkbench extends Container { if(stack.getItem() instanceof ItemSpellBook){ minSlotId = 0; maxSlotId = CRYSTAL_SLOT - 1; - }else if(stack.getItem() == WizardryItems.magic_crystal){ + }else if(getSlot(CRYSTAL_SLOT).isItemValid(stack)){ minSlotId = CRYSTAL_SLOT; maxSlotId = CRYSTAL_SLOT; - }else if(stack.getItem() instanceof IWorkbenchItem){ + }else if(getSlot(CENTRE_SLOT).isItemValid(stack)){ minSlotId = CENTRE_SLOT; maxSlotId = CENTRE_SLOT; - }else if(stack.getItem() instanceof ItemArcaneTome || stack.getItem() instanceof ItemArmourUpgrade - || WandHelper.isWandUpgrade(stack.getItem())){ + }else if(getSlot(UPGRADE_SLOT).isItemValid(stack)){ minSlotId = UPGRADE_SLOT; maxSlotId = UPGRADE_SLOT; }else{ @@ -257,8 +262,10 @@ public class ContainerArcaneWorkbench extends Container { if(((IWorkbenchItem)centre.getStack().getItem()) .onApplyButtonPressed(player, centre, this.getSlot(CRYSTAL_SLOT), this.getSlot(UPGRADE_SLOT), spellBooks)){ - - // Probably don't need to do anything here, unless we're going to use packets to control the animation + + if(player instanceof EntityPlayerMP){ + WizardryAdvancementTriggers.arcane_workbench.trigger((EntityPlayerMP)player, centre.getStack()); + } } } } diff --git a/src/main/java/electroblob/wizardry/tileentity/SlotItemClassList.java b/src/main/java/electroblob/wizardry/tileentity/SlotItemClassList.java new file mode 100644 index 00000000..783249d9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/tileentity/SlotItemClassList.java @@ -0,0 +1,40 @@ +package electroblob.wizardry.tileentity; + +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +/** + * Simple extension of {@link Slot} which only accepts items from an array of item classes defined in the constructor. + * + * @author Electroblob + * @since Wizardry 1.0 + */ +public class SlotItemClassList extends Slot { + + private final Class[] itemClasses; + private int stackLimit; + + @SafeVarargs + public SlotItemClassList(IInventory inventory, int index, int x, int y, int stackLimit, Class... allowedItemClasses){ + super(inventory, index, x, y); + this.itemClasses = allowedItemClasses; + this.stackLimit = stackLimit; + } + + public int getSlotStackLimit(){ + return stackLimit; + } + + public boolean isItemValid(ItemStack stack){ + + for(Class itemClass : itemClasses){ + if(itemClass.isAssignableFrom(stack.getItem().getClass())){ + return true; + } + } + + return false; + } +} diff --git a/src/main/java/electroblob/wizardry/tileentity/SlotItemList.java b/src/main/java/electroblob/wizardry/tileentity/SlotItemList.java index 93115155..db95b5e0 100644 --- a/src/main/java/electroblob/wizardry/tileentity/SlotItemList.java +++ b/src/main/java/electroblob/wizardry/tileentity/SlotItemList.java @@ -6,18 +6,18 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; /** - * Simple extension of {@link Slot} which only accepts items from an array defined in the constructor. + * Simple extension of {@link Slot} which only accepts items from an array of items defined in the constructor. * * @author Electroblob * @since Wizardry 1.0 */ public class SlotItemList extends Slot { - private Item[] items; + private final Item[] items; private int stackLimit; - public SlotItemList(IInventory par1iInventory, int index, int x, int y, int stackLimit, Item... allowedItems){ - super(par1iInventory, index, x, y); + public SlotItemList(IInventory inventory, int index, int x, int y, int stackLimit, Item... allowedItems){ + super(inventory, index, x, y); this.items = allowedItems; this.stackLimit = stackLimit; } @@ -27,11 +27,13 @@ public class SlotItemList extends Slot { } public boolean isItemValid(ItemStack stack){ - for(int i = 0; i < items.length; i++){ - if(stack.getItem() == this.items[i]){ + + for(Item item : items){ + if(stack.getItem() == item){ return true; } } + return false; } } diff --git a/src/main/java/electroblob/wizardry/tileentity/SlotWorkbenchItem.java b/src/main/java/electroblob/wizardry/tileentity/SlotWorkbenchItem.java index c83673f0..0e0a2f7d 100644 --- a/src/main/java/electroblob/wizardry/tileentity/SlotWorkbenchItem.java +++ b/src/main/java/electroblob/wizardry/tileentity/SlotWorkbenchItem.java @@ -35,7 +35,7 @@ public class SlotWorkbenchItem extends Slot { @Override public int getSlotStackLimit(){ - return 1; + return 16; } @Override diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java index a04d661c..991098b7 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityArcaneWorkbench.java @@ -1,11 +1,10 @@ package electroblob.wizardry.tileentity; -import java.util.HashSet; -import java.util.Set; - import electroblob.wizardry.Wizardry; -import electroblob.wizardry.item.ItemWand; -import electroblob.wizardry.item.ItemWizardArmour; +import electroblob.wizardry.item.IManaStoringItem; +import electroblob.wizardry.item.IWorkbenchItem; +import electroblob.wizardry.item.ItemCrystal; +import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.util.WandHelper; @@ -26,16 +25,15 @@ import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.HashSet; +import java.util.Set; + public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, ITickable { /** The inventory of the arcane workbench. */ private NonNullList inventory; - /** Controls the rotation of the rune. */ + /** Controls the rotating rune and floating wand animations. */ public float timer = 0; - /** Controls the change of yOffset. */ - public int yTimer = 0; - /** Controls the height of the wand. */ - public int yOffset = 300; public TileEntityArcaneWorkbench(){ inventory = NonNullList.withSize(ContainerArcaneWorkbench.UPGRADE_SLOT + 1, ItemStack.EMPTY); @@ -44,8 +42,6 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, @Override public void onLoad(){ timer = 0; - yTimer = 0; - yOffset = 300; } /** Called to manually sync the tile entity with clients. */ @@ -56,29 +52,18 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, @Override public void update(){ - ItemStack itemstack = this.getStackInSlot(ContainerArcaneWorkbench.CENTRE_SLOT); + ItemStack stack = this.getStackInSlot(ContainerArcaneWorkbench.CENTRE_SLOT); // Decrements wand damage (increases mana) every 1.5 seconds if it has a condenser upgrade - if(itemstack.getItem() instanceof ItemWand && !this.world.isRemote && itemstack.isItemDamaged() - && this.world.getWorldTime() % electroblob.wizardry.constants.Constants.CONDENSER_TICK_INTERVAL == 0){ + if(stack.getItem() instanceof IManaStoringItem && !this.world.isRemote && !((IManaStoringItem)stack.getItem()).isManaFull(stack) + && this.world.getTotalWorldTime() % electroblob.wizardry.constants.Constants.CONDENSER_TICK_INTERVAL == 0){ // If the upgrade level is 0, this does nothing anyway. - itemstack.setItemDamage( - itemstack.getItemDamage() - WandHelper.getUpgradeLevel(itemstack, WizardryItems.condenser_upgrade)); + ((IManaStoringItem)stack.getItem()).rechargeMana(stack, WandHelper.getUpgradeLevel(stack, WizardryItems.condenser_upgrade)); } // The server doesn't care what these are, and there's no need for them to be synced or saved. if(this.world.isRemote){ - if(timer < 359){ - timer++; - }else{ - timer = 0; - } - if(yOffset > 0){ - yTimer--; - }else{ - yTimer++; - } - yOffset += yTimer; + timer++; } } @@ -170,17 +155,16 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, if(itemstack == ItemStack.EMPTY) return true; if(slotNumber >= 0 && slotNumber < ContainerArcaneWorkbench.CRYSTAL_SLOT){ - return itemstack.getItem() == WizardryItems.spell_book; + return itemstack.getItem() instanceof ItemSpellBook; }else if(slotNumber == ContainerArcaneWorkbench.CRYSTAL_SLOT){ - return itemstack.getItem() == WizardryItems.magic_crystal; + return itemstack.getItem() instanceof ItemCrystal; }else if(slotNumber == ContainerArcaneWorkbench.CENTRE_SLOT){ - return (itemstack.getItem() instanceof ItemWand || itemstack.getItem() instanceof ItemWizardArmour - || itemstack.getItem() == WizardryItems.blank_scroll); + return itemstack.getItem() instanceof IWorkbenchItem; }else if(slotNumber == ContainerArcaneWorkbench.UPGRADE_SLOT){ - Set upgrades = new HashSet(WandHelper.getSpecialUpgrades()); + Set upgrades = new HashSet<>(WandHelper.getSpecialUpgrades()); upgrades.add(WizardryItems.arcane_tome); upgrades.add(WizardryItems.armour_upgrade); return upgrades.contains(itemstack.getItem()); @@ -197,16 +181,12 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, NBTTagList tagList = tagCompound.getTagList("Inventory", NBT.TAG_COMPOUND); for(int i = 0; i < tagList.tagCount(); i++){ - NBTTagCompound tag = (NBTTagCompound)tagList.getCompoundTagAt(i); + NBTTagCompound tag = tagList.getCompoundTagAt(i); byte slot = tag.getByte("Slot"); if(slot >= 0 && slot < getSizeInventory()){ setInventorySlotContents(slot, new ItemStack(tag)); } } - - // timer = tagCompound.getFloat("timer"); - // yTimer = tagCompound.getInteger("yTimer"); - // yOffset = tagCompound.getInteger("yOffset"); } @Override @@ -226,10 +206,6 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, } tagCompound.setTag("Inventory", itemList); - // tagCompound.setFloat("timer", timer); - // tagCompound.setInteger("yTimer", yTimer); - // tagCompound.setInteger("yOffset", yOffset); - return tagCompound; } @@ -249,6 +225,7 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory, } @SideOnly(Side.CLIENT) + @Override public AxisAlignedBB getRenderBoundingBox(){ AxisAlignedBB bb = INFINITE_EXTENT_AABB; Block type = getBlockType(); diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityMagicLight.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityMagicLight.java index 7a43f568..2fa0ab68 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityMagicLight.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityMagicLight.java @@ -19,6 +19,11 @@ public class TileEntityMagicLight extends TileEntityTimer { randomiser2[0] = -1; } + @Override + public boolean shouldRenderInPass(int pass){ + return pass == 1; + } + @Override public void update(){ diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSave.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSave.java index d9ff7e86..6e91f534 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSave.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSave.java @@ -1,43 +1,26 @@ package electroblob.wizardry.tileentity; -import java.lang.ref.WeakReference; -import java.util.UUID; - +import electroblob.wizardry.Wizardry; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ITickable; -public class TileEntityPlayerSave extends TileEntity implements ITickable { +import javax.annotation.Nullable; +import java.util.UUID; - /** The entity that created this construct */ - private WeakReference caster; +public class TileEntityPlayerSave extends TileEntity { - /** - * The UUID of the caster. Note that this is only for loading purposes; during normal updates the actual entity - * instance is stored (so that getEntityByUUID is not called constantly), so this will not always be synced (this is - * why it is private). - */ + /** The UUID of the caster. As of Wizardry 4.2, this is synced, and rather than storing the caster + * instance via a weak reference, it is fetched from the UUID each time it is needed in + * {@link TileEntityPlayerSave#getCaster()}. */ private UUID casterUUID; + public TileEntityPlayerSave(){} + public TileEntityPlayerSave(EntityLivingBase caster){ - this.caster = new WeakReference(caster); - } - - public TileEntityPlayerSave(){ - - } - - @Override - public void update(){ - if(this.getCaster() == null && this.casterUUID != null){ - Entity entity = WizardryUtilities.getEntityByUUID(world, casterUUID); - if(entity instanceof EntityLivingBase){ - this.caster = new WeakReference((EntityLivingBase)entity); - } - } + this.casterUUID = caster.getUniqueID(); } @Override @@ -52,7 +35,7 @@ public class TileEntityPlayerSave extends TileEntity implements ITickable { super.writeToNBT(tagCompound); if(this.getCaster() != null){ - tagCompound.setUniqueId("casterUUID", this.getCaster().getUniqueID()); + tagCompound.setUniqueId("casterUUID", casterUUID); } return tagCompound; @@ -63,12 +46,21 @@ public class TileEntityPlayerSave extends TileEntity implements ITickable { * may no longer exist are: entity died or was deleted, mob despawned, player logged out, entity teleported to * another dimension, or this construct simply had no caster in the first place. */ + @Nullable public EntityLivingBase getCaster(){ - return caster == null ? null : caster.get(); + + Entity entity = WizardryUtilities.getEntityByUUID(world, casterUUID); + + if(entity != null && !(entity instanceof EntityLivingBase)){ // Should never happen + Wizardry.logger.warn("{} has a non-living owner!", this); + entity = null; + } + + return (EntityLivingBase)entity; } - public void setCaster(EntityLivingBase caster){ - this.caster = new WeakReference(caster); + public void setCaster(@Nullable EntityLivingBase caster){ + this.casterUUID = caster == null ? null : caster.getUniqueID(); } } diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSaveTimed.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSaveTimed.java new file mode 100644 index 00000000..92f4ab37 --- /dev/null +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityPlayerSaveTimed.java @@ -0,0 +1,69 @@ +package electroblob.wizardry.tileentity; + +import electroblob.wizardry.block.BlockThorns; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.play.server.SPacketUpdateTileEntity; +import net.minecraft.util.ITickable; + +public class TileEntityPlayerSaveTimed extends TileEntityPlayerSave implements ITickable { + + public int timer = 0; + public int maxTimer; + + public TileEntityPlayerSaveTimed(int maxTimer){ + this.maxTimer = maxTimer; + } + + @Override + public void update(){ + + timer++; + + if(timer > maxTimer && !this.world.isRemote){ + this.world.destroyBlock(pos, false); + } + + if(timer % 2 == 0 && world.getBlockState(pos).getValue(BlockThorns.AGE) < BlockThorns.GROWTH_STAGES - 1){ + world.setBlockState(pos, world.getBlockState(pos).withProperty(BlockThorns.AGE, world.getBlockState(pos).getValue(BlockThorns.AGE) + 1), 2); + } + } + + public void setLifetime(int lifetime){ + this.maxTimer = lifetime; + } + + @Override + public void readFromNBT(NBTTagCompound tagCompound){ + super.readFromNBT(tagCompound); + timer = tagCompound.getInteger("timer"); + maxTimer = tagCompound.getInteger("maxTimer"); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound tagCompound){ + super.writeToNBT(tagCompound); + tagCompound.setInteger("timer", timer); + tagCompound.setInteger("maxTimer", maxTimer); + return tagCompound; + } + + @Override + public final NBTTagCompound getUpdateTag(){ + return this.writeToNBT(new NBTTagCompound()); + } + + @Override + public SPacketUpdateTileEntity getUpdatePacket(){ + NBTTagCompound tag = new NBTTagCompound(); + writeToNBT(tag); + return new SPacketUpdateTileEntity(pos, 1, tag); + } + + @Override + public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt){ + NBTTagCompound tag = pkt.getNbtCompound(); + readFromNBT(tag); + } + +} diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java new file mode 100644 index 00000000..2fdd0393 --- /dev/null +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityShrineCore.java @@ -0,0 +1,218 @@ +package electroblob.wizardry.tileentity; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockPedestal; +import electroblob.wizardry.entity.living.EntityEvilWizard; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.packet.PacketConquerShrine; +import electroblob.wizardry.packet.WizardryPacketHandler; +import electroblob.wizardry.potion.PotionContainment; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.registry.WizardrySounds; +import electroblob.wizardry.spell.ArcaneLock; +import electroblob.wizardry.util.NBTExtras; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.potion.PotionEffect; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ITickable; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fml.common.network.NetworkRegistry; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class TileEntityShrineCore extends TileEntity implements ITickable { + + private static final double ACTIVATION_RADIUS = 5; + + private boolean activated = false; + private AxisAlignedBB containmentField; + private final UUID[] linkedWizards = new UUID[3]; + private TileEntity linkedContainer; + private BlockPos linkedContainerPos; // Temporary stores the container position read from NBT until the world is set + + @Override + public void setPos(BlockPos pos){ + super.setPos(pos); + initContainmentField(pos); + } + + private void initContainmentField(BlockPos pos){ + float r = PotionContainment.getContainmentDistance(0); + this.containmentField = new AxisAlignedBB(-r, -r, -r, r, r, r).offset(WizardryUtilities.getCentre(pos)); + } + + public void linkContainer(TileEntity container){ + this.linkedContainer = container; + } + + @Override + public void update(){ + + if(this.linkedContainer == null && this.linkedContainerPos != null){ + this.linkContainer(world.getTileEntity(this.linkedContainerPos)); + } + + double x = this.pos.getX() + 0.5; + double y = this.pos.getY() + 0.5; + double z = this.pos.getZ() + 0.5; + + if(!activated && world.getClosestPlayer(x, y, z, ACTIVATION_RADIUS, false) != null){ + + this.activated = true; + + if(world.isRemote){ + ParticleBuilder.create(Type.SPHERE).pos(x, y + 1, z).clr(0xf06495).scale(5).time(12).spawn(world); + } + + world.playSound(x, y, z, + WizardrySounds.BLOCK_PEDESTAL_ACTIVATE, SoundCategory.BLOCKS, 1.5f, 1, false); + + if(!world.isRemote){ + + EntityEvilWizard[] wizards = new EntityEvilWizard[linkedWizards.length]; + + for(int i = 0; i < linkedWizards.length; i++){ + + EntityEvilWizard wizard = new EntityEvilWizard(world); + + float angle = world.rand.nextFloat() * 2 * (float)Math.PI; + double x1 = this.pos.getX() + 0.5 + 5 * MathHelper.sin(angle); + double z1 = this.pos.getZ() + 0.5 + 5 * MathHelper.cos(angle); + Integer y1 = WizardryUtilities.getNearestFloor(world, new BlockPos(x1, this.pos.getY(), z1), 8); + if(y1 == null){ + // Fallback to the position of the shrine core if it failed to find a position (unlikely) + x1 = this.pos.getX() + 1; // Offset it so the wizard isn't inside the block + y1 = this.pos.getY(); + z1 = this.pos.getZ(); + } + + wizard.setLocationAndAngles(x1, y1 + 0.5, z1, 0, 0); + wizard.setElement(world.getBlockState(pos).getValue(BlockPedestal.ELEMENT)); + wizard.onInitialSpawn(world.getDifficultyForLocation(pos), null); + wizard.hasStructure = true; + + world.spawnEntity(wizard); + wizards[i] = wizard; + linkedWizards[i] = wizard.getUniqueID(); + } + + for(EntityEvilWizard wizard : wizards) wizard.groupUUIDs.addAll(Arrays.asList(linkedWizards)); + } + + containNearbyTargets(); + } + + if(activated && world.getTotalWorldTime() % 20L == 0) containNearbyTargets(); + + if(activated && areWizardsDead() && !world.isRemote){ + conquer(); + } + } + + private boolean areWizardsDead(){ + + for(UUID uuid : linkedWizards){ + Entity entity = WizardryUtilities.getEntityByUUID(world, uuid); + if(entity instanceof EntityEvilWizard && entity.isEntityAlive()) return false; + } + + return true; + } + + public void conquer(){ + + double x = this.pos.getX() + 0.5; + double y = this.pos.getY() + 0.5; + double z = this.pos.getZ() + 0.5; + + if(!world.isRemote){ + WizardryPacketHandler.net.sendToAllAround(new PacketConquerShrine.Message(this.pos), + new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), x, y, z, 64)); + } + + world.setBlockState(pos, WizardryBlocks.runestone_pedestal.getDefaultState() + .withProperty(BlockPedestal.ELEMENT, world.getBlockState(pos).getValue(BlockPedestal.ELEMENT))); + + world.markTileEntityForRemoval(this); + + if(!world.isRemote){ + if(linkedContainer != null) NBTExtras.removeUniqueId(linkedContainer.getTileData(), ArcaneLock.NBT_KEY); + }else{ + TileEntity tileEntity = world.getTileEntity(this.pos.up()); + if(tileEntity != null){ // Bit of a dirty fix but it's only visual, so meh + NBTExtras.removeUniqueId(tileEntity.getTileData(), ArcaneLock.NBT_KEY); + } + } + + world.playSound(x, y, z, WizardrySounds.BLOCK_PEDESTAL_CONQUER, SoundCategory.BLOCKS, 1, 1, false); + + if(world.isRemote){ + ParticleBuilder.create(Type.SPHERE).scale(5).pos(x, y + 1, z).clr(0xf06495).time(12).spawn(world); + for(int i=0; i<5; i++){ + float brightness = 0.8f + world.rand.nextFloat() * 0.2f; + ParticleBuilder.create(Type.SPARKLE, world.rand, x, y + 1, z, 1, true) + .clr(1, brightness, brightness).spawn(world); + } + } + } + + private void containNearbyTargets(){ + + List entities = world.getEntitiesWithinAABB(EntityLivingBase.class, containmentField, + e -> e instanceof EntityPlayer || e instanceof EntityWizard || e instanceof EntityEvilWizard); + + for(EntityLivingBase entity : entities){ + entity.addPotionEffect(new PotionEffect(WizardryPotions.containment, 219)); + entity.getEntityData().setTag(PotionContainment.ENTITY_TAG, NBTUtil.createPosTag(this.pos)); + } + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound compound){ + + compound.setBoolean("activated", this.activated); + if(linkedContainer != null) compound.setTag("linkedContainerPos", NBTUtil.createPosTag(linkedContainer.getPos())); + + NBTTagList tagList = new NBTTagList(); + for(UUID uuid : linkedWizards){ + if(uuid != null) tagList.appendTag(NBTUtil.createUUIDTag(uuid)); + } + compound.setTag("wizards", tagList); + + return super.writeToNBT(compound); + } + + @Override + public void readFromNBT(NBTTagCompound compound){ + + this.activated = compound.getBoolean("activated"); + this.linkedContainerPos = NBTUtil.getPosFromTag(compound.getCompoundTag("linkedContainerPos")); + + NBTTagList tagList = compound.getTagList("wizards", Constants.NBT.TAG_COMPOUND); + int i = 0; + for(NBTBase tag : tagList){ + if(tag instanceof NBTTagCompound) linkedWizards[i++] = NBTUtil.getUUIDFromTag((NBTTagCompound)tag); + else Wizardry.logger.warn("Unexpected tag type in NBT tag list of compound tags!"); + } + + super.readFromNBT(compound); + // Must be after super + initContainmentField(this.pos); + } +} diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java index f93c7851..ab999d7d 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityStatue.java @@ -18,7 +18,7 @@ public class TileEntityStatue extends TileEntity implements ITickable { public EntityLiving creature; private NBTTagCompound entityCompound; - private String entityName; + private ResourceLocation entityName; private float entityYawHead; private float entityYawOffset; public boolean isIce; @@ -95,8 +95,7 @@ public class TileEntityStatue extends TileEntity implements ITickable { // System.out.println(entityName); if(this.creature == null && entityName != null){ - this.creature = (EntityLiving)EntityList.createEntityByIDFromName(new ResourceLocation(this.entityName), - this.world); + this.creature = (EntityLiving)EntityList.createEntityByIDFromName(this.entityName, this.world); if(this.creature != null){ this.creature.readFromNBT(entityCompound); this.creature.rotationYawHead = this.entityYawHead; @@ -133,7 +132,7 @@ public class TileEntityStatue extends TileEntity implements ITickable { position = tagCompound.getInteger("position"); parts = tagCompound.getInteger("parts"); entityCompound = tagCompound.getCompoundTag("entity"); - entityName = tagCompound.getString("entityName"); + entityName = new ResourceLocation(tagCompound.getString("entityName")); timer = tagCompound.getInteger("timer"); lifetime = tagCompound.getInteger("lifetime"); isIce = tagCompound.getBoolean("isIce"); @@ -149,7 +148,7 @@ public class TileEntityStatue extends TileEntity implements ITickable { entityCompound = new NBTTagCompound(); if(creature != null){ creature.writeToNBT(entityCompound); - tagCompound.setString("entityName", EntityList.getEntityString(creature)); + tagCompound.setString("entityName", EntityList.getKey(creature).toString()); tagCompound.setFloat("entityYawHead", creature.rotationYawHead); tagCompound.setFloat("entityYawOffset", creature.renderYawOffset); } diff --git a/src/main/java/electroblob/wizardry/tileentity/TileEntityTimer.java b/src/main/java/electroblob/wizardry/tileentity/TileEntityTimer.java index c8eb6062..185bbd55 100644 --- a/src/main/java/electroblob/wizardry/tileentity/TileEntityTimer.java +++ b/src/main/java/electroblob/wizardry/tileentity/TileEntityTimer.java @@ -22,11 +22,10 @@ public class TileEntityTimer extends TileEntity implements ITickable { @Override public void update(){ + timer++; - if(!this.world.isRemote){ - // System.out.println("Timer: " + timer + "/" + maxTimer); - } - if(timer > maxTimer && !this.world.isRemote){// && this.world.getBlockId(xCoord, yCoord, zCoord) == + + if(maxTimer > 0 && timer > maxTimer && !this.world.isRemote){// && this.world.getBlockId(xCoord, yCoord, zCoord) == // Wizardry.magicLight.blockID){ if(this.getBlockType() instanceof BlockVanishingCobweb){ // destroyBlock breaks the block as if broken by a player, with sound and particles. diff --git a/src/main/java/electroblob/wizardry/util/AllyDesignationSystem.java b/src/main/java/electroblob/wizardry/util/AllyDesignationSystem.java new file mode 100644 index 00000000..a066a9eb --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/AllyDesignationSystem.java @@ -0,0 +1,234 @@ +package electroblob.wizardry.util; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.registry.WizardryPotions; +import electroblob.wizardry.spell.MindControl; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityOwnable; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.event.entity.living.LivingAttackEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +/** + * Contains some useful static methods for interacting with the ally designation system. Also handles the friendly fire + * setting. This was split off from {@link WizardryUtilities} as of wizardry 4.2 in an effort to make the code easier to + * navigate. + */ +@Mod.EventBusSubscriber +public final class AllyDesignationSystem { + + private AllyDesignationSystem(){} // No instances! + + /** Set of constants for each of the four friendly fire settings. */ + public enum FriendlyFire { + + ALL("All", false, false), + ONLY_PLAYERS("Only players", false, true), + ONLY_OWNED("Only summoned/tamed creatures", true, false), + NONE("None", true, true); + + /** Constant array storing the names of each of the constants, in the order they are declared. */ + public static final String[] names; + + static { + names = new String[values().length]; + for(FriendlyFire setting : values()){ + names[setting.ordinal()] = setting.name; + } + } + + /** The readable name for this friendly fire setting that will be displayed on the button in the config GUI. */ + public final String name; + public final boolean blockPlayers; + public final boolean blockOwned; + + FriendlyFire(String name, boolean blockPlayers, boolean blockOwned){ + this.name = name; + this.blockPlayers = blockPlayers; + this.blockOwned = blockOwned; + } + + /** + * Gets a friendly fire setting from its string name (ignoring case), or ALL if the given name is not a valid + * setting. + */ + public static FriendlyFire fromName(String name){ + + for(FriendlyFire setting : values()){ + if(setting.name.equalsIgnoreCase(name)) return setting; + } + + Wizardry.logger.info("Invalid string for the friendly fire setting. Using default (all) instead."); + return ALL; + } + + } + + /** + * Returns whether the given target can be attacked by the given attacker. It is up to the caller of this method to + * work out what this means; it doesn't necessarily mean the target is completely immune (for example, revenge + * targeting might reasonably bypass this). This method is intended for use where the damage is indirect and/or + * unavoidable; direct attacks should not check this method. Currently this means the following situations check + * this method: + *

    + * - AI targeting for summoned creatures
    + * - AI targeting for mind-controlled creatures
    + * - Constructs with an area of effect
    + * - Instantaneous spells with an area of effect around the caster (e.g. forest's curse, thunderstorm)
    + * - Any lightning chaining effects
    + * - Any projectiles which seek targets + *

    + * Also note that the friendly fire option is dealt with in the event handler. This method acts as a sort of wrapper + * for all the AllyDesignationSystem stuff in {@link WizardData}; more details about the ally designation system can be found there. + * + * @param attacker The entity that cast the spell originally + * @param target The entity being attacked + * + * @return False under any of the following circumstances, true otherwise: + *

    + * - The target is null + *

    + * - The target is the attacker (this isn't as stupid as it sounds - anything with an AoE might cause this + * to be true, as can summoned creatures) + *

    + * - The target and the attacker are both players and the target is an ally of the attacker (but the + * attacker need not be an ally of the target) + *

    + * - The target is a creature that was summoned/controlled by the attacker or by an ally of the attacker. + *

    + * - The target is a creature that was tamed by the attacker or by an ally of the attacker + * (see {@link net.minecraft.entity.IEntityOwnable}). + *

    + * As of wizardry 4.1.2, this method now returns true instead of false if the attacker is null. This + * is because in the vast majority of cases, it makes more sense this way: if a construct has no caster, it + * should affect all entities; if a minion has no caster it should target all entities; etc. + */ + public static boolean isValidTarget(Entity attacker, Entity target){ + + // Always return true if the attacker is null + if(attacker == null) return true; + + // Always return false if the target is null + if(target == null) return false; + + // Tests whether the target is the attacker + if(target == attacker) return false; + + // I really shouldn't need to do this, but fake players seem to break stuff... + if(target instanceof FakePlayer) return false; + + // Tests whether the target is a creature that was summoned by the attacker +// if(target instanceof ISummonedCreature && ((ISummonedCreature)target).getCaster() == attacker){ +// return false; +// } + + // Tests whether the target is a creature that was summoned/tamed (or is otherwise owned) by the attacker + if(target instanceof IEntityOwnable && ((IEntityOwnable)target).getOwner() == attacker){ + return false; + } + + // Tests whether the target is a creature that was mind controlled by the attacker + if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(WizardryPotions.mind_control)){ + + NBTTagCompound entityNBT = target.getEntityData(); + + if(entityNBT != null && entityNBT.hasUniqueId(MindControl.NBT_KEY)){ + if(attacker == WizardryUtilities.getEntityByUUID(target.world, + entityNBT.getUniqueId(MindControl.NBT_KEY))){ + return false; + } + } + } + + // Ally section + if(attacker instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker) != null){ + + if(target instanceof EntityPlayer){ + // Tests whether the target is an ally of the attacker + if(WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)target)){ + return false; + } + +// }else if(target instanceof ISummonedCreature){ +// // Tests whether the target is a creature that was summoned by an ally of the attacker +// if(((ISummonedCreature)target).getCaster() instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker) +// .isPlayerAlly((EntityPlayer)((ISummonedCreature)target).getCaster())){ +// return false; +// } + + }else if(target instanceof IEntityOwnable){ + // Tests whether the target is a creature that was summoned/tamed by an ally of the attacker + if(isOwnerAlly((EntityPlayer)attacker, (IEntityOwnable)target)); + + }else if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(WizardryPotions.mind_control)){ + // Tests whether the target is a creature that was mind controlled by an ally of the attacker + NBTTagCompound entityNBT = target.getEntityData(); + + if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){ + + Entity controller = WizardryUtilities.getEntityByUUID(target.world, entityNBT.getUniqueId(MindControl.NBT_KEY)); + + if(controller instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)controller)){ + return false; + } + } + } + } + + return true; + } + + /** Umbrella method that covers both {@link AllyDesignationSystem#isPlayerAlly(EntityPlayer, EntityPlayer)} and + * {@link AllyDesignationSystem#isOwnerAlly(EntityPlayer, IEntityOwnable)}, returning true if the given + * {@link EntityLivingBase} is either owned by the given player, an ally of the given player or owned by an ally + * of the given player. This is generally used to determine targets for healing or other group buffs. */ + public static boolean isAllied(EntityPlayer allyOf, EntityLivingBase possibleAlly){ + return (possibleAlly instanceof EntityPlayer && isPlayerAlly(allyOf, (EntityPlayer)possibleAlly)) + || (possibleAlly instanceof IEntityOwnable && (((IEntityOwnable)possibleAlly).getOwner() == allyOf + || isOwnerAlly(allyOf, (IEntityOwnable)possibleAlly))); + } + + /** Helper method for testing if the second player is an ally of the first player. Makes the code neater. + * @see AllyDesignationSystem#isOwnerAlly(EntityPlayer, IEntityOwnable) */ + public static boolean isPlayerAlly(EntityPlayer allyOf, EntityPlayer possibleAlly){ + WizardData data = WizardData.get(allyOf); + return data != null && data.isPlayerAlly(possibleAlly); + } + + /** Helper method for testing if the given {@link net.minecraft.entity.IEntityOwnable}'s owner is an ally of the + * given player. This works even when the owner is not logged in, though it may not correctly respect teams when + * that is the case. */ + public static boolean isOwnerAlly(EntityPlayer allyOf, IEntityOwnable ownable){ + WizardData data = WizardData.get(allyOf); + if(data == null) return false; + Entity owner = ownable.getOwner(); + return owner instanceof EntityPlayer ? data.isPlayerAlly((EntityPlayer)owner) : data.isPlayerAlly(ownable.getOwnerId()); + } + + @SubscribeEvent + public static void onLivingAttackEvent(LivingAttackEvent event){ + + if(event.getSource() != null && event.getSource().getTrueSource() instanceof EntityPlayer + && event.getSource() instanceof IElementalDamage){ + + if(event.getEntity() instanceof EntityPlayer){ + // Prevents any magic damage to allied players if friendly fire is disabled for players + if(Wizardry.settings.friendlyFire.blockPlayers && isPlayerAlly((EntityPlayer)event.getSource().getTrueSource(), (EntityPlayer)event.getEntity())){ + event.setCanceled(true); + } + }else{ + // Prevents any magic damage to entities owned by allied players if friendly fire is disabled for owned creatures + // Since we're dealing with players separately we might as well just use isAllied + if(Wizardry.settings.friendlyFire.blockOwned && isAllied((EntityPlayer)event.getSource().getTrueSource(), event.getEntityLiving())){ + event.setCanceled(true); + } + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/util/CustomSoundCategory.java b/src/main/java/electroblob/wizardry/util/CustomSoundCategory.java new file mode 100644 index 00000000..a0fb1394 --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/CustomSoundCategory.java @@ -0,0 +1,86 @@ +package electroblob.wizardry.util; + +import com.google.common.collect.Maps; +import net.minecraft.util.SoundCategory; +import net.minecraftforge.common.util.EnumHelper; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.relauncher.FMLLaunchHandler; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.util.Map; + +/** + * Add a new CONSTANT and reference name to net.minecraft.util.SoundCategory + * + * This allows the display of a volume control in the "Music & Sound Options" dialog. + * Unfortunately the GuiScreenOptionsSounds dialog does not auto size + * properly and move the Done button lower on the screen. + * + * To initialize the class create an instance during FMLPreInitializationEvent in + * the file with the @Mod annotation or your common proxy class. + * + * Usage example: static final SoundCategory SC_MXTUNE = MODSoundCategory.add("MXTUNE"); + * + * The language file key is "soundCategory.mxtune" + * The game settings "options.txt" key is "soundCategory_mxtune" + * + * To use the MXTUNE enum constant in code it must be referenced by name because + * SoundCategory.MXTUNE does not exist at compile time. + * e.g. SoundCategory.getByName("mxtune"); + * + * @author Paul Boese aka Aeronica (modified for 1.12.2 and for conciseness/clarity by Electroblob) + * @see + * www.minecraftforge.net/forum/topic/42439-adding-additional-soundcategorys/ + */ +public final class CustomSoundCategory { + + private static final String SRG_soundLevels = "field_186714_aM"; + private static final String SRG_SOUND_CATEGORIES = "field_187961_k"; + // >> Electroblob: Don't know why this was instantiated at all, surely it's a static helper class? + + private CustomSoundCategory(){} + + /** + * Adds a new custom sound category, performing the necessary changes to GameSettings and + * + * @param name A unique name for the sound category + * @return The resulting SoundCategory object + * @throws IllegalArgumentException if name is not unique + */ + public static SoundCategory add(String name){ + + Map SOUND_CATEGORIES; + + String constantName; + String referenceName; + SoundCategory soundCategory; + // >> Electroblob: Constructors were unnecessary since strings are immutable + constantName = name.toUpperCase().replace(" ", ""); + referenceName = constantName.toLowerCase(); + // >> Electroblob: Removed array surrounding varargs argument + soundCategory = EnumHelper.addEnum(SoundCategory.class , constantName, new Class[]{String.class}, referenceName); + SOUND_CATEGORIES = ObfuscationReflectionHelper.getPrivateValue(SoundCategory.class, SoundCategory.VOICE ,"SOUND_CATEGORIES", SRG_SOUND_CATEGORIES); + if (SOUND_CATEGORIES.containsKey(referenceName)) + // >> Electroblob: changed from Error to IllegalArgumentException + throw new IllegalArgumentException("Clash in Sound Category name pools! Cannot insert " + constantName); + SOUND_CATEGORIES.put(referenceName, soundCategory); + if (FMLLaunchHandler.side() == Side.CLIENT) setSoundLevels(); + + return soundCategory; + } + + /** Game sound level options settings only exist on the client side */ + @SideOnly(Side.CLIENT) + private static void setSoundLevels(){ + // SoundCategory now contains 'name' sound category so build a new map + // >> Electroblob: Converted to local variable + Map soundLevels = Maps.newEnumMap(SoundCategory.class); + // Replace the map in the GameSettings.class + // >> Electroblob: Fully qualified names, because this class gets loaded on both sides + ObfuscationReflectionHelper.setPrivateValue(net.minecraft.client.settings.GameSettings.class, + net.minecraft.client.Minecraft.getMinecraft().gameSettings, soundLevels, + "soundLevels", SRG_soundLevels); + } + +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/util/IElementalDamage.java b/src/main/java/electroblob/wizardry/util/IElementalDamage.java index 47fad34a..a3d12aeb 100644 --- a/src/main/java/electroblob/wizardry/util/IElementalDamage.java +++ b/src/main/java/electroblob/wizardry/util/IElementalDamage.java @@ -1,9 +1,7 @@ package electroblob.wizardry.util; -import electroblob.wizardry.registry.WizardryAdvancementTriggers; import electroblob.wizardry.util.MagicDamage.DamageType; import net.minecraft.entity.monster.EntityCreeper; -import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -43,10 +41,6 @@ public interface IElementalDamage { && ((IElementalDamage)event.getSource()).getType() == DamageType.SHOCK){ // Charges creepers when they are hit by shock damage WizardryUtilities.chargeCreeper((EntityCreeper)event.getEntityLiving()); - // Gives the player that caused the shock damage the 'It's Gonna Blow' achievement - if(event.getSource().getTrueSource() instanceof EntityPlayer){ - WizardryAdvancementTriggers.charge_creeper.triggerFor((EntityPlayer)event.getSource().getTrueSource()); - } } } } diff --git a/src/main/java/electroblob/wizardry/util/Location.java b/src/main/java/electroblob/wizardry/util/Location.java new file mode 100644 index 00000000..dfeec264 --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/Location.java @@ -0,0 +1,47 @@ +package electroblob.wizardry.util; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.math.BlockPos; + +import javax.annotation.concurrent.Immutable; + +/** Simple wrapper class that stores a {@link BlockPos} and an integer dimension ID. */ +@Immutable +public class Location { + + public final BlockPos pos; + public final int dimension; + + public Location(BlockPos pos, int dimension){ + this.pos = pos; + this.dimension = dimension; + } + + /** Returns true if the given location refers to the same coordinates and dimension as this one. */ + @Override + public boolean equals(Object that){ + + if(this == that) return true; + + if(that instanceof Location){ + return this.pos.equals(((Location)that).pos) && this.dimension == ((Location)that).dimension; + } + + return false; + } + + /** Creates and returns an {@link NBTTagCompound} representing this location. The returned compound tag is the + * same as that returned by {@link NBTUtil#createPosTag(BlockPos)}, but with an extra "dimension" key. */ + public NBTTagCompound toNBT(){ + NBTTagCompound nbt = NBTUtil.createPosTag(pos); + nbt.setInteger("dimension", dimension); + return nbt; + } + + /** Creates a new {@code Location} from the given {@link NBTTagCompound}. The given compound tag should be the + * same as that returned by {@link NBTUtil#createPosTag(BlockPos)}, but with an extra "dimension" key. */ + public static Location fromNBT(NBTTagCompound nbt){ + return new Location(NBTUtil.getPosFromTag(nbt), nbt.getInteger("dimension")); + } +} diff --git a/src/main/java/electroblob/wizardry/util/MagicDamage.java b/src/main/java/electroblob/wizardry/util/MagicDamage.java index 5055c9ff..80e3cf6c 100644 --- a/src/main/java/electroblob/wizardry/util/MagicDamage.java +++ b/src/main/java/electroblob/wizardry/util/MagicDamage.java @@ -1,37 +1,15 @@ package electroblob.wizardry.util; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import electroblob.wizardry.entity.living.EntityBlazeMinion; -import electroblob.wizardry.entity.living.EntityIceGiant; -import electroblob.wizardry.entity.living.EntityIceWraith; -import electroblob.wizardry.entity.living.EntityLightningWraith; -import electroblob.wizardry.entity.living.EntityPhoenix; -import electroblob.wizardry.entity.living.EntityShadowWraith; -import electroblob.wizardry.entity.living.EntitySkeletonMinion; -import electroblob.wizardry.entity.living.EntitySpiderMinion; -import electroblob.wizardry.entity.living.EntityStormElemental; -import electroblob.wizardry.entity.living.EntityZombieMinion; +import electroblob.wizardry.entity.living.*; import net.minecraft.entity.Entity; import net.minecraft.entity.boss.EntityDragon; import net.minecraft.entity.boss.EntityWither; -import net.minecraft.entity.monster.EntityBlaze; -import net.minecraft.entity.monster.EntityCaveSpider; -import net.minecraft.entity.monster.EntityGhast; -import net.minecraft.entity.monster.EntityMagmaCube; -import net.minecraft.entity.monster.EntityPigZombie; -import net.minecraft.entity.monster.EntitySkeleton; -import net.minecraft.entity.monster.EntitySnowman; -import net.minecraft.entity.monster.EntitySpider; -import net.minecraft.entity.monster.EntityWitherSkeleton; -import net.minecraft.entity.monster.EntityZombie; +import net.minecraft.entity.monster.*; import net.minecraft.util.DamageSource; import net.minecraft.util.EntityDamageSource; +import java.util.*; + // A note on the use of the vanilla damagesources: // When using indirect damage sources, the SECOND argument is the original entity (i.e. the caster), and the // FIRST argument is the actual projectile or whatever that does the damage. getTrueSource() will return @@ -47,12 +25,12 @@ import net.minecraft.util.EntityDamageSource; /** * "Ouch, that hurt!" - *

    + *

    * As of wizardry 1.1, this class has replaced the damagesource-related methods in WizardryUtilities, allowing a * {@link DamageType} to be specified with the damage. The main reason for this is so that damage sources can fit with * the vanilla behaviour on armour enchantments and such like whilst still being classified as wizardry damage for the * purposes of friendly fire, etc. - *

    + *

    * In the future, there is scope for an entirely standalone mod based on this idea. Perhaps 'Elemental Damage' could * be a config-only mod which allows its users to define any number of specific damage types, then give any creature a * resistance, immunity or vulnerability to each, as well as being able to specify the sources for each type, such as @@ -71,7 +49,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage /** The name of the damagesource for indirect magic damage from the wizardry mod. */ public static final String INDIRECT_MAGIC_DAMAGE = "indirect_wizardry_magic"; // Technically, I don't need to specify that the classes in this map must extend entity, but it's good practice to. - private static final Map, DamageType[]> immunityMapping = new HashMap, DamageType[]>(); + private static final Map, DamageType[]> immunityMapping = new HashMap<>(); private final DamageType type; private final boolean isRetaliatory; @@ -82,29 +60,29 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * them. */ public enum DamageType { - /** Generic magic damage from the wizardry mod. Like vanilla magic damage, except it doesn't bypass armour. */ + /** Generic magic damage from wizardry. Like vanilla magic damage, except it doesn't bypass armour. */ MAGIC, - /** Fire damage from the wizardry mod. Counts as fire damage in the vanilla system, so is blocked by any mobs + /** Fire damage from wizardry. Counts as fire damage in the vanilla system, so is blocked by any mobs * that are immune to fire and entities with the fire resistance effect, and is affected by the fire protection * enchantment. */ FIRE, - /** Frost (ice) damage from the wizardry mod. Snow golems, ice wraiths and ice giants are immune. */ + /** Frost (ice) damage from wizardry. Snow golems, ice wraiths and ice giants are immune. */ FROST, - /** Shock (lightning) damage from the wizardry mod. Lightning wraiths and storm elementals are immune. */ + /** Shock (lightning) damage from wizardry. Lightning wraiths and storm elementals are immune. */ SHOCK, - /** Wither damage from the wizardry mod. Withers, wither skeletons and shadow wraiths are immune. */ + /** Wither damage from wizardry. Withers, wither skeletons and shadow wraiths are immune. */ WITHER, - /** Poison damage from the wizardry mod. Spiders, cave spiders and undead mobs are immune. */ + /** Poison damage from wizardry. Spiders, cave spiders and undead mobs are immune. */ POISON, - /** Force damage from the wizardry mod. */ // Insubstantial creatures (ghast, shadow wraith, etc.) are immune? + /** Force damage from wizardry. */ // Insubstantial creatures (ghast, shadow wraith, etc.) are immune? FORCE, - /** Blast damage from the wizardry mod. Affected by the blast protection enchantment. */ + /** Blast damage from wizardry. Affected by the blast protection enchantment. */ BLAST, - /** Radiant damage from the wizardry mod. */ - RADIANT; + /** Radiant damage from wizardry. */ + RADIANT } - static{ + static { // Of course, the entities that are immune to fire already are since there's a vanilla system for that, but // they're included here anyway for completeness and in case anyone wants to check if an entity is immune to // an unspecified element for reasons other than dealing damage. @@ -118,6 +96,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage setEntityImmunities(EntityStormElemental.class, DamageType.FIRE, DamageType.SHOCK); setEntityImmunities(EntityWither.class, DamageType.FIRE, DamageType.WITHER); setEntityImmunities(EntitySnowman.class, DamageType.FROST); + setEntityImmunities(EntityPolarBear.class, DamageType.FROST); setEntityImmunities(EntityIceWraith.class, DamageType.FROST); setEntityImmunities(EntityIceGiant.class, DamageType.FROST); setEntityImmunities(EntityLightningWraith.class, DamageType.SHOCK); @@ -165,7 +144,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage /** Adds the passed in damage type to the list of damage types to which the given entity is immune. */ public static void addEntityImmunity(Class entityType, DamageType immunity){ - List immunities = immunityMapping.get(entityType) == null ? new ArrayList() + List immunities = immunityMapping.get(entityType) == null ? new ArrayList<>() : Arrays.asList(immunityMapping.get(entityType)); immunities.add(immunity); // Apparently putting 0 here works just fine. @@ -178,7 +157,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * not bypass armour and has a player as the source (rather than nothing). It is still classed as magic damage (for * the record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway). * isRetaliatory defaults to false. - *

    + *

    * Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the * entire mod just to get rid of this method and use the constructor instead. * @@ -186,7 +165,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * @param type The type that this damage belongs to; used for resistances and wand perks. Use * {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element * even though the spell has one - for example, not all necromancy spells are 'withery', so some of them - * might reasonably affect creatures that are ususally immune to wither effects). + * might reasonably affect creatures that are usually immune to wither effects). * @return A damagesource object of type EntityDamageSource */ public static DamageSource causeDirectMagicDamage(Entity caster, DamageType type){ @@ -198,7 +177,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * types to allow things to distinguish between magic and regular melee/swords. Unlike DamageSource.MAGIC, it does * not bypass armour and has a player as the source (rather than nothing). It is still classed as magic damage (for * the record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway). - *

    + *

    * Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the * entire mod just to get rid of this method and use the constructor instead. * @@ -206,7 +185,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * @param type The type that this damage belongs to; used for resistances and wand perks. Use * {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element * even though the spell has one - for example, not all necromancy spells are 'withery', so some of them - * might reasonably affect creatures that are ususally immune to wither effects). + * might reasonably affect creatures that are usually immune to wither effects). * @param isRetaliatory whether this damage source came from a retaliatory attack; prevents infinite loops occurring * when two entities damage each other with retaliatory effects. * @return A damagesource object of type EntityDamageSource @@ -221,7 +200,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * DamageSource.causeIndirectMagicDamage, it does not bypass armour. It is still classed as magic damage (for the * record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway). * isRetaliatory defaults to false. - *

    + *

    * Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the * entire mod just to get rid of this method and use the constructor instead. * @@ -230,7 +209,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * @param type The type that this damage belongs to; used for resistances and wand perks. Use * {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element * even though the spell has one - for example, not all necromancy spells are 'withery', so some of them - * might reasonably affect creatures that are ususally immune to wither effects). + * might reasonably affect creatures that are usually immune to wither effects). * @return A damagesource object of type EntityDamageSourceIndirect */ public static DamageSource causeIndirectMagicDamage(Entity magic, Entity caster, DamageType type){ @@ -242,7 +221,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * types to allow things to distinguish between magic and regular arrows/throwables. Unlike * DamageSource.causeIndirectMagicDamage, it does not bypass armour. It is still classed as magic damage (for the * record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway). - *

    + *

    * Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the * entire mod just to get rid of this method and use the constructor instead. * @@ -251,7 +230,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage * @param type The type that this damage belongs to; used for resistances and wand perks. Use * {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element * even though the spell has one - for example, not all necromancy spells are 'withery', so some of them - * might reasonably affect creatures that are ususally immune to wither effects). + * might reasonably affect creatures that are usually immune to wither effects). * @param isRetaliatory whether this damage source came from a retaliatory attack; prevents infinite loops occurring * when two entities damage each other with retaliatory effects. * @return A damagesource object of type EntityDamageSourceIndirect diff --git a/src/main/java/electroblob/wizardry/util/NBTExtras.java b/src/main/java/electroblob/wizardry/util/NBTExtras.java new file mode 100644 index 00000000..309fa217 --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/NBTExtras.java @@ -0,0 +1,231 @@ +package electroblob.wizardry.util; + +import electroblob.wizardry.Wizardry; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import java.util.*; +import java.util.function.Function; + +/** + * Contains a number of useful static methods for interacting with NBT data, particularly involving collections. + * This was split off from {@link WizardryUtilities} as of wizardry 4.2 in an effort to make the code easier to navigate. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +public final class NBTExtras { + + private NBTExtras(){} // No instances! + + /** + * Generic method that stores any Map to an NBTTagList, given two functions that convert the key and value types in + * that map to subclasses of NBTBase. For what it's worth, there is very little point in using this unless you can + * use something more concise than an anonymous class to do the conversion. A lambda expression, or better, a method + * reference, would fit nicely. For example, take ExtendedPlayer's use of this to store conjured item durations: + *

    + * properties.setTag("conjuredItems", WizardryUtilities.mapToNBT(this.conjuredItemDurations, + * item -> new NBTTagInt(Item.getIdFromItem((Item)item)), NBTTagInt::new)); + *

    + * This is a lot nicer than simply iterating through the map, because for that you need to use the entry list, which + * introduces local variables that aren't really necessary. Notice that, since the values V in the map are simply + * Integer objects, a simple constructor reference to NBTTagInt::new can be used instead of a lambda expression (the + * Integer is auto-unboxed to int). + * + * @param The type of key stored in the given Map. + * @param The type of value stored in the given Map. + * @param The subtype of NBTBase that the keys (of type K) will be converted to. + * @param The subtype of NBTBase that the values (of type V) will be converted to. + * @param map The Map to be stored. + * @param keyFunction A Function that converts the keys in the map to NBT objects that can be stored. + * @param valueFunction A Function that converts the values in the map to NBT objects that can be stored. + * @param keyTagName The tag name to use for the key tags. + * @param valueTagName The tag name to use for the value tags. + * @return An NBTTagList that represents the given Map. + */ + public static NBTTagList mapToNBT(Map map, + Function keyFunction, Function valueFunction, String keyTagName, String valueTagName){ + + NBTTagList tagList = new NBTTagList(); + + for(Map.Entry entry : map.entrySet()){ + NBTTagCompound mapping = new NBTTagCompound(); + mapping.setTag(keyTagName, keyFunction.apply(entry.getKey())); + mapping.setTag(valueTagName, valueFunction.apply(entry.getValue())); + tagList.appendTag(mapping); + } + + return tagList; + } + + /** + * See {@link NBTExtras#mapToNBT(Map, Function, Function, String, String)}; this version is for when the + * names of the individual key/value tags are unimportant (they default to "key" and "value" respectively). + */ + public static NBTTagList mapToNBT(Map map, + Function keyFunction, Function valueFunction){ + return mapToNBT(map, keyFunction, valueFunction, "key", "value"); + } + + /** + * Generic method that reads a Map from an NBTTagList, given two functions that convert the key and value tag types + * into the key and value types in the returned map. The given NBTTagList remains unchanged after calling this + * method. + * + * @param The type of key stored in the returned Map. + * @param The type of value stored in the returned Map. + * @param The subtype of NBTBase that the keys are stored as. + * @param The subtype of NBTBase that the values are stored as. + * @param tagList The NBTTagList to be converted. This must be a list of compound tags. + * @param keyFunction A Function that converts the generic NBTBase tags in the list to keys of type K for the map. + * @param valueFunction A Function that converts the generic NBTBase tags in the list to values of type V for the + * map. + * @param keyTagName The tag name used for the key tags. + * @param valueTagName The tag name used for the value tags. + * @return A Map containing the keys and values stored in the given NBTTagList. Can be empty, but not null. + * @throws ClassCastException If the tags are not of the expected type. + * @see NBTExtras#mapToNBT(Map, Function, Function, String, String) + */ + @SuppressWarnings("unchecked") // Intentional, because throwing an exception is appropriate here. + public static Map NBTToMap(NBTTagList tagList, + Function keyFunction, Function valueFunction, String keyTagName, String valueTagName){ + + Map map = new HashMap<>(); + + for(int i = 0; i < tagList.tagCount(); i++){ + NBTTagCompound mapping = tagList.getCompoundTagAt(i); + NBTBase keyTag = mapping.getTag(keyTagName); + NBTBase valueTag = mapping.getTag(valueTagName); + K key = null; + try{ + key = keyFunction.apply((L)keyTag); + }catch (ClassCastException e){ + Wizardry.logger.error( + "Error when reading map from NBT: unexpected tag type " + NBTBase.NBT_TYPES[keyTag.getId()], e); + } + V value = null; + try{ + value = valueFunction.apply((W)valueTag); + }catch (ClassCastException e){ + Wizardry.logger.error( + "Error when reading map from NBT: unexpected tag type " + NBTBase.NBT_TYPES[valueTag.getId()], + e); + } + map.put(key, value); + } + + return map; + } + + /** + * See {@link NBTExtras#NBTToMap(NBTTagList, Function, Function, String, String)}; this version is for when + * the names of the individual key/value tags are unimportant (they default to "key" and "value" respectively). + */ + public static Map NBTToMap(NBTTagList tagList, + Function keyFunction, Function valueFunction){ + return NBTToMap(tagList, keyFunction, valueFunction, "key", "value"); + } + + /** + * Stores the given {@link Collection} to an {@link NBTTagList} and returns it, converting the elements in the + * collection to NBT tags (subclasses of {@link NBTBase}) according to the supplied mapper function. + * + * @param The type of element stored in the given collection. + * @param The NBT tag type that the elements will be converted to. + * @param list The collection to be stored. + * @param mapper A function that converts the elements in the collection to NBT objects that can be stored. + * @return An {@code NBTTagList} that represents the given collection. + */ + public static NBTTagList listToNBT(Collection list, Function mapper){ + + NBTTagList tagList = new NBTTagList(); + // If the collection is ordered, it will preserve the order, even though we don't know what type it is yet. + for(E element : list){ + tagList.appendTag(mapper.apply(element)); + } + + return tagList; + } + + /** + * Reads a {@link Collection} from the given {@link NBTTagList}, given a function that converts the element tag + * types to the element types in the returned collection. The given {@code NBTTagList} remains unchanged after + * calling this method. Unless the target variable for this method is of type {@code Collection}, you will need to + * create a new collection containing the elements in the returned collection via that collection's constructor (e.g. + * {@code new HashSet(collection)}). + *

    + * Although this method returns a Collection rather than any of its subtypes, it uses + * an ArrayList internally to guarantee the order of the elements in the returned collection is the same as the + * order in which they were stored. + * + * @param The type of element stored in the returned Collection. + * @param The subtype of NBTBase that the elements are stored as. + * @param tagList The NBTTagList to be converted. + * @param function A Function that converts the generic NBTBase tags in the list to elements for the collection. + * Chances are you will need to cast the NBTBase tag to whichever NBT tag type you are expecting in order to + * access the appropriate getter method. + * @return A Collection containing the elements stored in the given NBTTagList. Can be empty, but not null. + * @throws ClassCastException If the tags are not of the expected type. + */ + @SuppressWarnings("unchecked") // Intentional, because throwing an exception is appropriate here. + public static Collection NBTToList(NBTTagList tagList, Function function){ + // Uses an ArrayList to guarantee iteration order, and also to permit duplicate elements (which are + // perfectly reasonable in this context). + Collection list = new ArrayList<>(); + // The original tag list should remain unchanged, hence the copy. + NBTTagList tagList2 = tagList.copy(); + + while(!tagList2.isEmpty()){ + NBTBase tag = tagList2.removeTag(0); + // Why oh why is NBTTagList not parametrised? It even has a tagType field, so it must know! + try{ + list.add(function.apply((T)tag)); + }catch (ClassCastException e){ + Wizardry.logger.error( + "Error when reading list from NBT: unexpected tag type " + NBTBase.NBT_TYPES[tag.getId()], e); + } + } + + return list; + + } + + /** + * Removes the UUID with the given key from the given NBT tag, if any. Why this doesn't exist in vanilla I have + * no idea. + *

    + * Usage note: this method complements {@link NBTTagCompound#setUniqueId(String, UUID)} and + * {@link NBTTagCompound#getUniqueId(String)}, which store UUIDs by appending "Most" and "Least" to the given + * key to store the most and least significant UUID bits respectively. It will not work for the UUID methods in + * {@link net.minecraft.nbt.NBTUtil}, which store the long values under "M" and "L" in their own compound tag. + */ + public static void removeUniqueId(NBTTagCompound tag, String key){ + tag.removeTag(key + "Most"); + tag.removeTag(key + "Least"); + } + + /** + * Returns an NBTTagCompound which contains only the given UUID, stored using + * {@link NBTTagCompound#setUniqueId(String, UUID)}. Allows for neater storage to NBTTagLists. + * @deprecated Use {@link net.minecraft.nbt.NBTUtil#createUUIDTag(UUID)}. Note that this will break backwards + * compatibility because it uses "M" and "L" instead of "uuidMost" and "uuidLeast". + */ + @Deprecated + public static NBTTagCompound UUIDtoTagCompound(UUID id){ + NBTTagCompound tag = new NBTTagCompound(); + tag.setUniqueId("uuid", id); + return tag; + } + + /** + * Wrapper for {@link NBTTagCompound#getUniqueId(String)} which converts an NBTTagCompound directly to a UUID. + * Intended to be used as the inverse of {@link NBTExtras#UUIDtoTagCompound(UUID)}. + * @deprecated Use {@link net.minecraft.nbt.NBTUtil#getUUIDFromTag(NBTTagCompound)}. Note that this will break + * backwards compatibility because it uses "M" and "L" instead of "uuidMost" and "uuidLeast". + */ + @Deprecated + public static UUID tagCompoundToUUID(NBTTagCompound tag){ + return tag.getUniqueId("uuid"); + } +} diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index eb78c50b..273875b2 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -1,45 +1,51 @@ package electroblob.wizardry.util; -import java.util.Random; - import electroblob.wizardry.Wizardry; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import java.util.Random; + /** * "Don't waste time spawning particles manually - let {@code ParticleBuilder} do the work for you!" - *

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

    + *

    + * Singleton class that builds wizardry particles. This is an alternative (and neater, I think) solution to vanilla's + * varargs-based system. All building methods are chainable, so particles can be created using only one line of code, + * similar to how {@code BufferBuilder} is used for drawing vertices. This class replaces the particle spawning methods + * in wizardry's proxies. + *

    * {@link ParticleBuilder#instance} retrieves the static instance of the particle builder. Use - * {@link ParticleBuilder#particle(Type)} to start building a particle, or alternatively use the static - * convenience version {@link ParticleBuilder#create(Type)}. Use {@link ParticleBuilder#spawn(World)} + * {@link ParticleBuilder#particle(ResourceLocation)} to start building a particle, or alternatively use the static + * convenience version {@link ParticleBuilder#create(ResourceLocation)}. Use {@link ParticleBuilder#spawn(World)} * to finish building and spawn the particle. Between these two, a variety of parameters can be set using the various * setter methods (see individual method descriptions for more details). These, along with {@code ParticleBuilder.particle(...)}, * return the particle builder instance, allowing them to be chained together to spawn particles using a single line of code. * If any parameters are unspecified these will default to certain values, which may or may not depend on the particle type. * Not all parameters affect all particles. Again, see individual method descriptions for more details. - *

    + *

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

    + *

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

    + *

    * It also goes without saying that this class should only ever be used client-side. Attempting to spawn particles * on the server side will not work and will print a warning to the console. * @author Electroblob * @since Wizardry 4.2 */ -/* This isn't strictly a builder class in the traditional sense, because rather than returning the built object at the - * end, it sends it to be processed instead and returns nothing. It's also lazy, see the comment about builder variables - * below. */ +// The number of different combinations of parameters now required for the various particle +// types in wizardry made the method overloads in the proxies very cumbersome and inevitably resulted in redundant +// parameters, which made the code messy and hard to read. Those methods have now been removed. + +// Strictly speaking, this isn't a builder class in the traditional sense, because rather than returning the built +// object at the end, it sends it to be processed instead and returns nothing. Additionally, unlike most builders +// it's a singleton, because it's likely to be called very frequently and there's no point making a new instance +// every time and clogging the heap with objects. It's also lazy, see the comment about builder variables below. public final class ParticleBuilder { /** The static instance of the particle builder. */ @@ -51,7 +57,7 @@ public final class ParticleBuilder { // Builder variables // We can't just store a particle and set its parameters in the builder methods, because the server won't like having // a field of a client-only type - private Type type; + private ResourceLocation type; private double x, y, z; private double vx, vy, vz; private float r, g, b; @@ -66,36 +72,66 @@ public final class ParticleBuilder { private Entity entity; private float yaw, pitch; private double tx, ty, tz; + private double tvx, tvy, tvz; private Entity target; + private long seed; + private double length; - /** Enum constants representing the different types of particle added by wizardry. As of 4.2.0, this has been moved - * from its own file {@code WizardryParticleType} to inside {@link ParticleBuilder}. This allowed its name to be - * shortened to simply {@code Type}, making most references more concise. References in classes where another - * {@code Type} is also used can simply refer to the full name, {@code ParticleBuilder.Type}, which is no more verbose - * than before. - *

    + /** + * {@link ResourceLocation} constants representing the different types of particle added by wizardry. These + * effectively replace the enum {@code WizardryParticleType} from previous versions. + *

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

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

    Defaults:

    Lifetime: 48-60 ticks
    Colour: white */ SPARKLE + * randomness. + *

    + * To register your own particle types, use {@link electroblob.wizardry.client.particle.ParticleWizardry#registerParticle( + * ResourceLocation, electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory) + * ParticleWizardry.registerParticle(ResourceLocation, IWizardryParticleFactory)}. + */ + // This was originally an enum, but I think having 'Type' explicitly declared is quite nice so I've left it as a + // nested class. + public static class Type { + /** 3D-rendered light-beam particle.

    Defaults:
    Lifetime: 1 tick
    Colour: white */ + public static final ResourceLocation BEAM = new ResourceLocation(Wizardry.MODID,"beam"); + /** Helical animated 'buffing' particle.

    Defaults:
    Lifetime: 15 ticks + *
    Velocity: (0, 0.27, 0)
    Colour: white */ + public static final ResourceLocation BUFF = new ResourceLocation(Wizardry.MODID,"buff"); + /** Spiral particle, like potions.

    Defaults:
    Lifetime: 8-40 ticks
    Colour: white */ + public static final ResourceLocation DARK_MAGIC = new ResourceLocation(Wizardry.MODID,"dark_magic"); + /** Single pixel particle.

    Defaults:
    Lifetime: 16-80 ticks
    Colour: white */ + public static final ResourceLocation DUST = new ResourceLocation(Wizardry.MODID,"dust"); + /** Rapid flash, like fireworks.

    Defaults:
    Lifetime: 6 ticks
    Colour: white */ + public static final ResourceLocation FLASH = new ResourceLocation(Wizardry.MODID,"flash"); + /** Small shard of ice.

    Defaults:
    Lifetime: 8-40 ticks
    Gravity: true */ + public static final ResourceLocation ICE = new ResourceLocation(Wizardry.MODID,"ice"); + /** Single leaf.

    Defaults:
    Lifetime: 10-15 ticks
    Velocity: (0, -0.03, 0) + *
    Colour: green/brown */ + public static final ResourceLocation LEAF = new ResourceLocation(Wizardry.MODID,"leaf"); + /** 3D-rendered lightning particle.

    Defaults:
    Lifetime: 3 ticks
    Colour: blue */ + public static final ResourceLocation LIGHTNING = new ResourceLocation(Wizardry.MODID,"lightning"); + /** 2D lightning effect, normally on the ground.

    Defaults:
    Lifetime: 7 ticks + *
    Facing: up */ + public static final ResourceLocation LIGHTNING_PULSE = new ResourceLocation(Wizardry.MODID,"lightning_pulse"); + /** Bubble that doesn't burst in air.

    Defaults:
    Lifetime: 8-40 ticks */ + public static final ResourceLocation MAGIC_BUBBLE = new ResourceLocation(Wizardry.MODID,"magic_bubble"); + /** Animated flame.

    Defaults:
    Lifetime: 12-16 ticks
    */ + public static final ResourceLocation MAGIC_FIRE = new ResourceLocation(Wizardry.MODID,"magic_fire"); + /** Soft-edged round particle.

    Defaults:
    Lifetime: 8-40 ticks
    Colour: white */ + public static final ResourceLocation PATH = new ResourceLocation(Wizardry.MODID,"path"); + /** Scorch mark.

    Defaults:
    Lifetime: 100-140 ticks
    Colour: black
    Fade: black */ + public static final ResourceLocation SCORCH = new ResourceLocation(Wizardry.MODID,"scorch"); + /** Snowflake particle.

    Defaults:
    Lifetime: 40-50 ticks
    Velocity: (0, -0.02, 0) */ + public static final ResourceLocation SNOW = new ResourceLocation(Wizardry.MODID,"snow"); + /** Animated lightning particle.

    Defaults:
    Lifetime: 3 ticks */ + public static final ResourceLocation SPARK = new ResourceLocation(Wizardry.MODID,"spark"); + /** Animated sparkle particle.

    Defaults:<
    Lifetime: 48-60 ticks
    Colour: white */ + public static final ResourceLocation SPARKLE = new ResourceLocation(Wizardry.MODID,"sparkle"); + /** 3D-rendered expanding sphere.

    Defaults:<
    Lifetime: 6 ticks
    Colour: white */ + public static final ResourceLocation SPHERE = new ResourceLocation(Wizardry.MODID,"sphere"); + /** Wrapped animated 'summoning' particle.

    Defaults:<
    Lifetime: 15 ticks */ + public static final ResourceLocation SUMMON = new ResourceLocation(Wizardry.MODID,"summon"); + /** 3D-rendered vine particle.

    Defaults:
    Lifetime: 1 tick
    Colour: green */ + public static final ResourceLocation VINE = new ResourceLocation(Wizardry.MODID,"vine"); } private ParticleBuilder(){ @@ -106,12 +142,12 @@ public final class ParticleBuilder { /** * Starts building a particle of the given type. Static convenience version of - * {@link ParticleBuilder#particle(Type)}; makes code more concise. + * {@link ParticleBuilder#particle(ResourceLocation)}; makes code more concise. * @param type The type of particle to build * @return The particle builder instance, allowing other methods to be chained onto this one * @throws IllegalStateException if the particle builder is already building. */ - public static ParticleBuilder create(Type type){ + public static ParticleBuilder create(ResourceLocation type){ return ParticleBuilder.instance.particle(type); } @@ -121,8 +157,8 @@ public final class ParticleBuilder { * @return The particle builder instance, allowing other methods to be chained onto this one * @throws IllegalStateException if the particle builder is already building. */ - public ParticleBuilder particle(Type type){ - if(building) throw new IllegalStateException("Already Building! Particle being built: " + getCurrentParticleString()); + public ParticleBuilder particle(ResourceLocation type){ + if(building) throw new IllegalStateException("Already building! Particle being built: " + getCurrentParticleString()); this.type = type; this.building = true; return this; @@ -131,7 +167,7 @@ public final class ParticleBuilder { /** Gets a readable string representation of the current builder parameters; used in error messages. */ private String getCurrentParticleString(){ return String.format("[ Type: %s, Position: (%s, %s, %s), Velocity: (%s, %s, %s), Colour: (%s, %s, %s), " - + "Fade Colour: (%s, %s, %s), Radius: %s, Revs/tick: %s, Lifetime: %s, Gravity: %s, Shaded: %s," + + "Fade Colour: (%s, %s, %s), Radius: %s, Revs/tick: %s, Lifetime: %s, Gravity: %s, Shaded: %s, " + "Scale: %s, Entity: %s ]", type, x, y, z, vx, vy, vz, r, g, b, fr, fg, fb, radius, rpt, lifetime, gravity, shaded, scale, entity); } @@ -139,7 +175,7 @@ public final class ParticleBuilder { /** * Sets the position of the particle being built. If unspecified, this defaults to the origin (0, 0, 0). If an entity * is specified using {@link ParticleBuilder#entity(Entity)}, this will be relative to that entity's position. - *

    + *

    * Affects: All particle types * @param x The x coordinate to set * @param y The y coordinate to set @@ -158,7 +194,7 @@ public final class ParticleBuilder { /** * Sets the position of the particle being built. This is a vector-based alternative to {@link ParticleBuilder#pos( * double, double, double)}, allowing for even more concise code when a vector is available. - *

    + *

    * Affects: All particle types * @param pos A vector representing the coordinates of the particle to be built. * @return The particle builder instance, allowing other methods to be chained onto this one @@ -171,8 +207,8 @@ public final class ParticleBuilder { /** * Sets the velocity of the particle being built. If unspecified, this defaults to the particle's default velocity, * specified within its constructor. - *

    - * Affects: All particle types except {@link Type#DUST DUST} + *

    + * Affects: All particle types * @param vx The x velocity to set * @param vy The y velocity to set * @param vz The z velocity to set @@ -190,8 +226,8 @@ public final class ParticleBuilder { /** * Sets the velocity of the particle being built. This is a vector-based alternative to {@link ParticleBuilder#vel( * double, double, double)}, allowing for even more concise code when a vector is available. - *

    - * Affects: All particle types + *

    + * Affects: All particle types except * @param vel A vector representing the velocity of the particle to be built. * @return The particle builder instance, allowing other methods to be chained onto this one * @throws IllegalStateException if the particle builder is not yet building. @@ -202,10 +238,11 @@ public final class ParticleBuilder { /** * Sets the colour of the particle being built. If unspecified, this defaults to the particle's default colour, - * specified within its constructor. - *

    - * Affects: {@link Type#DARK_MAGIC DARK_MAGIC}, {@link Type#DUST DUST}, {@link Type#FLASH FLASH}, - * {@link Type#LEAF LEAF}, {@link Type#PATH PATH}, {@link Type#SPARKLE SPARKLE} + * specified within its constructor. If all colour components are 0 or 1, at least one must have the float suffix + * ({@code f} or {@code F}) or the integer overload will be used instead, causing the particle to appear black! + *

    + * Affects: All particle types except {@link Type#ICE ICE}, {@link Type#MAGIC_BUBBLE MAGIC_BUBBLE} + * and {@link Type#MAGIC_FIRE MAGIC_FIRE} * @param r The red colour component to set; will be clamped to between 0 and 1 * @param g The green colour component to set; will be clamped to between 0 and 1 * @param b The blue colour component to set; will be clamped to between 0 and 1 @@ -219,13 +256,47 @@ public final class ParticleBuilder { this.b = MathHelper.clamp(b, 0, 1); return this; } + + /** + * Sets the colour of the particle being built. This is an 8-bit (0-255) integer version of + * {@link ParticleBuilder#clr(float, float, float)}. + *

    + * Affects: All particle types except {@link Type#ICE ICE}, {@link Type#MAGIC_BUBBLE MAGIC_BUBBLE} + * and {@link Type#MAGIC_FIRE MAGIC_FIRE} + * @param r The red colour component to set; will be clamped to between 0 and 255 + * @param g The green colour component to set; will be clamped to between 0 and 255 + * @param b The blue colour component to set; will be clamped to between 0 and 255 + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder clr(int r, int g, int b){ + return this.clr(r/255f, g/255f, b/255f); // Yes, 255 is correct and not 256, or else we can't have pure white + } + + /** + * Sets the colour of the particle being built. This is a 6-digit hex colour version of + * {@link ParticleBuilder#clr(float, float, float)}. + *

    + * Affects: All particle types except {@link Type#ICE ICE}, {@link Type#MAGIC_BUBBLE MAGIC_BUBBLE} + * and {@link Type#MAGIC_FIRE MAGIC_FIRE} + * @param hex The colour to be set, as a packed 6-digit hex integer (e.g. 0xff0000). + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder clr(int hex){ + int r = (hex & 0xFF0000) >> 16; + int g = (hex & 0xFF00) >> 8; + int b = (hex & 0xFF); + return this.clr(r, g, b); + } /** * Sets the fade colour of the particle being built. If unspecified, this defaults to the whatever the particle's base - * colour is. - *

    - * Affects: {@link Type#DARK_MAGIC DARK_MAGIC}, {@link Type#DUST DUST}, {@link Type#FLASH FLASH}, - * {@link Type#LEAF LEAF}, {@link Type#PATH PATH}, {@link Type#SPARKLE SPARKLE} + * colour is. If all colour components are 0 or 1, at least one must have the float suffix + * ({@code f} or {@code F}) or the integer overload will be used instead, causing the particle to appear black! + *

    + * Affects: All particle types except {@link Type#ICE ICE}, {@link Type#MAGIC_BUBBLE MAGIC_BUBBLE} + * and {@link Type#MAGIC_FIRE MAGIC_FIRE} * @param r The red colour component to set; will be clamped to between 0 and 1 * @param g The green colour component to set; will be clamped to between 0 and 1 * @param b The blue colour component to set; will be clamped to between 0 and 1 @@ -239,10 +310,43 @@ public final class ParticleBuilder { this.fb = MathHelper.clamp(b, 0, 1); return this; } + + /** + * Sets the fade colour of the particle being built. This is an 8-bit (0-255) integer version of + * {@link ParticleBuilder#fade(float, float, float)}. + *

    + * Affects: All particle types except {@link Type#ICE ICE}, {@link Type#MAGIC_BUBBLE MAGIC_BUBBLE} + * and {@link Type#MAGIC_FIRE MAGIC_FIRE} + * @param r The red colour component to set; will be clamped to between 0 and 255 + * @param g The green colour component to set; will be clamped to between 0 and 255 + * @param b The blue colour component to set; will be clamped to between 0 and 255 + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder fade(int r, int g, int b){ + return this.clr(r/255f, g/255f, b/255f); // Yes, 255 is correct and not 256, or else we can't have pure white + } + + /** + * Sets the fade colour of the particle being built. This is a 6-digit hex colour version of + * {@link ParticleBuilder#fade(float, float, float)}. + *

    + * Affects: All particle types except {@link Type#ICE ICE}, {@link Type#MAGIC_BUBBLE MAGIC_BUBBLE} + * and {@link Type#MAGIC_FIRE MAGIC_FIRE} + * @param hex The colour to be set, as a packed 6-digit hex integer (e.g. 0xff0000). + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder fade(int hex){ + int r = (hex & 0xFF0000) >> 16; + int g = (hex & 0xFF00) >> 8; + int b = (hex & 0xFF); + return this.clr(r, g, b); + } /** * Sets the scale of the particle being built. If unspecified, this defaults to 1. - *

    + *

    * Affects: All particle types * @param scale The scale to set, as a multiple of the particle's default scale * @return The particle builder instance, allowing other methods to be chained onto this one @@ -257,7 +361,7 @@ public final class ParticleBuilder { /** * Sets the lifetime of the particle being built. If unspecified, this defaults to the particle's default lifetime, * specified within its constructor. - *

    + *

    * Affects: All particle types * @param lifetime The lifetime to set in ticks * @return The particle builder instance, allowing other methods to be chained onto this one @@ -268,10 +372,28 @@ public final class ParticleBuilder { this.lifetime = lifetime; return this; } + + /** + * Sets the seed of the particle being built. If unspecified, this defaults to the particle's default seed, + * specified within its constructor (this is normally chosen at random). + *

    + * Pro tip: to get a particle to stay the same while a continuous spell is in use (but change between casts), + * use {@code .seed(world.getTotalWorldTime() - ticksInUse)}. + *

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

    + *

    * Affects: All particle types * @param radius The rotation radius to set * @param speed The rotation speed to set, in revolutions per tick @@ -284,11 +406,12 @@ public final class ParticleBuilder { this.rpt = speed; return this; } - + + // Used to say Affects: {@link Type#ICE ICE}, {@link Type#SPARKLE SPARKLE} - not sure that's true any more /** * Sets the gravity of the particle being built. If unspecified, this defaults to false. - *

    - * Affects: {@link Type#ICE ICE}, {@link Type#SPARKLE SPARKLE} + *

    + * Affects: All particle types * @param gravity True to enable gravity for the particle, false to disable * @return The particle builder instance, allowing other methods to be chained onto this one * @throws IllegalStateException if the particle builder is not yet building. @@ -301,7 +424,7 @@ public final class ParticleBuilder { /** * Sets the shading of the particle being built. If unspecified, this defaults to false. - *

    + *

    * Affects: All particle types * @param shaded True to enable shading for the particle, false for full brightness * @return The particle builder instance, allowing other methods to be chained onto this one @@ -315,7 +438,7 @@ public final class ParticleBuilder { /** * Sets the collisions of the particle being built. If unspecified, this defaults to false. - *

    + *

    * Affects: All particle types * @param collide True to enable block collisions for the particle, false to disable * @return The particle builder instance, allowing other methods to be chained onto this one @@ -331,7 +454,7 @@ public final class ParticleBuilder { * Sets the entity of the particle being built. This will cause the particle to move with the given entity, and will * make the position specified using {@link ParticleBuilder#pos(double, double, double)} relative to that * entity's position. - *

    + *

    * Affects: All particle types * @param entity The entity to set (passing in null will do nothing but will not cause any problems, so for the sake * of conciseness it is not necessary to perform a null check on the passed-in argument) @@ -347,7 +470,7 @@ public final class ParticleBuilder { /** * Sets the rotation of the particle being built. If unspecified, the particle will use the default behaviour and * rotate to face the viewer. - *

    + *

    * Affects: All particle types * @param yaw The yaw angle to set in degrees, where 0 is south. * @param pitch The pitch angle to set in degrees, where 0 is horizontal. @@ -365,7 +488,8 @@ public final class ParticleBuilder { * Sets the rotation of the particle being built. This is an {@code EnumFacing}-based alternative to {@link * ParticleBuilder#face(float, float)} which sets the yaw and pitch to the appropriate angles for the given facing. * For example, if the given facing is {@code NORTH}, the particle will render parallel to the north face of blocks. - *

    + * If unspecified, the particle will use the default behaviour and rotate to face the viewer. + *

    * Affects: All particle types * @param direction The {@code EnumFacing} direction to set. * @return The particle builder instance, allowing other methods to be chained onto this one @@ -374,11 +498,13 @@ public final class ParticleBuilder { public ParticleBuilder face(EnumFacing direction){ return face(direction.getHorizontalAngle(), direction.getAxis().isVertical() ? direction.getAxisDirection().getOffset() * 90 : 0); } + + // ============================================= Targeted-only methods ============================================= /** * Sets the target of the particle being built. This will cause the particle to stretch to touch the given position. - *

    - * Affects: + *

    + * Affects: Targeted particles, namely {@link Type#BEAM BEAM}, {@link Type#LIGHTNING LIGHTNING} and {@link Type#VINE VINE} * @param x The target x-coordinate to set * @param y The target y-coordinate to set * @param z The target z-coordinate to set @@ -394,10 +520,11 @@ public final class ParticleBuilder { } /** - * Sets the target of the particle being built. This is a vector-based alternative to {@link ParticleBuilder# - * target(double, double, double)}, allowing for even more concise code when a vector is available. - *

    - * Affects: All particle types + * Sets the target of the particle being built. This is a vector-based alternative to + * {@link ParticleBuilder#target(double, double, double)}, allowing for even more concise code when a vector is + * available. + *

    + * Affects: Targeted particles, namely {@link Type#BEAM BEAM}, {@link Type#LIGHTNING LIGHTNING} and {@link Type#VINE VINE} * @param pos A vector representing the target position of the particle to be built. * @return The particle builder instance, allowing other methods to be chained onto this one * @throws IllegalStateException if the particle builder is not yet building. @@ -405,11 +532,59 @@ public final class ParticleBuilder { public ParticleBuilder target(Vec3d pos){ return target(pos.x, pos.y, pos.z); } + + /** + * Sets the target point velocity of the particle being built. This will cause the position it stretches to touch to move + * at the given velocity. Has no effect unless {@link ParticleBuilder#target(double, double, double)} or one of its + * overloads is also set.

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

    + * Affects: Targeted particles, namely {@link Type#BEAM BEAM}, {@link Type#LIGHTNING LIGHTNING} and {@link Type#VINE VINE} + * @param vel A vector representing the target point velocity of the particle to be built. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder tvel(Vec3d vel){ + return tvel(vel.x, vel.y, vel.z); + } + + /** + * Sets the target and target velocity of the particle being built. This method takes an origin entity and a + * position and estimates the position of the target point based on the given entity's rotational velocities and its + * distance from the given position. + *

    + * Affects: Targeted particles, namely {@link Type#BEAM BEAM}, {@link Type#LIGHTNING LIGHTNING} and {@link Type#VINE VINE} + * @param length The length of the particle being built. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder length(double length){ + this.length = length; + return this; + } /** * Sets the target of the particle being built. This will cause the particle to stretch to touch the given entity. - *

    - * Affects: + *

    + * Affects: Targeted particles, namely {@link Type#BEAM BEAM}, {@link Type#LIGHTNING LIGHTNING} and {@link Type#VINE VINE} * @param target The entity to set * @return The particle builder instance, allowing other methods to be chained onto this one * @throws IllegalStateException if the particle builder is not yet building. @@ -429,7 +604,7 @@ public final class ParticleBuilder { if(!building) throw new IllegalStateException("Not building yet!"); - if(y < 0 && entity == null) Wizardry.logger.warn("Spawning particle below y = 0 - are you sure the position/entity" + if(y < 0 && entity == null) Wizardry.logger.warn("Spawning particle below y = 0 - are you sure the position/entity " + "has been set correctly?"); if(!world.isRemote){ @@ -443,22 +618,27 @@ public final class ParticleBuilder { electroblob.wizardry.client.particle.ParticleWizardry particle = Wizardry.proxy.createParticle(type, world, x, y, z); if(particle == null){ + // No need to display a warning here, we already did it in the client proxy reset(); return; } // Anything with an if statement here allows default values to be set in particle constructors + if(!Double.isNaN(vx) && !Double.isNaN(vy) && !Double.isNaN(vz)) particle.setVelocity(vx, vy, vz); + if(r >= 0 && g >= 0 && b >= 0) particle.setRBGColorF(r, g, b); + if(fr >= 0 && fg >= 0 && fb >= 0) particle.setFadeColour(fr, fg, fb); + if(lifetime >= 0) particle.setMaxAge(lifetime); + if(radius > 0) particle.setSpin(radius, rpt); + if(!Float.isNaN(yaw) && !Float.isNaN(pitch)) particle.setFacing(yaw, pitch); + if(seed != 0) particle.setSeed(seed); + if(!Double.isNaN(tvx) && !Double.isNaN(tvy) && !Double.isNaN(tvz)) particle.setTargetVelocity(tvx, tvy, tvz); + if(length > 0) particle.setLength(length); + particle.multipleParticleScaleBy(scale); - if(!Double.isNaN(vx) && !Double.isNaN(vy) && !Double.isNaN(vz)) particle.setVelocity(vx, vy, vz); - if(r >= 0 && g >= 0 && b >= 0) particle.setRBGColorF(r, g, b); - if(fr >= 0 && fg >= 0 && fb >= 0)particle.setFadeColour(fr, fg, fb); - if(lifetime >= 0) particle.setMaxAge(lifetime); particle.setGravity(gravity); particle.setShaded(shaded); particle.setCollisions(collide); - if(radius > 0) particle.setSpin(radius, rpt); particle.setEntity(entity); - if(!Float.isNaN(yaw) && !Float.isNaN(pitch)) particle.setFacing(yaw, pitch); particle.setTargetPosition(tx, ty, tz); particle.setTargetEntity(target); @@ -498,7 +678,12 @@ public final class ParticleBuilder { tx = Double.NaN; ty = Double.NaN; tz = Double.NaN; + tvx = Double.NaN; + tvy = Double.NaN; + tvz = Double.NaN; target = null; + seed = 0; + length = -1; } // ============================================== Convenience methods ============================================== @@ -513,14 +698,14 @@ public final class ParticleBuilder { * Equivalent to calling {@code ParticleBuilder.create(type).pos(...)}; users should chain any additional builder * methods onto this one and finish with {@code .spawn(world)} as normal. * Used extensively with summoned creatures; makes code much neater and more concise. - *

    + *

    * N.B. this does not cause the particle to move with the given entity. * @param type The type of particle to build * @param entity The entity to position the particle at * @return The particle builder instance, allowing other methods to be chained onto this one * @throws IllegalStateException if the particle builder is already building. */ - public static ParticleBuilder create(Type type, Entity entity){ + public static ParticleBuilder create(ResourceLocation type, Entity entity){ double x = entity.posX + (entity.world.rand.nextDouble() - 0.5D) * (double)entity.width; double y = entity.posY + entity.world.rand.nextDouble() * (double)entity.height; @@ -545,7 +730,7 @@ public final class ParticleBuilder { * @return The particle builder instance, allowing other methods to be chained onto this one * @throws IllegalStateException if the particle builder is already building. */ - public static ParticleBuilder create(Type type, Random random, double x, double y, double z, double radius, boolean move){ + public static ParticleBuilder create(ResourceLocation type, Random random, double x, double y, double z, double radius, boolean move){ double px = x + (random.nextDouble()*2 - 1) * radius; double py = y + (random.nextDouble()*2 - 1) * radius; @@ -560,7 +745,9 @@ public final class ParticleBuilder { /** Spawns spark and large smoke particles (8 of each) within a 1x1x1 volume centred on the given position. */ public static void spawnShockParticles(World world, double x, double y, double z) { + double px, py, pz; + for(int i=0; i<8; i++){ px = x + world.rand.nextDouble() - 0.5; py = y + world.rand.nextDouble() - 0.5; @@ -572,5 +759,19 @@ public final class ParticleBuilder { world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, px, py, pz, 0, 0, 0); } } + + /** Spawns golden-yellow sparkle particles around the given entity's head and a golden-yellow buff particle around + * its entire body. */ + public static void spawnHealParticles(World world, EntityLivingBase entity){ + + for(int i = 0; i < 10; i++){ + double x = entity.posX + world.rand.nextDouble() * 2 - 1; + double y = entity.getEntityBoundingBox().minY + entity.getEyeHeight() - 0.5 + world.rand.nextDouble(); + double z = entity.posZ + world.rand.nextDouble() * 2 - 1; + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(1, 1, 0.3f).spawn(world); + } + + ParticleBuilder.create(Type.BUFF).entity(entity).clr(1, 1, 0.3f).spawn(world); + } } diff --git a/src/main/java/electroblob/wizardry/util/RayTracer.java b/src/main/java/electroblob/wizardry/util/RayTracer.java new file mode 100644 index 00000000..6079251d --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/RayTracer.java @@ -0,0 +1,207 @@ +package electroblob.wizardry.util; + +import electroblob.wizardry.entity.ICustomHitbox; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.function.Predicate; + +/** + * Contains a number of static methods that perform raytracing and related functions. This was split off from + * {@link WizardryUtilities} as of wizardry 4.2 in an effort to make the code easier to navigate. + * + * @author Electroblob + * @since Wizardry 4.2 + */ +public final class RayTracer { + + private RayTracer(){} // No instances! + + /** + * Helper method which performs a ray trace for blocks only from an entity's eye position in the direction + * they are looking, over a specified range, using {@link World#rayTraceBlocks(Vec3d, Vec3d, boolean, boolean, boolean)}. + * + * @param world The world in which to perform the ray trace. + * @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye + * position and proceed in the direction the entity is looking. + * @param range The distance over which the ray trace will be performed. + * @param hitLiquids True to return hits on the surfaces of liquids, false to ignore liquid blocks as if they were + * not there. + * @return A {@link RayTraceResult} representing the object that was hit, which may be either a block or nothing. + * Returns {@code null} only if the origin and endpoint are within the same block. + */ + @Nullable + public static RayTraceResult standardBlockRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids, + boolean ignoreUncollidables, boolean returnLastUncollidable){ + // This method does not apply an offset like ray spells do, since it is not desirable in most other use cases. + Vec3d origin = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); + Vec3d endpoint = origin.add(entity.getLookVec().scale(range)); + return world.rayTraceBlocks(origin, endpoint, hitLiquids, ignoreUncollidables, returnLastUncollidable); + } + + /** + * Helper method which performs a ray trace for blocks only from an entity's eye position in the direction + * they are looking, over a specified range. This is a shorthand for + * {@link #standardBlockRayTrace(World, EntityLivingBase, double, boolean, boolean, boolean)}; ignoreUncollidables + * and returnLastUncollidable default to false. + */ + @Nullable + public static RayTraceResult standardBlockRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids){ + return standardBlockRayTrace(world, entity, range, hitLiquids, false, false); + } + + /** + * Helper method which performs a ray trace for blocks and entities from an entity's eye position in the direction + * they are looking, over a specified range, using {@link RayTracer#rayTrace(World, Vec3d, Vec3d, float, boolean, boolean, boolean, Class, Predicate)}. Aim assist is zero, the entity type is simply {@code Entity} (all entities), and the + * filter removes the given entity and any dying entities and allows all others. + * + * @param world The world in which to perform the ray trace. + * @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye + * position and proceed in the direction the entity is looking. This entity will be ignored when ray tracing. + * @param range The distance over which the ray trace will be performed. + * @param hitLiquids True to return hits on the surfaces of liquids, false to ignore liquid blocks as if they were + * not there. + * @return A {@link RayTraceResult} representing the object that was hit, which may be an entity, a block or + * nothing. Returns {@code null} only if the origin and endpoint are within the same block and no entity was hit. + */ + @Nullable + public static RayTraceResult standardEntityRayTrace(World world, Entity entity, double range, boolean hitLiquids){ + // This method does not apply an offset like ray spells do, since it is not desirable in most other use cases. + Vec3d origin = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); + Vec3d endpoint = origin.add(entity.getLookVec().scale(range)); + return rayTrace(world, origin, endpoint, 0, hitLiquids, false, false, Entity.class, ignoreEntityFilter(entity)); + } + + /** + * Helper method for use with {@link RayTracer#rayTrace(World, Vec3d, Vec3d, float, boolean, boolean, boolean, Class, Predicate)} + * which returns a {@link Predicate} that returns true for the given entity, plus any entities that have zero health + * or less (i.e. are in the process of dying). This is a commonly used filter in spells. + * + * @param entity The entity that the returned predicate should return true for. + * @return A {@link Predicate} that returns true for the given entity and any entities that are in the process of + * dying, false for all other entities. + */ + public static Predicate ignoreEntityFilter(Entity entity){ + return e -> e == entity || (e instanceof EntityLivingBase && ((EntityLivingBase)e).getHealth() <= 0); + } + + /** + * Performs a ray trace for blocks and entities, starting at the given origin and finishing at the given endpoint. + * As of wizardry 4.2, the ray tracing methods have been rewritten to be more user-friendly and implement proper + * aim assist. + *

    + * N.B. It is possible to ignore entities entirely by passing in a {@code Predicate} that is always false; + * however, in this specific case it is more efficient to use + * {@link World#rayTraceBlocks(Vec3d, Vec3d, boolean, boolean, boolean)} or one of its overloads. + * + * @param world The world in which to perform the ray trace. + * @param origin A vector representing the coordinates of the start point of the ray trace. + * @param endpoint A vector representing the coordinates of the finish point of the ray trace. + * @param aimAssist In addition to direct hits, the ray trace will also hit entities that are up to this distance + * from its path. For a normal ray trace, this should be 0. Values greater than 0 will give an 'aim assist' effect. + * @param hitLiquids Whether liquids should be ignored when ray tracing blocks + * @param ignoreUncollidables Whether blocks with no collisions should be ignored + * @param returnLastUncollidable If blocks with no collisions are ignored, whether to return the last one (useful if, + * for example, you want to replace snow layers or tall grass) + * @param entityType The class of entities to include; all other entities will be ignored. + * @param filter A {@link Predicate} which filters out entities that can be ignored; often used to exclude the + * player that is performing the ray trace. + * + * @return A {@link RayTraceResult} representing the object that was hit, which may be an entity, a block or + * nothing. Returns {@code null} only if the origin and endpoint are within the same block and no entity was hit. + * + * @see RayTracer#standardEntityRayTrace(World, Entity, double, boolean) + * @see RayTracer#standardBlockRayTrace(World, EntityLivingBase, double, boolean) + */ + // Interestingly enough, aimAssist can be negative, which means hits have to be in the middle of entities! + @Nullable + public static RayTraceResult rayTrace(World world, Vec3d origin, Vec3d endpoint, float aimAssist, + boolean hitLiquids, boolean ignoreUncollidables, boolean returnLastUncollidable, Class entityType, Predicate filter){ + + // 1 is the standard amount of extra search volume, and aim assist needs to increase this further as well as + // expanding the entities' bounding boxes. + float borderSize = 1 + aimAssist; + + // The AxisAlignedBB constructor accepts min/max coords in either order. + AxisAlignedBB searchVolume = new AxisAlignedBB(origin.x, origin.y, origin.z, endpoint.x, endpoint.y, endpoint.z) + .grow(borderSize, borderSize, borderSize); + + // Gets all of the entities in the bounding box that could be collided with. + List entities = world.getEntitiesWithinAABB(entityType, searchVolume); + // Applies the given filter to remove entities that should be ignored. + entities.removeIf(filter); + + // Finds the first block hit by the ray trace, if any. + RayTraceResult result = world.rayTraceBlocks(origin, endpoint, hitLiquids, ignoreUncollidables, returnLastUncollidable); + + // Clips the entity search range to the part of the ray trace before the block hit, if it hit a block. + if(result != null){ + endpoint = result.hitVec; + } + + // Search variables + Entity closestHitEntity = null; + Vec3d closestHitPosition = endpoint; + AxisAlignedBB entityBounds; + Vec3d intercept = null; + + // Iterates through all the entities + for(Entity entity : entities){ + + // I'd like to add the following line so we can, for example, use greater telekinesis through a + // ring of fire, but doing so will stop forcefields blocking particles + //if(!entity.canBeCollidedWith()) continue; + + float fuzziness = WizardryUtilities.isLiving(entity) ? aimAssist : 0; // Only living entities have aim assist + + if(entity instanceof ICustomHitbox){ // Custom hitboxes + intercept = ((ICustomHitbox)entity).calculateIntercept(origin, endpoint, fuzziness); + + }else{ // Normal hit detection + + entityBounds = entity.getEntityBoundingBox(); + + if(entityBounds != null){ + + // This is zero for everything except fireballs... + float entityBorderSize = entity.getCollisionBorderSize(); + // ... meaning the following line does nothing in all other cases. + // -> Added the non-zero check to prevent unnecessary AABB object creation. + if(entityBorderSize != 0) + entityBounds = entityBounds.grow(entityBorderSize, entityBorderSize, entityBorderSize); + + // Aim assist expands the bounding box to hit entities within the specified distance of the ray trace. + if(fuzziness != 0) entityBounds = entityBounds.grow(fuzziness, fuzziness, fuzziness); + + // Finds the first point at which the ray trace intercepts the entity's bounding box, if any. + RayTraceResult hit = entityBounds.calculateIntercept(origin, endpoint); + if(hit != null) intercept = hit.hitVec; + } + } + + // If the ray trace hit the entity... + if(intercept != null){ + // Decides whether the entity that was hit is the closest so far, and if so, overwrites the old one. + float currentHitDistance = (float)intercept.distanceTo(origin); + float closestHitDistance = (float)closestHitPosition.distanceTo(origin); + if(currentHitDistance < closestHitDistance){ + closestHitEntity = entity; + closestHitPosition = intercept; + } + } + } + + // If the ray trace hit an entity, return that entity; otherwise return the result of the block ray trace. + if(closestHitEntity != null){ + result = new RayTraceResult(closestHitEntity, closestHitPosition); + } + + return result; + } +} diff --git a/src/main/java/electroblob/wizardry/util/RelativeFacing.java b/src/main/java/electroblob/wizardry/util/RelativeFacing.java new file mode 100644 index 00000000..f5988df9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/RelativeFacing.java @@ -0,0 +1,42 @@ +package electroblob.wizardry.util; + +import net.minecraft.entity.Entity; +import net.minecraft.util.EnumFacing; + +/** + * Like {@link EnumFacing}, but relative! + */ +public enum RelativeFacing { + + DOWN("down", -1), + UP("up", -1), + FRONT("front", 0), + BACK("back", 2), + LEFT("left", 3), + RIGHT("right", 1); + + public final String name; + private final int horizontalIndex; + + private static final RelativeFacing[] HORIZONTALS = new RelativeFacing[4]; + + RelativeFacing(String name, int horizontalIndex){ + this.name = name; + this.horizontalIndex = horizontalIndex; + } + + static { + for(RelativeFacing facing : values()){ + if(facing.horizontalIndex > -1) HORIZONTALS[facing.horizontalIndex] = facing; + } + } + + public static RelativeFacing relativise(EnumFacing absolute, Entity relativeTo){ + if(absolute == EnumFacing.DOWN) return DOWN; + if(absolute == EnumFacing.UP) return UP; + EnumFacing look = relativeTo.getAdjustedHorizontalFacing(); + int relativeIndex = absolute.getHorizontalIndex() - look.getHorizontalIndex(); + if(relativeIndex < 0) relativeIndex += 4; + return HORIZONTALS[relativeIndex]; + } +} diff --git a/src/main/java/electroblob/wizardry/util/SpellModifiers.java b/src/main/java/electroblob/wizardry/util/SpellModifiers.java index a8ee1e91..93ea7e96 100644 --- a/src/main/java/electroblob/wizardry/util/SpellModifiers.java +++ b/src/main/java/electroblob/wizardry/util/SpellModifiers.java @@ -1,31 +1,28 @@ package electroblob.wizardry.util; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - import electroblob.wizardry.event.SpellCastEvent; import io.netty.buffer.ByteBuf; import net.minecraft.item.Item; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fml.common.network.ByteBufUtils; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + /** * "{@code SpellModifiers} - modify all the things!" - *

    + *

    * Object that wraps any number of spell modifiers into one, allowing for expandability within the Spell#cast methods. - * This class is essentially a glorified {@link Map} which can be written to and read from a {@link ByteBuf}. It is - * possible to calculate spell modifiers from wand NBT within the cast methods, but this is cumbersome and does not - * allow the modifiers to be sent to the client, which is sometimes necessary (for example, detonate needs to know about - * range modifiers on the client side or the particles wouldn't show outside of the base range). - *

    + * This class is essentially a glorified {@link Map} which can be written to and read from a {@link ByteBuf}. + *

    * Most external interaction with SpellModifiers objects will be in {@link SpellCastEvent.Pre}, where you can add * additional modifiers to them if desired for use with your own spells, or modify the existing ones. If you have added * a wand upgrade, this is not done automatically for you; you will have to do it yourself (for the simple reason * that not all wand upgrades affect spells). SpellModifiers objects are mutable, so you can simply change the * values they contain to modify the spell. - *

    + *

    * To use a SpellModifiers object within the Spell.cast methods, simply retrieve the desired modifier * using {@link SpellModifiers#get(Item)} for wand upgrades, or {@link SpellModifiers#get(String)} if the modifier is * not from a wand upgrade. @@ -40,21 +37,40 @@ import net.minecraftforge.fml.common.network.ByteBufUtils; // fly. public final class SpellModifiers { - /** Constant string identifier for the potency modifier. All the other modifiers in Wizardry have items. */ + /** Constant string identifier for the potency modifier. */ public static final String POTENCY = "potency"; + /** Constant string identifier for the mana cost modifier. */ + public static final String COST = "cost"; + /** Constant string identifier for the wand progression modifier. */ + public static final String PROGRESSION = "progression"; - private Map multiplierMap; - private Map syncedMultiplierMap; + private final Map multiplierMap; + private final Map syncedMultiplierMap; /** * Creates an empty SpellModifiers object. All calls to get(...) on an empty SpellModifiers object will * return a value of 1. */ public SpellModifiers(){ - multiplierMap = new HashMap(); - syncedMultiplierMap = new HashMap(); + multiplierMap = new HashMap<>(); + syncedMultiplierMap = new HashMap<>(); } +// /** Returns a deep copy of this {@code SpellModifiers} object. */ +// @Override +// public SpellModifiers clone(){ +// SpellModifiers clone; +// try { +// clone = (SpellModifiers)super.clone(); +// }catch(CloneNotSupportedException e){ +// Wizardry.logger.error("Whaaaaat?!", e); +// return null; +// } +// clone.multiplierMap = new HashMap<>(this.multiplierMap); +// clone.syncedMultiplierMap = new HashMap<>(this.syncedMultiplierMap); +// return clone; +// } + /** * Adds the given multiplier to this SpellModifiers object, using the string identifier that the given wand upgrade * item was registered with. @@ -109,6 +125,31 @@ public final class SpellModifiers { return value == null ? 1 : value; } + // Not sure this really makes sense with the current system, it may just be better to keep it how it is +// /** +// * Returns the level of upgrade (i.e. number of upgrades or wand tier) that would be required to +// * generate a modifier with the given key. This does not necessarily mean that was how this modifier was +// * applied; and the returned value may not be a whole number if commands were involved. +// */ +// public float level(String key){ +// return 0; +// } + + /** + * Returns an amplified version of the multiplier corresponding to the given string key. An amplified + * modifier is the original modifier scaled about 1 - for example, amplifying by 2 would produce the + * following results:
    + * 1.3 -> 1.6
    + * 2 -> 3
    + * 0.7 -> 0.4
    + * 1 -> 1
    + * (In other words, the modifier is decreased by 1, multiplied by the scalar and then increased by 1 again.)
    + * N.B. This does not change the stored modifier. + */ + public float amplified(String key, float scalar){ + return (get(key) - 1) * scalar + 1; + } + /** * Returns an unmodifiable map of the modifiers stored in this SpellModifiers object. Useful for iterating through * the modifiers. @@ -146,10 +187,10 @@ public final class SpellModifiers { /** * Creates a new SpellModifiers object from the given NBTTagCompound. The NBTTagCompound should have 1 or more float * tags, which will be stored as modifiers under the same name as the tag. For example, the following NBT tag (in - * command syntax) will create a SpellModifiers object with a damage modifier of 1.5 and a range modifier of 2: - *

    + * command syntax) represents a SpellModifiers object with a damage modifier of 1.5 and a range modifier of 2: + *

    * {damage:1.5, range:2} - *

    + *

    * Note that needsSyncing is set to true for all returned modifiers. */ public static SpellModifiers fromNBT(NBTTagCompound nbt){ @@ -159,5 +200,22 @@ public final class SpellModifiers { } return modifiers; } + + /** + * Creates a new NBTTagCompound for this SpellModifiers object. The NBTTagCompound will have a float tags for each + * modifier, which will be stored using the modifier names as keys. For example, the following NBT tag (in + * command syntax) represents a SpellModifiers object with a damage modifier of 1.5 and a range modifier of 2: + *

    + * {damage:1.5, range:2} + *

    + * Note that information about syncing of modifiers is discarded. + */ + public NBTTagCompound toNBT(){ + NBTTagCompound nbt = new NBTTagCompound(); + for(Entry entry : multiplierMap.entrySet()){ + nbt.setFloat(entry.getKey(), entry.getValue()); + } + return nbt; + } } diff --git a/src/main/java/electroblob/wizardry/util/SpellProperties.java b/src/main/java/electroblob/wizardry/util/SpellProperties.java new file mode 100644 index 00000000..55e7d00b --- /dev/null +++ b/src/main/java/electroblob/wizardry/util/SpellProperties.java @@ -0,0 +1,361 @@ +package electroblob.wizardry.util; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSyntaxException; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.constants.SpellType; +import electroblob.wizardry.constants.Tier; +import electroblob.wizardry.registry.Spells; +import electroblob.wizardry.spell.Spell; +import io.netty.buffer.ByteBuf; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.CraftingHelper; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Object that stores base properties associated with spells. Each spell has a single instance of this class which + * stores its base properties and other data. This class also handles loading of the properties from JSON. + *

    + * All the fields in this class are final and are assigned during object creation. This is because the intent is that a + * new SpellProperties object is created on load and synced with each client on player login. Having final fields + * therefore guarantees that the properties are always synced whenever necessary, but cannot otherwise be fiddled + * with programmatically. + *

    + * Generally, users need not worry about this class; it is intended that the various property getters in Spell be used + * rather than querying this class directly (in fact, you can't do that without reflection anyway). + *

    + * @author Electroblob + * @since Wizardry 4.2 + */ +// There is not a particular semantic reason to separate this from the Spell class itself. However, doing so means that +// everything related to the JSON spell system is kept in one place and doesn't clutter the (already long) Spell class. +// Additionally, it allows SpellProperties objects to be passed around during loading and syncing. +public final class SpellProperties { + + private static final Gson gson = new Gson(); + + /** Set of enum constants representing contexts in which a spell can be enabled/disabled. */ + public enum Context { + + /** Disabling this context will make a spell's book unobtainable and unusable. */ BOOK("book"), + /** Disabling this context will make a spell's scroll unobtainable and unusable. */ SCROLL("scroll"), + /** Disabling this context will prevent a spell from being cast using a wand. */ WANDS("wands"), + /** Disabling this context will prevent NPCs from casting or dropping a spell. */ NPCS("npcs"), + /** Disabling this context will prevent dispensers from casting a spell. */ DISPENSERS("dispensers"), + /** Disabling this context will prevent a spell from being cast using commands. */ COMMANDS("commands"), + /** Disabling this context will prevent a spell's book or scroll generating in chests. */ TREASURE("treasure"), + /** Disabling this context will prevent a spell's book or scroll from being sold by NPCs.*/ TRADES("trades"), + /** Disabling this context will prevent a spell's book or scroll being dropped by mobs. */ LOOTING("looting"); + + /** The JSON identifier for this context. */ + public final String name; + + Context(String name){ + this.name = name; + } + } + + /** A map storing whether each context is enabled for this spell. */ + private final Map enabledContexts; + /** A map storing the base values for this spell. These values are defined by the spell class and cannot be + * changed. */ + // We're using Number here because it makes implementors think about what they convert it to. + // If we did what attributes do and just use doubles, people (myself included!) might plug them into calculations + // without thinking. However, with Number you can't just do that, you have to convert and therefore you have to + // decide how to do the conversion. Internally they're handled as floats though. + private final Map baseValues; + + /** The tier this spell belongs to. */ + public final Tier tier; + /** The element this spell belongs to. */ + public final Element element; + /** The type of spell this is classified as. */ + public final SpellType type; + /** Mana cost of the spell. If it is a continuous spell the cost is per second. */ + public final int cost; + /** The charge-up time of the spell, in ticks. */ + public final int chargeup; + /** The cooldown time of the spell, in ticks. */ + public final int cooldown; + + // Sometimes it just makes more sense to do the JSON parsing in the constructor + // It's the only way we're gonna keep the fields final! + /** + * Parses the given JSON object and constructs a new {@code SpellProperties} from it, setting all the relevant + * fields and references. + * + * @param json A JSON object representing the spell properties to be constructed. + * @param spell The spell that this {@code SpellProperties} object is for. + * @throws JsonSyntaxException if at any point the JSON object is found to be invalid. + */ + private SpellProperties(JsonObject json, Spell spell){ + + String[] baseValueNames = spell.getPropertyKeys(); + + enabledContexts = new EnumMap<>(Context.class); + baseValues = new HashMap<>(); + + JsonObject enabled = JsonUtils.getJsonObject(json, "enabled"); + + // This time we know the exact set of properties so we can iterate over them instead of the json object + // In fact, we actually want to throw an exception if any of them are missing + for(Context context : Context.values()){ + enabledContexts.put(context, JsonUtils.getBoolean(enabled, context.name)); + } + + try { + tier = Tier.fromName(JsonUtils.getString(json, "tier")); + element = Element.fromName(JsonUtils.getString(json, "element")); + type = SpellType.fromName(JsonUtils.getString(json, "type")); + }catch(IllegalArgumentException e){ + throw new JsonSyntaxException("Incorrect spell property value", e); + } + + cost = JsonUtils.getInt(json, "cost"); + chargeup = JsonUtils.getInt(json, "chargeup"); + cooldown = JsonUtils.getInt(json, "cooldown"); + + // There's not much point specifying the classes of the numbers here because the json getter methods just + // perform conversion to the requested type anyway. It therefore makes very little difference whether the + // conversion is done during JSON parsing or when we actually use the value - and at least in the latter case, + // individual subclasses have control over how it is converted. + + // My case in point: summoning 2.5 spiders is obviously nonsense, but what happens when we cast that with a + // modifier of 2? Should we round the base value down to 2 and then apply the x2 modifier to get 4 spiders? + // Should we round it up instead? Or should we apply the modifier first and then do the rounding, so with no + // modifier we still get 2 spiders but with the x2 modifier we get 5? + // The most pragmatic solution is to let the spell class decide for itself. + // (Of course, we can only hope that the users aren't jerks and don't try to summon 2 and a half spiders...) + + JsonObject baseValueObject = JsonUtils.getJsonObject(json, "base_properties"); + + // If the code requests more values than the JSON file contains, that will cause a JsonSyntaxException here anyway. + // If there are redundant values in the JSON file, chances are that a user has misunderstood the system and tried + // to add properties that aren't implemented. However, redundant values will also be found if a programmer has + // forgotten to call addProperties in their spell constructor (I know I have!), potentially causing a crash at + // some random point in the future. Since redundant values aren't a problem by themselves, we shouldn't throw an + // exception, but a warning is appropriate. + + int redundantKeys = baseValueObject.size() - baseValueNames.length; + if(redundantKeys > 0) Wizardry.logger.warn("Spell " + spell.getRegistryName() + " has " + redundantKeys + + " redundant spell property key(s) defined in its JSON file. Extra values will have no effect! (Modders:" + + " make sure you have called addProperties(...) during spell construction)"); + + if(baseValueNames.length > 0){ + + for(String baseValueName : baseValueNames){ + baseValues.put(baseValueName, JsonUtils.getFloat(baseValueObject, baseValueName)); + } + } + + } + + /** Constructs a new SpellProperties object for the given spell, reading its values from the given ByteBuf. */ + public SpellProperties(Spell spell, ByteBuf buf){ + + enabledContexts = new EnumMap<>(Context.class); + baseValues = new HashMap<>(); + + for(Context context : Context.values()){ + // Enum maps have a guaranteed iteration order so this works fine + enabledContexts.put(context, buf.readBoolean()); + } + + tier = Tier.values()[buf.readShort()]; + element = Element.values()[buf.readShort()]; + type = SpellType.values()[buf.readShort()]; + + cost = buf.readInt(); + chargeup = buf.readInt(); + cooldown = buf.readInt(); + + List keys = Arrays.asList(spell.getPropertyKeys()); + Collections.sort(keys); // Should be the same list of keys in the same order they were written to the ByteBuf + + for(String key : keys){ + baseValues.put(key, buf.readFloat()); + } + } + + /** Writes this SpellProperties object to the given ByteBuf so it can be sent via packets. */ + public void write(ByteBuf buf){ + + for(Context context : Context.values()){ + // Enum maps have a guaranteed iteration order so this works fine + buf.writeBoolean(enabledContexts.get(context)); + } + + buf.writeShort(tier.ordinal()); + buf.writeShort(element.ordinal()); + buf.writeShort(type.ordinal()); + + buf.writeInt(cost); + buf.writeInt(chargeup); + buf.writeInt(cooldown); + + List keys = new ArrayList<>(baseValues.keySet()); + Collections.sort(keys); // Sort alphabetically (as long as the order is consistent it doesn't matter) + + for(String key : keys){ + buf.writeFloat(baseValues.get(key).floatValue()); + } + } + + /** + * Returns whether the spell is enabled in any of the given contexts. + * @param contexts The context in which to check if the spell is enabled. + * @return True if the spell is enabled in any of the given contexts, false if not. + */ + public boolean isEnabled(Context... contexts){ + return enabledContexts.entrySet().stream().anyMatch(e -> e.getValue() && Arrays.asList(contexts).contains(e.getKey())); + } + + /** + * Returns the base value for this spell that corresponds to the given identifier. + * @param identifier The string identifier to fetch the base value for. + * @return The base value, as a {@code Number}. + * @throws IllegalArgumentException if no base value was defined with the given identifier. + */ + public Number getBaseValue(String identifier){ + if(!baseValues.containsKey(identifier)){ + throw new IllegalArgumentException("Base value with identifier '" + identifier + "' is not defined."); + } + return baseValues.get(identifier); + } + + /** + * Called from preInit() in the main mod class to initialise the spell property system. + */ + // For some reason I had this called from a method in CommonProxy which was overridden to do nothing in + // ClientProxy, but that method was never called and instead this one was called directly from the main mod class. + // I *think* I decided against the proxy thing and just forgot to delete the methods (they're gone now), but if + // things don't work as expected then that may be why - pretty sure it's fine though since the properties get + // wiped client-side on each login anyway. + public static void init(){ + // Collecting to a set should give us one of each mod ID + Set modIDs = Spell.getSpells(Spell.allSpells).stream().map(s -> s.getRegistryName().getNamespace()).collect(Collectors.toSet()); + + boolean flag = true; + + for(String modID : modIDs){ + flag &= loadSpellProperties(modID); // Don't short-circuit, or mods later on won't get loaded! + } + + if(!flag) Wizardry.logger.warn("Some spell property files did not load correctly; this will likely cause problems later!"); + } + + // Sooooooo I just realised that resource packs - you know, that famously client-side thing - can now define + // stuff that should be specified by the server. No wonder it all got moved to data packs in 1.13... + // Anyway, for the time being we're in 1.12 so we're gonna have to do this instead. + + // For crafting recipes, Forge does some stuff behind the scenes to load recipe JSON files from mods' namespaces. + // This leverages the same methods. + + private static boolean loadSpellProperties(String modID){ + + // Yes, I know you're not supposed to do orElse(null). But... meh. + ModContainer mod = Loader.instance().getModList().stream().filter(m -> m.getModId().equals(modID)).findFirst().orElse(null); + + if(mod == null){ + Wizardry.logger.warn("Tried to load spell properties for mod with ID '" + modID + "', but no such mod was loaded"); + return false; // Failed! + } + + // Spells will be removed from this list as their properties are set + // If everything works properly, it should be empty by the end + List spells = Spell.getSpells(s -> s.getRegistryName().getNamespace().equals(modID)); + if(modID.equals(Wizardry.MODID)) spells.add(Spells.none); // In this particular case we do need the none spell + + Wizardry.logger.info("Loading spell properties for " + spells.size() + " spells in mod " + modID); + + // This method is used by Forge to load mod recipes and advancements, so it's a fair bet it's the right one + // In the absence of Javadoc, here's what the non-obvious parameters do: + // - preprocessor is called once with just the root directory, allowing any global index files to be processed + // - processor is called once for each file in the directory so processing can be done + // - defaultUnfoundRoot is the default value to return if the root specified isn't found + // - visitAllFiles determines whether the method short-circuits; in other words, if the processor returns false + // at any point and visitAllFiles is false, the method returns immediately. + boolean success = CraftingHelper.findFiles(mod, "assets/" + modID + "/spells", null, + + (root, file) -> { + + String relative = root.relativize(file).toString(); + if(!"json".equals(FilenameUtils.getExtension(file.toString())) || relative.startsWith("_")) + return true; // True or it'll look like it failed just because it found a non-JSON file + + String name = FilenameUtils.removeExtension(relative).replaceAll("\\\\", "/"); + ResourceLocation key = new ResourceLocation(modID, name); + + Spell spell = Spell.registry.getValue(key); + + // If no spell matches a particular file, log it and just ignore the file + if(spell == null){ + Wizardry.logger.info("Spell properties file " + name + ".json does not match any registered spells; ensure the filename is spelled correctly."); + return true; + } + + BufferedReader reader = null; + + // We want to do this regardless of whether the JSON file got read properly, because that prints its + // own separate warning + if(!spells.remove(spell)) Wizardry.logger.warn("What's going on?!"); + + try{ + + reader = Files.newBufferedReader(file); + + JsonObject json = JsonUtils.fromJson(gson, reader, JsonObject.class); + SpellProperties properties = new SpellProperties(json, spell); + spell.setProperties(properties); + + }catch(JsonParseException jsonparseexception){ + Wizardry.logger.error("Parsing error loading spell property file for " + key, jsonparseexception); + return false; + }catch(IOException ioexception){ + Wizardry.logger.error("Couldn't read spell property file for " + key, ioexception); + return false; + }finally{ + IOUtils.closeQuietly(reader); + } + + return true; + + }, + true, true); + + // If a spell is missing its file, log an error + if(!spells.isEmpty()){ + if(spells.size() <= 15){ + spells.forEach(s -> Wizardry.logger.error("Spell " + s.getRegistryName() + " is missing a properties file!")); + }else{ + // If there are more than 15 don't bother logging them all, chances are they're all missing + Wizardry.logger.error("Mod " + modID + " has " + spells.size() + " spells that are missing properties files!"); + } + } + + return success; + } +} + +// We probably could have used the attribute system for all of this, but I am reluctant to do so for a number of +// reasons: +// - It's a mess. +// - Unlike entities and itemstacks, spells don't have a separate instance for each time they are cast, which might +// prove problematic. +// - I'm loading my base properties once and not touching them again, so they're more like block materials than anything +// else. +// - Some of the properties aren't numerical, and some of them can't have modifiers applied. In fact, most of them can't! +// So even if we were to use attributes, we'd still need this class. \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/util/WandHelper.java b/src/main/java/electroblob/wizardry/util/WandHelper.java index 332f8cc3..449a807c 100644 --- a/src/main/java/electroblob/wizardry/util/WandHelper.java +++ b/src/main/java/electroblob/wizardry/util/WandHelper.java @@ -1,9 +1,5 @@ package electroblob.wizardry.util; -import java.util.Collections; -import java.util.HashMap; -import java.util.Set; - import electroblob.wizardry.item.ItemWand; import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.WizardryItems; @@ -12,25 +8,29 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import java.util.Collections; +import java.util.HashMap; +import java.util.Set; + /** * "Never fear, {@code WandHelper} is here!" - *

    + *

    * Much like {@link net.minecraft.enchantment.EnchantmentHelper EnchantmentHelper}, this class has some static methods * which allow cleaner and more concise interaction with the wand NBT data, which is quite a complex structure. Such * interaction previously resulted in rather verbose and repetitive code which was hard to read and even harder to * debug! For example, this class allowed {@link electroblob.wizardry.item.ItemWand ItemWand} to be shortened by about * 80 lines. In addition, by having all the various null checks and array size checks in one place, the chance of * accidental errors due to forgetting to check these things is greatly reduced. - *

    + *

    * Note that these methods contain no game logic at all; they are purely for interacting with the NBT data. Conversely, * you should never need to access the wand's NBT data directly when using this class, but the keys are public in the * unlikely case that this is necessary. - *

    + *

    * Also note that none of the methods in this class actually check that the given ItemStack contains an ItemWand; you * can, for example, pass in a stack of snowballs without causing problems, but that is of course pointless! However, if * you have your own spell casting item (which doesn't extend ItemWand), this setup means you can still use this class * to manage its NBT structure. - *

    + *

    * All get methods in this class return some kind of default if the passed-in wand stack has no nbt data. See * individual method descriptions for more details.
    * All set methods in this class create a new nbt data for the passed-in wand if it has none, before doing @@ -46,11 +46,13 @@ public final class WandHelper { public static final String SPELL_ARRAY_KEY = "spells"; public static final String SELECTED_SPELL_KEY = "selectedSpell"; public static final String COOLDOWN_ARRAY_KEY = "cooldown"; + public static final String MAX_COOLDOWN_ARRAY_KEY = "maxCooldown"; public static final String UPGRADES_KEY = "upgrades"; + public static final String PROGRESSION_KEY = "progression"; private static final HashMap upgradeMap = new HashMap(); - static{ + static { upgradeMap.put(WizardryItems.condenser_upgrade, "condenser"); upgradeMap.put(WizardryItems.storage_upgrade, "storage"); upgradeMap.put(WizardryItems.siphon_upgrade, "siphon"); @@ -59,8 +61,11 @@ public final class WandHelper { upgradeMap.put(WizardryItems.cooldown_upgrade, "cooldown"); upgradeMap.put(WizardryItems.blast_upgrade, "blast"); upgradeMap.put(WizardryItems.attunement_upgrade, "attunement"); + upgradeMap.put(WizardryItems.melee_upgrade, "melee"); } + // =================================================== Spells =================================================== + /** * Returns an array containing the spells currently bound to the given wand. As of Wizardry 1.1, this array is not * always the same size; it can be anywhere between 5 and 8 (inclusive) in length. If the wand has no spell data, @@ -77,7 +82,7 @@ public final class WandHelper { spells = new Spell[spellIDs.length]; for(int i = 0; i < spellIDs.length; i++){ - spells[i] = Spell.get(spellIDs[i]); + spells[i] = Spell.byMetadata(spellIDs[i]); } } @@ -95,7 +100,7 @@ public final class WandHelper { int[] spellIDs = new int[spells.length]; for(int i = 0; i < spells.length; i++){ - spellIDs[i] = spells[i] != null ? spells[i].id() : Spells.none.id(); + spellIDs[i] = spells[i] != null ? spells[i].metadata() : Spells.none.metadata(); } wand.getTagCompound().setIntArray(SPELL_ARRAY_KEY, spellIDs); @@ -123,9 +128,10 @@ public final class WandHelper { public static Spell getNextSpell(ItemStack wand){ Spell[] spells = getSpells(wand); + int index = getNextSpellIndex(wand); - if(wand.getTagCompound() != null){ - return spells[getNextSpellIndex(wand)]; + if(index >= 0 && index < spells.length){ + return spells[index]; } return Spells.none; @@ -136,9 +142,10 @@ public final class WandHelper { public static Spell getPreviousSpell(ItemStack wand){ Spell[] spells = getSpells(wand); + int index = getPreviousSpellIndex(wand); - if(wand.getTagCompound() != null){ - return spells[getPreviousSpellIndex(wand)]; + if(index >= 0 && index < spells.length){ + return spells[index]; } return Spells.none; @@ -165,6 +172,8 @@ public final class WandHelper { } private static int getNextSpellIndex(ItemStack wand){ + + if(wand.getTagCompound() == null) wand.setTagCompound(new NBTTagCompound()); int numberOfSpells = getSpells(wand).length; int spellIndex = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY); @@ -181,6 +190,8 @@ public final class WandHelper { } private static int getPreviousSpellIndex(ItemStack wand){ + + if(wand.getTagCompound() == null) wand.setTagCompound(new NBTTagCompound()); int numberOfSpells = getSpells(wand).length; int spellIndex = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY); @@ -194,6 +205,8 @@ public final class WandHelper { return spellIndex; } + // ================================================== Cooldowns ================================================== + /** * Returns an array of the cooldowns for each spell bound to the given wand. As of Wizardry 1.1, this array is not * always the same size; it can be anywhere between 5 and 8 (inclusive) in length. If the wand has no cooldown data, @@ -211,7 +224,8 @@ public final class WandHelper { return cooldowns; } - /** Sets the given wand's cooldown array. The array can be anywhere between 5 and 8 (inclusive) in length. */ + /** Sets the given wand's cooldown array. The array can be anywhere between 5 and 8 (inclusive) in length. + * Unlike {@link WandHelper#setCurrentCooldown(ItemStack, int)}, this will not set the max cooldowns. */ public static void setCooldowns(ItemStack wand, int[] cooldowns){ if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound())); @@ -266,7 +280,7 @@ public final class WandHelper { return cooldowns[getPreviousSpellIndex(wand)]; } - /** Sets the given wand's cooldown for the currently selected spell. */ + /** Sets the given wand's cooldown for the currently selected spell. Will also set the maximum cooldown. */ public static void setCurrentCooldown(ItemStack wand, int cooldown){ if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound())); @@ -280,8 +294,52 @@ public final class WandHelper { cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)] = cooldown; setCooldowns(wand, cooldowns); + + int[] maxCooldowns = getMaxCooldowns(wand); + + if(maxCooldowns.length == 0) maxCooldowns = new int[getSpells(wand).length]; + + maxCooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)] = cooldown; + + setMaxCooldowns(wand, maxCooldowns); } + /** + * Returns an array of the max cooldowns for each spell bound to the given wand. If the wand has no cooldown data, + * returns an array of length 0. + */ + public static int[] getMaxCooldowns(ItemStack wand){ + + int[] cooldowns = new int[0]; + + if(wand.getTagCompound() != null){ + + return wand.getTagCompound().getIntArray(MAX_COOLDOWN_ARRAY_KEY); + } + + return cooldowns; + } + + /** Sets the given wand's cooldown array. The array can be anywhere between 5 and 8 (inclusive) in length. */ + public static void setMaxCooldowns(ItemStack wand, int[] cooldowns){ + + if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound())); + + wand.getTagCompound().setIntArray(MAX_COOLDOWN_ARRAY_KEY, cooldowns); + } + + /** Returns the given wand's max cooldown for the currently selected spell, or 0 if the wand has no cooldown data. */ + public static int getCurrentMaxCooldown(ItemStack wand){ + + int[] cooldowns = getMaxCooldowns(wand); + + if(cooldowns.length == 0) return 0; + // Don't need to check if the tag compound is null since the above check is equivalent. + return cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)]; + } + + // ================================================== Upgrades ================================================== + /** * Returns the number of upgrades of the given type that have been applied to the given wand, or 0 if the wand has * no upgrade data or the given item is not a valid wand upgrade. @@ -371,4 +429,28 @@ public final class WandHelper { throw new IllegalArgumentException("Duplicate wand upgrade identifier: " + identifier); upgradeMap.put(upgrade, identifier); } + + // ================================================= Progression ================================================= + + /** Sets the given wand's progression to the given value. */ + public static void setProgression(ItemStack wand, int progression){ + + if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound())); + + wand.getTagCompound().setInteger(PROGRESSION_KEY, progression); + } + + /** Returns the progression value for the given wand, or 0 if the wand has no data. */ + public static int getProgression(ItemStack wand){ + + if(wand.getTagCompound() == null) return 0; + + return wand.getTagCompound().getInteger(PROGRESSION_KEY); + } + + /** Adds the given amount of progression to this wand's progression value. */ + public static void addProgression(ItemStack wand, int progression){ + setProgression(wand, getProgression(wand) + progression); + } + } diff --git a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java index 592a3bc3..8cbdcb58 100644 --- a/src/main/java/electroblob/wizardry/util/WizardryUtilities.java +++ b/src/main/java/electroblob/wizardry/util/WizardryUtilities.java @@ -1,70 +1,49 @@ package electroblob.wizardry.util; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; -import java.util.UUID; -import java.util.function.Function; -import java.util.function.Predicate; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.tuple.ImmutablePair; - import electroblob.wizardry.CommonProxy; -import electroblob.wizardry.WizardData; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.constants.Element; -import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.living.ISummonedCreature; -import electroblob.wizardry.registry.WizardryItems; -import electroblob.wizardry.registry.WizardryPotions; -import electroblob.wizardry.spell.MindControl; +import electroblob.wizardry.data.WizardData; +import electroblob.wizardry.entity.living.ISpellCaster; +import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.spell.Spell; +import net.minecraft.block.Block; +import net.minecraft.block.BlockLog; +import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.effect.EntityLightningBolt; import net.minecraft.entity.item.EntityArmorStand; import net.minecraft.entity.monster.EntityCreeper; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.entity.projectile.EntityThrowable; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.inventory.EntityEquipmentSlot.Type; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTBase; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; import net.minecraft.network.datasync.DataParameter; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.DamageSource; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.NonNullList; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.*; +import net.minecraft.util.EnumFacing.Axis; +import net.minecraft.util.math.*; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.ReflectionHelper; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.BiPredicate; +import java.util.function.Predicate; /** * "Where do you put random but useful bits and pieces? {@code WizardryUtilities} of course - the 'stuff that doesn't * fit anywhere else' class!" - *

    + *

    * This class contains some useful static methods for use anywhere - items, entities, spells, events, blocks, etc. * Broadly speaking, these fall into the following categories: - *

    + *

    * - In-world utilities (position calculating, retrieving entities, etc.)
    * - Raytracing
    * - NBT and data storage utilities
    @@ -83,6 +62,8 @@ public final class WizardryUtilities { public static final EntityEquipmentSlot[] ARMOUR_SLOTS; /** Changed to a constant in wizardry 2.1, since this is a lot more efficient. */ private static final DataParameter POWERED; +// /** Pointing item action used in various spells. */ +// public static final EnumAction POINT; static { // The list of slots needs to be mutable. @@ -92,10 +73,32 @@ public final class WizardryUtilities { ARMOUR_SLOTS = slots.toArray(new EntityEquipmentSlot[0]); // Null is passed in deliberately since POWERED is a static field. - POWERED = ReflectionHelper.getPrivateValue(EntityCreeper.class, null, "POWERED", "field_184714_b"); + POWERED = ObfuscationReflectionHelper.getPrivateValue(EntityCreeper.class, null, "field_184714_b"); + + //POINT = EnumHelper.addAction("POINT"); + } + + /** A global offset used for placing/rendering flat things so that they appear to sit flush with the face of blocks + * but do not cause z-fighting at a distance where it is noticeable. */ + // This value is a compromise between flushness and minimum view distance for z-fighting to occur. 0.005 seems to + // be immune to z-fighting until over a hundred blocks away, which is pretty good, and the distance from flat + // surfaces is still indistinguishable. + public static final double ANTI_Z_FIGHTING_OFFSET = 0.005; + + // I'm fed up with remembering these... + /** Stores constant values for attribute modifier operations (and javadoc for what they actually do!) */ + public static final class Operations { + /** Adds the attribute modifier amount to the base value. */ + public static final int ADD = 0; + /** Multiplies the base value by 1 plus the attribute modifier amount. Multiple modifiers are processed in + * parallel, i.e. the calculation is based on the base value and does not depend on previous modifiers. */ + public static final int MULTIPLY_FLAT = 1; + /** Multiplies the base value by 1 plus the attribute modifier amount. Multiple modifiers are processed in + * series, i.e. the calculation is based on the value after previous modifiers are applied, in the order added. */ + public static final int MULTIPLY_CUMULATIVE = 2; } - // SECTION Block/Entity/World Utilities + // World, Blocks and Coordinates // =============================================================================================================== /** @@ -117,64 +120,208 @@ public final class WizardryUtilities { return i; } - + /** - * Returns whether the block at the given coordinates can be replaced by another one (works as if a block is being - * placed by a player). True for air, liquids, vines, tall grass and snow layers but not for flowers, signs etc. + * Returns whether the block at the given position can be replaced by another one (works as if a block is being + * placed by a player). True for air, vines, tall grass and snow layers but not for flowers, signs etc. * This is a shortcut for world.getBlockState(pos).getMaterial().isReplaceable(). - * - * @see WizardryUtilities#canBlockBeReplacedB(World, BlockPos) + * + * @param world The world the block is in. + * @param pos The position of the block. + * @param excludeLiquids True to treat liquids as non-replaceable, false to treat liquids as replaceable. + * + * @see WizardryUtilities#canBlockBeReplaced(World, BlockPos) */ - public static boolean canBlockBeReplaced(World world, BlockPos pos){ - return world.isAirBlock(new BlockPos(pos)) || world.getBlockState(pos).getMaterial().isReplaceable(); + public static boolean canBlockBeReplaced(World world, BlockPos pos, boolean excludeLiquids){ + return (world.isAirBlock(new BlockPos(pos)) || world.getBlockState(pos).getMaterial().isReplaceable()) + && (!excludeLiquids || !world.getBlockState(pos).getMaterial().isLiquid()); } /** - * Returns whether the block at the given coordinates can be replaced by another one (works as if a block is being - * placed by a player) and is not a liquid. True for air, vines, tall grass and snow layers but not for flowers, - * signs etc. or any liquids. - * - * @see WizardryUtilities#canBlockBeReplaced(World, BlockPos) + * Returns whether the block at the given position can be replaced by another one (works as if a block is being + * placed by a player). True for air, liquids, vines, tall grass and snow layers but not for flowers, signs etc. + * This is a shorthand version of {@link WizardryUtilities#canBlockBeReplaced(World, BlockPos, boolean)}; + * excludeLiquids defaults to false. + * + * @param world The world the block is in. + * @param pos The position of the block. */ - public static boolean canBlockBeReplacedB(World world, BlockPos pos){ - return canBlockBeReplaced(world, pos) && !world.getBlockState(pos).getMaterial().isLiquid(); + public static boolean canBlockBeReplaced(World world, BlockPos pos){ + return canBlockBeReplaced(world, pos, false); } /** * Returns whether the block at the given coordinates is unbreakable in survival mode. In vanilla this is true for - * bedrock and end portal frame, for example. This is a shortcut for:

    + * bedrock and end portal frame, for example. This is a shortcut for:

    * {@code world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f} */ public static boolean isBlockUnbreakable(World world, BlockPos pos){ return !world.isAirBlock(new BlockPos(pos)) && world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f; } + /** + * Returns a block state for the given block, with all properties set to the values from the given source state. + * The source block state must have exactly the same properties as the destination block will allow or an + * {@link IllegalArgumentException} will be thrown. + *

    + * This method allows, for example, an oak door block to be replaced with a spruce one whilst keeping the same + * orientation, door half, open/closed state, etc. + * @param block The new block type + * @param source The block state to copy property values from + * @return The resulting block state + */ + @SuppressWarnings("unchecked") // Don't complain to me about Mojang's code design... + public static IBlockState copyState(Block block, IBlockState source){ + + IBlockState state = block.getDefaultState(); + + for(IProperty property : source.getPropertyKeys()){ + // It ain't pretty but it works + state = state.withProperty(property, (Comparable)source.getProperties().get(property)); + } + + return state; + } + + /** + * Finds the nearest surface (according to the given criteria) in the given direction from the given position, + * within the range specified. This is a generalised replacement for the old {@code getNearestFloorLevel} methods; + * overloads and predefined surface criteria that replicate the old behaviours are available. + * + * @param world The world to search in + * @param pos The position to search from + * @param direction The direction to search in; also defines the direction the surface must face. + * @param range The maximum distance from the given y coordinate to search. + * @param doubleSided True to also search in the opposite direction, false to only search in the given direction. + * @param criteria A {@link SurfaceCriteria} representing the criteria defining a surface. See that class for + * available predefined criteria. + * @return The x, y, or z coordinate of the closest surface, or null if no surface was found. This represents the + * exact position of the block boundary that forms the surface (and therefore it may correspond to the coordinate + * of the inside or outside block of the surface depending on the direction). + */ + @Nullable + public static Integer getNearestSurface(World world, BlockPos pos, EnumFacing direction, int range, + boolean doubleSided, SurfaceCriteria criteria){ + + // This is a neat trick that allows a default 'not found' return value for integers where all possible integer + // values could, in theory, be returned. The alternative is to use a double and have NaN as the default, but + // that would introduce extra casting, and since NaN can be calculated with, it could produce strange results + // when unaccounted for. Using an Integer means it'll immediately throw an NPE instead. + Integer surface = null; + int currentBest = Integer.MAX_VALUE; + + for(int i = doubleSided ? -range : 0; i <= range && i < currentBest; i++){ // Now short-circuits for efficiency + + BlockPos testPos = pos.offset(direction, i); + + if(criteria.test(world, testPos, direction)){ + // Because the loop now short-circuits, this must be closer than the previous surface found + surface = (int)component(getFaceCentre(testPos, direction), direction.getAxis()); + currentBest = Math.abs(i); + } + } + + return surface; + } + + /** + * A {@code SurfaceCriteria} object is used to define a 'surface', a boundary between two blocks which differ in + * some way, for use in {@link WizardryUtilities#getNearestSurface(World, BlockPos, EnumFacing, int, boolean, SurfaceCriteria)}. + * This provides a more flexible replacement for the (now deprecated) {@code getNearestFloorLevel} methods.
    + *
    + * In the context of this class, 'outside' refers to the side of the surface that is in the supplied direction, + * and 'inside' refers to the side which is in the opposite direction. For example, if the direction is {@code UP}, + * the inside of the surface is defined as below it, and the outside is defined as above it. + */ + @FunctionalInterface + public interface SurfaceCriteria { + + /** + * Tests whether the inputs define a valid surface according to this set of criteria. + * @param world The world in which the surface is to be tested. + * @param pos The block coordinates of the inside ('solid' part) of the surface. + * @param side The direction in which the surface must face. + * @return True if the side {@code side} of the block at {@code pos} in {@code world} is a valid surface + * according to this set of criteria, false otherwise. + */ + boolean test(World world, BlockPos pos, EnumFacing side); + + /** Returns a {@code SurfaceCriteria} with the opposite arrangement to this one. */ + default SurfaceCriteria flip(){ + return (world, pos, side) -> this.test(world, pos.offset(side), side.getOpposite()); + } + + /** Returns a {@code SurfaceCriteria} based on the given condition, where the inside of the surface satisfies + * the condition and the outside does not. */ + static SurfaceCriteria basedOn(BiPredicate condition){ + return (world, pos, side) -> condition.test(world, pos) && !condition.test(world, pos.offset(side)); + } + + /** Returns a {@code SurfaceCriteria} based on the given condition, where the inside of the surface satisfies + * the condition and the outside does not. */ + static SurfaceCriteria basedOn(Predicate condition){ + return (world, pos, side) -> condition.test(world.getBlockState(pos)) && !condition.test(world.getBlockState(pos.offset(side))); + } + + /** Surface criterion which defines a surface as the boundary between a block that cannot be moved through and + * a block that can be moved through. This means the surface can be stood on. */ + SurfaceCriteria COLLIDABLE = basedOn(b -> b.getMaterial().blocksMovement()); + + /** Surface criterion which defines a surface as the boundary between a block that is solid on the required side and + * a block that is replaceable. This means the surface can be built on. */ + SurfaceCriteria BUILDABLE = (world, pos, side) -> world.isSideSolid(pos, side) && world.getBlockState(pos.offset(side)).getBlock().isReplaceable(world, pos); + + /** Surface criterion which defines a surface as the boundary between a block that is solid on the required side + * or a liquid, and an air block. Used for freezing water and placing snow. */ + // Was getNearestFloorLevelB + SurfaceCriteria SOLID_LIQUID_TO_AIR = (world, pos, side) -> (world.getBlockState(pos).getMaterial().isLiquid() + || world.isSideSolid(pos, side) && world.isAirBlock(pos.offset(side))); + + /** Surface criterion which defines a surface as the boundary between any non-air block and an air block. + * Used for particles. */ + // Was getNearestFloorLevelC + SurfaceCriteria NOT_AIR_TO_AIR = basedOn(World::isAirBlock).flip(); + + /** Surface criterion which defines a surface as the boundary between a block that cannot be moved through, and + * a block that can be moved through or a tree block (log or leaves). Used for structure generation. */ + SurfaceCriteria COLLIDABLE_IGNORING_TREES = basedOn((world, pos) -> + world.getBlockState(pos).getMaterial().blocksMovement() + && !(world.getBlockState(pos).getBlock() instanceof BlockLog) + && !(world.getBlockState(pos).getBlock().isLeaves(world.getBlockState(pos), world, pos) + && !(world.getBlockState(pos).getBlock().isFoliage(world, pos)))); + + } + + /** + * Finds the nearest floor level in the given direction from the given position, + * within the range specified. This is a shorthand for + * {@link WizardryUtilities#getNearestSurface(World, BlockPos, EnumFacing, int, boolean, SurfaceCriteria)}; + * {@code doubleSided} defaults to true, {@code direction} defaults to {@code EnumFacing.UP}, and + * {@code criteria} defaults to {@link SurfaceCriteria#COLLIDABLE}. + */ + @Nullable + public static Integer getNearestFloor(World world, BlockPos pos, int range){ + return getNearestSurface(world, pos, EnumFacing.UP, range, true, SurfaceCriteria.COLLIDABLE); + } + /** * Finds the nearest floor level to the given y coord within the range specified at the given x and z coords. - * Liquids and other blocks that cannot be built on top of do not count, but stuff like signs does. (Technically any - * block is allowed to be the floor according to the code, but seeing as it searches upwards and non-solid blocks - * usually need a supporting block, the floor is likely to always be solid). + * As of Wizardry 4.2, this is now a wrapper for {@link WizardryUtilities#getNearestFloor(World, BlockPos, int)} + * which retains the old functionality (i.e. returning an {@code int}, with -1 as 'not found') for compatibility. * * @param world The world to search in * @param pos The coordinates to search from * @param range The maximum distance from the given y coordinate to search. * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the * floor as would be seen in the debug screen when the player is standing on it. - * @see WizardryUtilities#getNearestFloorLevelB(World, BlockPos, int) + * @deprecated Use {@link WizardryUtilities#getNearestFloor(World, BlockPos, int)}; this method may be removed in + * future. */ + // Since this is always a y-coordinate, the 'not found' value can just be any negative number. + @Deprecated public static int getNearestFloorLevel(World world, BlockPos pos, int range){ - - int yCoord = -2; - for(int i = -range; i <= range; i++){ - // The last bit determines whether the block found to be a suitable floor is closer than the previous one - // found. - if(world.isSideSolid(pos.up(i), EnumFacing.UP) - && (world.isAirBlock(pos.up(i + 1)) || !world.isSideSolid(pos.up(i + 1), EnumFacing.UP)) - && (i < yCoord - pos.getY() || yCoord == -2)){ - yCoord = pos.getY() + i; - } - } - return yCoord + 1; + Integer floor = getNearestFloor(world, pos, range); + return floor == null ? -1 : floor; } /** @@ -186,21 +333,13 @@ public final class WizardryUtilities { * @param range The maximum distance from the given y coordinate to search. * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the * floor as would be seen in the debug screen when the player is standing on it. - * @see WizardryUtilities#getNearestFloorLevel(World, BlockPos, int) + * @deprecated Use {@link WizardryUtilities#getNearestSurface(World, BlockPos, EnumFacing, int, boolean, SurfaceCriteria)}; + * this method may be removed in future. */ + @Deprecated public static int getNearestFloorLevelB(World world, BlockPos pos, int range){ - int yCoord = -2; - for(int i = -range; i <= range; i++){ - if(world.isAirBlock(new BlockPos(pos.up(i + 1))) - && (world.getBlockState(pos.up(i)).getMaterial().isLiquid() - || world.isSideSolid(pos.up(i), EnumFacing.UP)) - && (i < yCoord - pos.getY() || yCoord == -2)){ - // The last bit determines whether the block found to be a suitable floor is closer than the previous - // one found. - yCoord = pos.getY() + i; - } - } - return yCoord + 1; + Integer floor = getNearestSurface(world, pos, EnumFacing.UP, range, true, SurfaceCriteria.SOLID_LIQUID_TO_AIR); + return floor == null ? -1 : floor; } /** @@ -212,18 +351,13 @@ public final class WizardryUtilities { * @param range The maximum distance from the given y coordinate to search. * @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the * floor as would be seen in the debug screen when the player is standing on it. - * @see WizardryUtilities#getNearestFloorLevel(World, BlockPos, int) + * @deprecated Use {@link WizardryUtilities#getNearestSurface(World, BlockPos, EnumFacing, int, boolean, SurfaceCriteria)}; + * this method may be removed in future. */ + @Deprecated public static int getNearestFloorLevelC(World world, BlockPos pos, int range){ - int yCoord = -2; - for(int i = -range; i <= range; i++){ - if(world.isAirBlock(new BlockPos(pos.up(i + 1))) && (i < yCoord - pos.getY() || yCoord == -2)){ - // The last bit determines whether the block found to be a suitable floor is closer than the previous - // one found. - yCoord = pos.getY() + i; - } - } - return yCoord + 1; + Integer floor = getNearestSurface(world, pos, EnumFacing.UP, range, true, SurfaceCriteria.NOT_AIR_TO_AIR); + return floor == null ? -1 : floor; } /** @@ -274,8 +408,8 @@ public final class WizardryUtilities { for(int x = -horizontalRange; x <= horizontalRange; x++){ for(int z = -horizontalRange; z <= horizontalRange; z++){ - int y = WizardryUtilities.getNearestFloorLevel(world, origin.add(x, 0, z), verticalRange); - if(y > -1) possibleLocations.add(new BlockPos(origin.getX() + x, y, origin.getZ() + z)); + Integer y = WizardryUtilities.getNearestFloor(world, origin.add(x, 0, z), verticalRange); + if(y != null) possibleLocations.add(new BlockPos(origin.getX() + x, y, origin.getZ() + z)); } } @@ -297,10 +431,43 @@ public final class WizardryUtilities { return entity.world.getBlockState(pos); } + /** + * Generates a sphere of block positions centred on the given position, with the given radius. This is an efficient + * implementation - rather than simply generating a cube and cutting the rest out, it works as follows: + *

    + * 1. Step through all x offsets within the specified radius
    + * 2. For each x offset, check the maximum y offset within the radius using Pythagoras
    + * 3. Step through the resulting valid y offsets
    + * 4. For each y offset, check the maximum z offset within the radius using Pythagoras
    + * 5. Step through the resulting valid z offsets + * @return A list of BlockPos objects in a sphere. This list will be ordered negative to positive, with axes + * nested in order (i.e. blocks in a line on the z axis will be consecutive in the list). + */ + public static List getBlockSphere(BlockPos centre, double radius){ + + // Extra efficiency by assigning enough capacity for a cube of side length r + List sphere = new ArrayList<>((int)Math.pow(radius, 3)); + + for(int i=-(int)radius; i<=radius; i++){ + + float r1 = MathHelper.sqrt(radius*radius - i*i); + + for(int j=-(int)r1; j<=r1; j++){ + + float r2 = MathHelper.sqrt(radius*radius - i*i - j*j); + + for(int k=-(int)r2; k<=r2; k++){ + sphere.add(centre.add(i, j, k)); + } + } + } + + return sphere; + } + /** * Shorthand for {@link WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World, Class)} - * with EntityLivingBase as the entity type. This is by far the most common use for that method, which is why this - * shorthand exists. + * with EntityLivingBase as the entity type. This is by far the most common use for that method. * * @param radius The search radius * @param x The x coordinate to search around @@ -334,21 +501,121 @@ public final class WizardryUtilities { for(int i = 0; i < entityList.size(); i++){ if(entityList.get(i).getDistance(x, y, z) > radius){ entityList.remove(i); + break; } } return entityList; } + // Why is there a distanceSqToCentre method in Vec3i but not a getCentre method? + /** - * Gets an entity from its UUID. Note that you should check this isn't null. If the UUID is known to belong to an - * EntityPlayer, use the more efficient {@link World#getPlayerEntityByUUID(UUID)} instead. + * Returns a {@link Vec3d} of the coordinates at the centre of the given block position (i.e. the block coordinates + * plus 0.5 in x, y, and z). + */ + public static Vec3d getCentre(BlockPos pos){ + return new Vec3d(pos).add(0.5, 0.5, 0.5); + } + + /** + * Returns a {@link Vec3d} of the coordinates at the centre of the given bounding box (The one in {@code AxisAlignedBB} + * itself is client-side only). + */ + public static Vec3d getCentre(AxisAlignedBB box){ + return new Vec3d(box.minX + (box.maxX - box.minX) * 0.5, box.minY + (box.maxY - box.minY) * 0.5, box.minZ + (box.maxZ - box.minZ) * 0.5); + } + + /** + * Returns a {@link Vec3d} of the coordinates at the centre of the given face of the given block position (i.e. the + * centre of the block plus 0.5 in the given direction). + */ + public static Vec3d getFaceCentre(BlockPos pos, EnumFacing face){ + return getCentre(pos).add(new Vec3d(face.getDirectionVec()).scale(0.5)); + } + + /** + * Returns the component of the given {@link Vec3d} corresponding to the given {@link Axis Axis}. + */ + public static double component(Vec3d vec, Axis axis){ + return new double[]{vec.x, vec.y, vec.z}[axis.ordinal()]; // Damn, that's compact. + } + + /** + * Returns the component of the given {@link Vec3i} corresponding to the given {@link Axis Axis}. + */ + public static int component(Vec3i vec, Axis axis){ + return new int[]{vec.getX(), vec.getY(), vec.getZ()}[axis.ordinal()]; + } + + /** + * Returns a new {@link Vec3d} with the component corresponding to the given {@link Axis Axis} replaced by the + * given value. + */ + public static Vec3d replaceComponent(Vec3d vec, Axis axis, double newValue){ + double[] components = {vec.x, vec.y, vec.z}; + components[axis.ordinal()] = newValue; + return new Vec3d(components[0], components[1], components[2]); + } + + /** + * Returns a new {@link Vec3i} with the component corresponding to the given {@link Axis Axis} replaced by the + * given value. + */ + public static Vec3i replaceComponent(Vec3i vec, Axis axis, int newValue){ + int[] components = {vec.getX(), vec.getY(), vec.getZ()}; + components[axis.ordinal()] = newValue; + return new Vec3i(components[0], components[1], components[2]); + } + + /** + * Returns an array of {@code Vec3d} objects representing the vertices of the given bounding box. + * @param box The bounding box whose vertices are to be returned. + * @return The list of vertices, which will contain 8 elements. Using EnumFacing initials, the order is: + * DNW, DNE, DSE, DSW, UNW, UNE, USE, USW. The returned coordinates are absolute (i.e. measured from the world origin). + */ + public static Vec3d[] getVertices(AxisAlignedBB box){ + return new Vec3d[]{ + new Vec3d(box.minX, box.minY, box.minZ), + new Vec3d(box.maxX, box.minY, box.minZ), + new Vec3d(box.maxX, box.minY, box.maxZ), + new Vec3d(box.minX, box.minY, box.maxZ), + new Vec3d(box.minX, box.maxY, box.minZ), + new Vec3d(box.maxX, box.maxY, box.minZ), + new Vec3d(box.maxX, box.maxY, box.maxZ), + new Vec3d(box.minX, box.maxY, box.maxZ) + }; + } + + /** + * Returns an array of {@code Vec3d} objects representing the vertices of the block at the given position. + * @param pos The position of the block whose vertices are to be returned. + * @return The list of vertices, which will contain 8 elements. Using EnumFacing initials, the order is: + * DNW, DNE, DSE, DSW, UNW, UNE, USE, USW. The returned coordinates are absolute (i.e. measured from the world origin). + */ + public static Vec3d[] getVertices(World world, BlockPos pos){ + return getVertices(world.getBlockState(pos).getBoundingBox(world, pos).offset(pos.getX(), pos.getY(), pos.getZ())); + } + + /** + * Returns the pitch angle in degrees of the given {@link EnumFacing}. For some reason {@code EnumFacing} has a get + * yaw method ({@link EnumFacing#getHorizontalAngle()}) but not a get pitch method. + */ + public static float getPitch(EnumFacing facing){ + return facing == EnumFacing.UP ? 90 : facing == EnumFacing.DOWN ? -90 : 0; + } + + /** + * Gets an entity from its UUID. If the UUID is known to belong to an {@code EntityPlayer}, use the more efficient + * {@link World#getPlayerEntityByUUID(UUID)} instead. * * @param world The world the entity is in * @param id The entity's UUID * @return The Entity that has the given UUID, or null if no such entity exists in the specified world. */ @Nullable - public static Entity getEntityByUUID(World world, UUID id){ + public static Entity getEntityByUUID(World world, @Nullable UUID id){ + + if(id == null) return null; // It would return null eventually but there's no point even looking for(Entity entity : world.loadedEntityList){ // This is a perfect example of where you need to use .equals() and not ==. For most applications, @@ -382,6 +649,9 @@ public final class WizardryUtilities { player.world.playSound(null, player.posX, player.posY, player.posZ, sound, SoundCategory.PLAYERS, volume, pitch); } + // Players and Mobs + // =============================================================================================================== + /** * Returns the entity riding the given entity, or null if there is none. Allows for neater code now that entities * have a list of passengers, because it is necessary to check that the list is not empty first. @@ -430,8 +700,25 @@ public final class WizardryUtilities { * 0.01D){ dx = (Math.random() - Math.random()) * 0.01D; } - // The first argument is never used. - target.knockBack(null, 0.4f, dx, dz); + target.knockBack(attacker, 0.4f, dx, dz); + } + + /** + * Undoes 1 tick's worth of velocity change due to gravity for the given entity. If the entity has no gravity, + * this method does nothing. This method is intended to be used in situations where entity gravity needs to be + * turned on and off and it is not practical to use {@link Entity#setNoGravity(boolean)}, usually if there is no + * easy way to get a reference to the entity to turn gravity back on. + * + * @param entity The entity to undo gravity for. + */ + public static void undoGravity(Entity entity){ + if(!entity.hasNoGravity()){ + double gravity = 0.04; + if(entity instanceof EntityThrowable) gravity = 0.03; + else if(entity instanceof EntityArrow) gravity = 0.05; + else if(entity instanceof EntityLivingBase) gravity = 0.08; + entity.motionY += gravity; + } } /** @@ -503,6 +790,13 @@ public final class WizardryUtilities { return server.getPlayerList().getOppedPlayers().getEntry(player.getGameProfile()) != null; } + /** Checks that the given entity is allowed to damage blocks in the given world. If the entity is a player, this + * checks the player block damage config setting, otherwise it posts a mob griefing event and returns the result. */ + public static boolean canDamageBlocks(EntityLivingBase entity, World world){ + if(entity instanceof EntityPlayer) return Wizardry.settings.playerBlockDamage; + return ForgeEventFactory.getMobGriefingEvent(world, entity); + } + /** Returns the default aiming arror used by skeletons for the given difficulty. For reference, these are: Easy - 10, * Normal - 6, Hard - 2, Peaceful - 10 (rarely used). */ public static int getDefaultAimingError(EnumDifficulty difficulty){ @@ -536,159 +830,79 @@ public final class WizardryUtilities { public static void chargeCreeper(EntityCreeper creeper){ creeper.getDataManager().set(POWERED, true); } - - // SECTION Raytracing - // =============================================================================================================== - + /** - * Helper method which performs a ray trace for blocks only from an entity's eye position in the direction - * they are looking, over a specified range, using {@link World#rayTraceBlocks(Vec3d, Vec3d, boolean)}. - * - * @param world The world in which to perform the ray trace. - * @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye - * position and proceed in the direction the entity is looking. - * @param range The distance over which the ray trace will be performed. - * @param hitLiquids True to return hits on the surfaces of liquids, false to ignore liquid blocks as if they were - * not there. - * @return A {@link RayTraceResult} representing the object that was hit, which may be either a block or nothing. - * Returns {@code null} only if the origin and endpoint are within the same block. + * Returns true if the given caster is currently casting the given spell by any means. This method is intended to + * eliminate the long and cumbersome wand use checking in event handlers, which often missed out spells cast by + * means other than wands. + * @param caster The potential spell caster, which may be a player or an {@link ISpellCaster}. Any other entity will + * cause this method to always return false. + * @param spell The spell to check for. The spell must be continuous or this method will always return false. + * @return True if the caster is currently casting the given spell through any means, false otherwise. */ - @Nullable - public static RayTraceResult standardBlockRayTrace(World world, EntityLivingBase entity, double range, boolean hitLiquids){ - // This method does not apply an offset like ray spells do, since it is not desirable in most other use cases. - Vec3d origin = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); - Vec3d endpoint = origin.add(entity.getLookVec().scale(range)); - return world.rayTraceBlocks(origin, endpoint, hitLiquids); - } - - /** - * Helper method which performs a ray trace for blocks and entities from an entity's eye position in the direction - * they are looking, over a specified range, using {@link WizardryUtilities#rayTrace(World, Vec3d, Vec3d, float, - * boolean, Class, Predicate)}. Aim assist is zero, the entity type is simply {@code Entity} (all entities), and the - * filter removes the given entity and any dying entities and allows all others. - * - * @param world The world in which to perform the ray trace. - * @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye - * position and proceed in the direction the entity is looking. This entity will be ignored when ray tracing. - * @param range The distance over which the ray trace will be performed. - * @param hitLiquids True to return hits on the surfaces of liquids, false to ignore liquid blocks as if they were - * not there. - * @return A {@link RayTraceResult} representing the object that was hit, which may be an entity, a block or - * nothing. Returns {@code null} only if the origin and endpoint are within the same block and no entity was hit. - */ - @Nullable - public static RayTraceResult standardEntityRayTrace(World world, Entity entity, double range, boolean hitLiquids){ - // This method does not apply an offset like ray spells do, since it is not desirable in most other use cases. - Vec3d origin = new Vec3d(entity.posX, entity.getEntityBoundingBox().minY + entity.getEyeHeight(), entity.posZ); - Vec3d endpoint = origin.add(entity.getLookVec().scale(range)); - return WizardryUtilities.rayTrace(world, origin, endpoint, 0, hitLiquids, Entity.class, e -> e == entity); - } - - /** - * Performs a ray trace for blocks and entities, starting at the given origin and finishing at the given endpoint. - * As of wizardry 4.2, the ray tracing methods have been rewritten to be more user-friendly and implement proper - * aim assist. - *

    - * N.B. It is possible to ignore entities entirely by passing in a {@code Predicate} that is always false; - * however, in this specific case it is more efficient to use - * {@link World#rayTraceBlocks(Vec3d, Vec3d, boolean, boolean, boolean)} or one of its overloads. - * - * @param The type of entities to include; all other entities will be ignored. - * @param world The world in which to perform the ray trace. - * @param origin A vector representing the coordinates of the start point of the ray trace. - * @param endpoint A vector representing the coordinates of the finish point of the ray trace. - * @param aimAssist In addition to direct hits, the ray trace will also hit entities that are up to this distance - * from its path. For a normal ray trace, this should be 0. Values greater than 0 will give an 'aim assist' effect. - * @param hitLiquids Whether liquids should be ignored when ray tracing blocks - * @param entityType The class of entities to include; all other entities will be ignored. - * @param filter A {@link Predicate} which filters out entities that can be ignored; often used to exclude the - * player that is performing the ray trace. - * - * @return A {@link RayTraceResult} representing the object that was hit, which may be an entity, a block or - * nothing. Returns {@code null} only if the origin and endpoint are within the same block and no entity was hit. - * - * @see WizardryUtilities#standardEntityRayTrace(World, Entity, double, boolean) - * @see WizardryUtilities#standardBlockRayTrace(World, EntityLivingBase, double, boolean) - */ - // Interestingly enough, aimAssist can be negative, which means hits have to be in the middle of entities! - @Nullable - public static RayTraceResult rayTrace(World world, Vec3d origin, Vec3d endpoint, float aimAssist, - boolean hitLiquids, Class entityType, Predicate filter){ + // The reason this is a boolean check is that actually returning a spell presents a problem: players can cast two + // continuous spells at once, one via commands and one via an item, so which do you choose? Since the main point was + // to check for specific spells, it seems more useful to do it this way. + public static boolean isCasting(EntityLivingBase caster, Spell spell){ - // 1 is the standard amount of extra search volume, and aim assist needs to increase this further as well as - // expanding the entities' bounding boxes. - float borderSize = 1 + aimAssist; - - // The AxisAlignedBB constructor accepts min/max coords in either order. - AxisAlignedBB searchVolume = new AxisAlignedBB(origin.x, origin.y, origin.z, endpoint.x, endpoint.y, endpoint.z) - .grow(borderSize, borderSize, borderSize); + if(!spell.isContinuous) return false; - // Gets all of the entities in the bounding box that could be collided with. - List entities = world.getEntitiesWithinAABB(entityType, searchVolume); - // Applies the given filter to remove entities that should be ignored. - entities.removeIf(filter); - - // Finds the first block hit by the ray trace, if any. - RayTraceResult result = world.rayTraceBlocks(origin, endpoint, hitLiquids); - - // Clips the entity search range to the part of the ray trace before the block hit, if it hit a block. - if(result != null){ - endpoint = result.hitVec; - } - - // Search variables - Entity closestHitEntity = null; - Vec3d closestHitPosition = endpoint; - AxisAlignedBB entityBounds; - RayTraceResult intercept; - - // Iterates through all the entities - for(Entity entity : entities){ + if(caster instanceof EntityPlayer){ - entityBounds = entity.getEntityBoundingBox(); + WizardData data = WizardData.get((EntityPlayer)caster); - if(entityBounds != null){ + if(data != null && data.currentlyCasting() == spell) return true; - // This is zero for everything except fireballs... - float entityBorderSize = entity.getCollisionBorderSize(); - // ... meaning the following line does nothing in all other cases. - // -> Added the non-zero check to prevent unnecessary AABB object creation. - if(entityBorderSize != 0) entityBounds = entityBounds.grow(entityBorderSize, entityBorderSize, entityBorderSize); - - // Aim assist expands the bounding box to hit entities within the specified distance of the ray trace. - if(aimAssist != 0) entityBounds = entityBounds.grow(aimAssist, aimAssist, aimAssist); - - // Finds the first point at which the ray trace intercepts the entity's bounding box, if any. - intercept = entityBounds.calculateIntercept(origin, endpoint); - - // If the ray trace hit the entity... - if(intercept != null){ - // Decides whether the entity that was hit is the closest so far, and if so, overwrites the old one. - float currentHitDistance = (float)intercept.hitVec.distanceTo(origin); - float closestHitDistance = (float)closestHitPosition.distanceTo(origin); - if(currentHitDistance < closestHitDistance){ - closestHitEntity = entity; - closestHitPosition = intercept.hitVec; - } + if(caster.isHandActive()){ + + ItemStack stack = caster.getHeldItem(caster.getActiveHand()); + + if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack) == spell + && ((ISpellCastingItem)stack.getItem()).canCast(stack, spell, (EntityPlayer)caster, + EnumHand.MAIN_HAND, 0, new SpellModifiers())){ + return true; } } + + }else if(caster instanceof ISpellCaster){ + if(((ISpellCaster)caster).getContinuousSpell() == spell) return true; } - // If the ray trace hit an entity, return that entity; otherwise return the result of the block ray trace. - if(closestHitEntity != null){ - result = new RayTraceResult(closestHitEntity, closestHitPosition); - } - - return result; + return false; } - // SECTION NBT and Data Storage + /** + * Returns whether the given {@link DamageSource} is melee damage. This method makes a best guess as to whether + * the damage was from a melee attack; there is no way of testing this properly. + * @param source The damage source to be tested. + * @return True if the given damage source is melee damage, false otherwise. + */ + public static boolean isMeleeDamage(DamageSource source){ + + // With the exception of minions, melee damage always has the same entity for immediate/true source + if(!(source instanceof MinionDamage) && source.getImmediateSource() != source.getTrueSource()) return false; + if(source.isProjectile()) return false; // Projectile damage obviously isn't melee damage + if(source.isUnblockable()) return false; // Melee damage should always be blockable + if(!(source instanceof MinionDamage) && source instanceof IElementalDamage) return false; + if(!(source.getTrueSource() instanceof EntityLivingBase)) return false; // Only living things can melee! + + if(source.getTrueSource() instanceof EntityPlayer && source.getDamageLocation() != null + && source.getDamageLocation().distanceTo(source.getTrueSource().getPositionVector()) > ((EntityLivingBase)source + .getTrueSource()).getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue()){ + return false; // Out of melee reach for players + } + + // If it got through all that, chances are it's melee damage + return true; + } + + // Miscellaneous // =============================================================================================================== /** * Verifies that the given string is a valid string representation of a UUID. More specifically, returns true if and * only if the given string is not null and matches the regular expression: - *

    + *

    *
    /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/

    * which is the regex equivalent of the standard string representation of a UUID as described in * {@link UUID#toString()}. This method is intended to be used as a check to prevent an @@ -705,355 +919,24 @@ public final class WizardryUtilities { } /** - * Generic method that stores any Map to an NBTTagList, given two functions that convert the key and value types in - * that map to subclasses of NBTBase. For what it's worth, there is very little point in using this unless you can - * use something more concise than an anonymous class to do the conversion. A lambda expression, or better, a method - * reference, would fit nicely. For example, take ExtendedPlayer's use of this to store conjured item durations: - *

    - * properties.setTag("conjuredItems", WizardryUtilities.mapToNBT(this.conjuredItemDurations, - * item -> new NBTTagInt(Item.getIdFromItem((Item)item)), NBTTagInt::new)); - *

    - * This is a lot nicer than simply iterating through the map, because for that you need to use the entry list, which - * introduces local variables that aren't really necessary. Notice that, since the values V in the map are simply - * Integer objects, a simple constructor reference to NBTTagInt::new can be used instead of a lambda expression (the - * Integer is auto-unboxed to int). - * - * @param The type of key stored in the given Map. - * @param The type of value stored in the given Map. - * @param The subtype of NBTBase that the keys (of type K) will be converted to. - * @param The subtype of NBTBase that the values (of type V) will be converted to. - * @param map The Map to be stored. - * @param keyFunction A Function that converts the keys in the map to NBT objects that can be stored. - * @param valueFunction A Function that converts the values in the map to NBT objects that can be stored. - * @param keyTagName The tag name to use for the key tags. - * @param valueTagName The tag name to use for the value tags. - * @return An NBTTagList that represents the given Map. + * Flattens the given nested collection. The returned collection is an unmodifiable collection of all the elements + * contained within all of the sub-collections of the given nested collection. + * @param collection A nested collection to flatten + * @param The type of elements in the given nested collection + * @return The resulting flattened collection. */ - public static NBTTagList mapToNBT(Map map, - Function keyFunction, Function valueFunction, String keyTagName, String valueTagName){ - - NBTTagList tagList = new NBTTagList(); - - for(Entry entry : map.entrySet()){ - NBTTagCompound mapping = new NBTTagCompound(); - mapping.setTag(keyTagName, keyFunction.apply(entry.getKey())); - mapping.setTag(valueTagName, valueFunction.apply(entry.getValue())); - tagList.appendTag(mapping); - } - - return tagList; + public static Collection flatten(Collection> collection){ + Collection result = new ArrayList<>(); + collection.forEach(result::addAll); + return Collections.unmodifiableCollection(result); } - /** - * See {@link WizardryUtilities#mapToNBT(Map, Function, Function, String, String)}; this version is for when the - * names of the individual key/value tags are unimportant (they default to "key" and "value" respectively). - */ - public static NBTTagList mapToNBT(Map map, - Function keyFunction, Function valueFunction){ - return mapToNBT(map, keyFunction, valueFunction, "key", "value"); - } - - /** - * Generic method that reads a Map from an NBTTagList, given two functions that convert the key and value tag types - * into the key and value types in the returned map. The given NBTTagList remains unchanged after calling this - * method. - * - * @param The type of key stored in the returned Map. - * @param The type of value stored in the returned Map. - * @param The subtype of NBTBase that the keys are stored as. - * @param The subtype of NBTBase that the values are stored as. - * @param tagList The NBTTagList to be converted. This must be a list of compound tags. - * @param keyFunction A Function that converts the generic NBTBase tags in the list to keys of type K for the map. - * @param valueFunction A Function that converts the generic NBTBase tags in the list to values of type V for the - * map. - * @param keyTagName The tag name used for the key tags. - * @param valueTagName The tag name used for the value tags. - * @return A Map containing the keys and values stored in the given NBTTagList. Can be empty, but not null. - * @throws ClassCastException If the tags are not of the expected type. - * @see WizardryUtilities#mapToNBT(Map, Function, Function, String, String) - */ - @SuppressWarnings("unchecked") // Intentional, because throwing an exception is appropriate here. - public static Map NBTToMap(NBTTagList tagList, - Function keyFunction, Function valueFunction, String keyTagName, String valueTagName){ - - Map map = new HashMap(); - - for(int i = 0; i < tagList.tagCount(); i++){ - NBTTagCompound mapping = tagList.getCompoundTagAt(i); - NBTBase keyTag = mapping.getTag(keyTagName); - NBTBase valueTag = mapping.getTag(valueTagName); - K key = null; - try{ - key = keyFunction.apply((L)keyTag); - }catch (ClassCastException e){ - Wizardry.logger.error( - "Error when reading map from NBT: unexpected tag type " + NBTBase.NBT_TYPES[keyTag.getId()], e); - } - V value = null; - try{ - value = valueFunction.apply((W)valueTag); - }catch (ClassCastException e){ - Wizardry.logger.error( - "Error when reading map from NBT: unexpected tag type " + NBTBase.NBT_TYPES[valueTag.getId()], - e); - } - map.put(key, value); - } - - return map; - } - - /** - * See {@link WizardryUtilities#NBTToMap(NBTTagList, Function, Function, String, String)}; this version is for when - * the names of the individual key/value tags are unimportant (they default to "key" and "value" respectively). - */ - public static Map NBTToMap(NBTTagList tagList, - Function keyFunction, Function valueFunction){ - return NBTToMap(tagList, keyFunction, valueFunction, "key", "value"); - } - - /** - * Generic method that stores any Collection to an NBTTagList, given a function that converts the elements in that - * collection to subclasses of NBTBase. For what it's worth, there is very little point in using this unless you can - * use something more concise than an anonymous class to do the conversion. A lambda expression, or better, a method - * reference, would fit nicely. - * - * @param The type of element stored in the given Collection. - * @param The NBT tag type that the elements will be converted to. - * @param list The Collection to be stored. - * @param function A Function that converts the elements in the collection to NBT objects that can be stored. - * @return An NBTTagList that represents the given Collection. - */ - public static NBTTagList listToNBT(Collection list, Function function){ - - NBTTagList tagList = new NBTTagList(); - // If the collection is ordered, it will preserve the order, even though we don't know what type it is yet. - for(E element : list){ - tagList.appendTag(function.apply(element)); - } - - return tagList; - } - - /** - * Generic method that reads a Collection from an NBTTagList, given a function that converts the element tag types - * to the element types in the returned collection. The given NBTTagList remains unchanged after calling this - * method. Unless the target variable for this method is of type Collection, you will need to create a new - * collection containing the elements in the returned collection via that collection's constructor (e.g. {@code new - * HashSet(collection)}). Although this method returns a Collection rather than any of its subtypes, it uses - * an ArrayList internally to guarantee the order of the elements in the returned collection is the same as the - * order in which they were stored. As such, you may safely cast to List should you wish. - * - * @param The type of element stored in the returned Collection. - * @param The subtype of NBTBase that the elements are stored as. - * @param tagList The NBTTagList to be converted. - * @param function A Function that converts the generic NBTBase tags in the list to elements for the collection. - * Chances are you will need to cast the NBTBase tag to whichever NBT tag type you are expecting in order to - * access the appropriate getter method. - * @return A Collection containing the elements stored in the given NBTTagList. Can be empty, but not null. - * @throws ClassCastException If the tags are not of the expected type. - */ - @SuppressWarnings("unchecked") // Intentional, because throwing an exception is appropriate here. - public static Collection NBTToList(NBTTagList tagList, Function function){ - // Uses an ArrayList to guarantee iteration order, and also to permit duplicate elements (which are - // perfectly reasonable in this context). - Collection list = new ArrayList(); - // The original tag list should remain unchanged, hence the copy. - NBTTagList tagList2 = (NBTTagList)tagList.copy(); - - while(!tagList2.hasNoTags()){ - NBTBase tag = tagList2.removeTag(0); - // Why oh why is NBTTagList not parametrised? It even has a tagType field, so it must know! - try{ - list.add(function.apply((T)tag)); - }catch (ClassCastException e){ - Wizardry.logger.error( - "Error when reading list from NBT: unexpected tag type " + NBTBase.NBT_TYPES[tag.getId()], e); - } - } - - return list; - - } - - /** Removes the UUID with the given key from the given NBT tag, if any. Why this doesn't exist in vanilla I have - * no idea. */ - public static void removeUniqueId(NBTTagCompound tag, String key){ - tag.removeTag(key + "Most"); - tag.removeTag(key + "Least"); - } - - // TODO: Backport: It has recently become apparent that storing UUIDs as strings is not good practice, so backport - // these two - // methods to 1.7.10 and replace tag.setUniqueId and tag.getUniqueId with their respective contents from 1.10.2. - - /** - * Returns an NBTTagCompound which contains only the given UUID, stored using - * {@link NBTTagCompound#setUniqueId(String, UUID)}. Allows for neater storage to NBTTagLists. - */ - public static NBTTagCompound UUIDtoTagCompound(UUID id){ - NBTTagCompound tag = new NBTTagCompound(); - tag.setUniqueId("uuid", id); - return tag; - } - - /** - * Wrapper for {@link NBTTagCompound#getUniqueId(String)} which converts an NBTTagCompound directly to a UUID. - * Intended to be used as the inverse of {@link WizardryUtilities#UUIDtoTagCompound(UUID)}. - */ - public static UUID tagCompoundToUUID(NBTTagCompound tag){ - return tag.getUniqueId("uuid"); - } - - // SECTION Ally Designation System - // =============================================================================================================== - - /** - * Returns whether the given target can be attacked by the given attacker. It is up to the caller of this method to - * work out what this means; it doesn't necessarily mean the target is completely immune (for example, revenge - * targeting might reasonably bypass this). This method is intended for use where the damage is indirect and/or - * unavoidable; direct attacks should not check this method. Currently this means the following situations check - * this method: - *

    - * - AI targeting for summoned creatures
    - * - AI targeting for mind-controlled creatures
    - * - Constructs with an area of effect
    - * - Instantaneous spells with an area of effect around the caster (e.g. forest's curse, thunderstorm)
    - * - Any lightning chaining effects
    - * - Any projectiles which seek targets - *

    - * Also note that the friendly fire option is dealt with in the event handler. This method acts as a sort of wrapper - * for all the ADS stuff in {@link WizardData}; more details about the ally designation system can be found there. - * - * @param attacker The entity that cast the spell originally - * @param target The entity being attacked - * - * @return False under any of the following circumstances, true otherwise: - *

    - * - The target is null - *

    - * - The target is the attacker (this isn't as stupid as it sounds - anything with an AoE might cause this - * to be true, as can summoned creatures) - *

    - * - The target and the attacker are both players and the target is an ally of the attacker (but the - * attacker need not be an ally of the target) - *

    - * - The target is a creature that was summoned/controlled by the attacker or by an ally of the attacker. - *

    - * As of wizardry 4.1.2, this method now returns true instead of false if the attacker is null. This - * is because in the vast majority of cases, it makes more sense this way: if a construct has no caster, it - * should affect all entities; if a minion has no caster it should target all entities; etc. - */ - public static boolean isValidTarget(Entity attacker, Entity target){ - - // Always return true if the attacker is null - if(attacker == null) return true; - - // Always return false if the target is null - if(target == null) return false; - - // Tests whether the target is the attacker - if(target == attacker) return false; - - // Tests whether the target is a creature that was summoned by the attacker - if(target instanceof ISummonedCreature && ((ISummonedCreature)target).getCaster() == attacker){ - return false; - } - - // Tests whether the target is a creature that was mind controlled by the attacker - if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(WizardryPotions.mind_control)){ - - NBTTagCompound entityNBT = target.getEntityData(); - - if(entityNBT != null && entityNBT.hasUniqueId(MindControl.NBT_KEY)){ - if(attacker == WizardryUtilities.getEntityByUUID(target.world, - entityNBT.getUniqueId(MindControl.NBT_KEY))){ - return false; - } - } - } - - // Ally section - if(attacker instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker) != null){ - - if(target instanceof EntityPlayer){ - // Tests whether the target is an ally of the attacker - if(WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)target)){ - return false; - } - - }else if(target instanceof ISummonedCreature){ - // Tests whether the target is a creature that was summoned by an ally of the attacker - if(((ISummonedCreature)target).getCaster() instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker) - .isPlayerAlly((EntityPlayer)((ISummonedCreature)target).getCaster())){ - return false; - } - - }else if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(WizardryPotions.mind_control)){ - // Tests whether the target is a creature that was mind controlled by an ally of the attacker - NBTTagCompound entityNBT = target.getEntityData(); - - if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){ - - Entity controller = WizardryUtilities.getEntityByUUID(target.world, entityNBT.getUniqueId(MindControl.NBT_KEY)); - - if(controller instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)controller)){ - return false; - } - } - } - } - - return true; - } - - /** Helper method for testing if the second player is an ally of the first player. Makes the code neater. */ - public static boolean isPlayerAlly(EntityPlayer allyOf, EntityPlayer possibleAlly){ - - WizardData properties = WizardData.get(allyOf); - - if(properties != null && properties.isPlayerAlly(possibleAlly)) return true; - - return false; - } - - // SECTION Loot and Weighting - // =============================================================================================================== - - /** - * See {@link WizardryUtilities#getStandardWeightedRandomSpellId(Random, boolean)}. nonContinuous defaults to false. - */ - public static int getStandardWeightedRandomSpellId(Random random){ - return getStandardWeightedRandomSpellId(random, false); - } - - /** - * Helper method which gets a spell id according to the standard weighting. The tier is a weighted random value; the - * actual spell within that tier is completely random. Will not return the id of a spell which has been disabled in - * the config. This is for simple stuff like chests and drops; more complex generators like wizard trades don't use - * this method. - *

    - * For reference, the standard weighting is as follows: Basic: 60%, Apprentice: 25%, Advanced: 10%, Master: 5% - * - * @param random An instance of {@link Random} to use for RNG - * @param nonContinuous Whether the spells must be non-continuous (used for scrolls) - * @return A random spell id number - */ - public static int getStandardWeightedRandomSpellId(Random random, boolean nonContinuous){ - - Tier tier = Tier.getWeightedRandomTier(random); - - List spells = Spell.getSpells(new Spell.TierElementFilter(tier, null)); - if(nonContinuous) spells.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); - - // Ensures the tier chosen actually has spells in it, and if not uses BASIC instead. - if(spells.isEmpty()){ - spells = Spell.getSpells(new Spell.TierElementFilter(Tier.BASIC, null)); - if(nonContinuous) spells.retainAll(Spell.getSpells(Spell.nonContinuousSpells)); - } - - // Finds a random spell in the list and returns its id. - return spells.get(random.nextInt(spells.size())).id(); - } + // Neat way of getting a random element from a set, wasn't needed in the end but kept here for future reference +// public static E randomElement(Collection collection, Random random){ +// if(collection.isEmpty()) throw new IndexOutOfBoundsException("The given collection must not be empty"); +// Iterator iterator = collection.iterator(); +// for(int n = random.nextInt(collection.size()); n > 0; n--) iterator.next(); +// return iterator.next(); +// } } diff --git a/src/main/java/electroblob/wizardry/worldgen/MossifierTemplateProcessor.java b/src/main/java/electroblob/wizardry/worldgen/MossifierTemplateProcessor.java new file mode 100644 index 00000000..fab35b0d --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/MossifierTemplateProcessor.java @@ -0,0 +1,51 @@ +package electroblob.wizardry.worldgen; + +import net.minecraft.block.BlockStoneBrick; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.template.ITemplateProcessor; +import net.minecraft.world.gen.structure.template.Template; + +import javax.annotation.Nullable; + +/** Structure template processor that randomly 'mossifies' cobblestone and stone bricks in the structure. This is done + * using weighting so there is more moss at the bottom, making it look more natural. */ +// Behold, the ACME Mossifier 3000! (Patent pending) +public class MossifierTemplateProcessor implements ITemplateProcessor { + + private final float mossiness; + private final float heightWeight; + private final int groundLevel; + + /** + * Creates a new {@code MossifierTemplateProcessor} with the given parameters. + * @param mossiness The chance for each block in a given layer to be mossified. + * @param heightWeight The amount by which mossiness reduces for each subsequent level upwards. + * @param groundLevel The ground level for the structure, at which height is taken to be zero for the purposes of + * calculating mossiness. + */ + public MossifierTemplateProcessor(float mossiness, float heightWeight, int groundLevel){ + this.mossiness = mossiness; + this.heightWeight = heightWeight; + this.groundLevel = groundLevel; + } + + @Nullable + @Override + public Template.BlockInfo processBlock(World world, BlockPos pos, Template.BlockInfo info){ + + float chance = mossiness - heightWeight * (pos.getY() - groundLevel); + + if(world.rand.nextFloat() < chance){ + if(info.blockState.getBlock() == Blocks.COBBLESTONE){ + return new Template.BlockInfo(info.pos, Blocks.MOSSY_COBBLESTONE.getDefaultState(), info.tileentityData); + }else if(info.blockState.getBlock() == Blocks.STONEBRICK){ + return new Template.BlockInfo(info.pos, Blocks.STONEBRICK.getDefaultState() + .withProperty(BlockStoneBrick.VARIANT, BlockStoneBrick.EnumType.MOSSY), info.tileentityData); + } + } + + return info; + } +} diff --git a/src/main/java/electroblob/wizardry/worldgen/MultiTemplateProcessor.java b/src/main/java/electroblob/wizardry/worldgen/MultiTemplateProcessor.java new file mode 100644 index 00000000..791ba318 --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/MultiTemplateProcessor.java @@ -0,0 +1,39 @@ +package electroblob.wizardry.worldgen; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.template.ITemplateProcessor; +import net.minecraft.world.gen.structure.template.Template; + +import javax.annotation.Nullable; + +/** Structure template processor that allows multiple processors to be run in order. */ +public class MultiTemplateProcessor implements ITemplateProcessor { + + private final ITemplateProcessor[] processors; + private final boolean stopWhenNull; + + /** + * Creates a new {@code MultiTemplateProcessor} which applies the given processors in order. + * @param stopWhenNull True to skip any remaining processors in the sequence if one of them returns null, false to + * process them all regardless. If this is false, you should ensure all the given processors + * accept null {@link net.minecraft.world.gen.structure.template.Template.BlockInfo} arguments. + * @param processors The processors to be run, in order (i.e. the first one given will be applied first). + */ + public MultiTemplateProcessor(boolean stopWhenNull, ITemplateProcessor... processors){ + this.processors = processors; + this.stopWhenNull = stopWhenNull; + } + + @Nullable + @Override + public Template.BlockInfo processBlock(World world, BlockPos pos, Template.BlockInfo info){ + + for(ITemplateProcessor processor : processors){ + info = processor.processBlock(world, pos, info); + if(stopWhenNull && info == null) break; + } + + return info; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/worldgen/WoodTypeTemplateProcessor.java b/src/main/java/electroblob/wizardry/worldgen/WoodTypeTemplateProcessor.java new file mode 100644 index 00000000..a900c929 --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/WoodTypeTemplateProcessor.java @@ -0,0 +1,90 @@ +package electroblob.wizardry.worldgen; + +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.Block; +import net.minecraft.block.BlockPlanks; +import net.minecraft.block.BlockWoodSlab; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.template.ITemplateProcessor; +import net.minecraft.world.gen.structure.template.Template; + +import javax.annotation.Nullable; +import java.util.EnumMap; + +/** Structure template processor that switches all wood in the structure to a certain given wood type. */ +public class WoodTypeTemplateProcessor implements ITemplateProcessor { + + private final BlockPlanks.EnumType woodType; + + private final EnumMap DOORS; + private final EnumMap STAIRS; + private final EnumMap FENCES; + private final EnumMap FENCE_GATES; + + /** + * Creates a new {@code WoodTypeTemplateProcessor} of the given type. + * @param woodType The wood type to be used. + */ + public WoodTypeTemplateProcessor(BlockPlanks.EnumType woodType){ + + this.woodType = woodType; + + DOORS = new EnumMap<>(BlockPlanks.EnumType.class); + DOORS.put(BlockPlanks.EnumType.OAK, Blocks.OAK_DOOR); + DOORS.put(BlockPlanks.EnumType.SPRUCE, Blocks.SPRUCE_DOOR); + DOORS.put(BlockPlanks.EnumType.BIRCH, Blocks.BIRCH_DOOR); + DOORS.put(BlockPlanks.EnumType.JUNGLE, Blocks.JUNGLE_DOOR); + DOORS.put(BlockPlanks.EnumType.ACACIA, Blocks.ACACIA_DOOR); + DOORS.put(BlockPlanks.EnumType.DARK_OAK, Blocks.DARK_OAK_DOOR); + + STAIRS = new EnumMap<>(BlockPlanks.EnumType.class); + STAIRS.put(BlockPlanks.EnumType.OAK, Blocks.OAK_STAIRS); + STAIRS.put(BlockPlanks.EnumType.SPRUCE, Blocks.SPRUCE_STAIRS); + STAIRS.put(BlockPlanks.EnumType.BIRCH, Blocks.BIRCH_STAIRS); + STAIRS.put(BlockPlanks.EnumType.JUNGLE, Blocks.JUNGLE_STAIRS); + STAIRS.put(BlockPlanks.EnumType.ACACIA, Blocks.ACACIA_STAIRS); + STAIRS.put(BlockPlanks.EnumType.DARK_OAK, Blocks.DARK_OAK_STAIRS); + + FENCES = new EnumMap<>(BlockPlanks.EnumType.class); + FENCES.put(BlockPlanks.EnumType.OAK, Blocks.OAK_FENCE); + FENCES.put(BlockPlanks.EnumType.SPRUCE, Blocks.SPRUCE_FENCE); + FENCES.put(BlockPlanks.EnumType.BIRCH, Blocks.BIRCH_FENCE); + FENCES.put(BlockPlanks.EnumType.JUNGLE, Blocks.JUNGLE_FENCE); + FENCES.put(BlockPlanks.EnumType.ACACIA, Blocks.ACACIA_FENCE); + FENCES.put(BlockPlanks.EnumType.DARK_OAK, Blocks.DARK_OAK_FENCE); + + FENCE_GATES = new EnumMap<>(BlockPlanks.EnumType.class); + FENCE_GATES.put(BlockPlanks.EnumType.OAK, Blocks.OAK_FENCE_GATE); + FENCE_GATES.put(BlockPlanks.EnumType.SPRUCE, Blocks.SPRUCE_FENCE_GATE); + FENCE_GATES.put(BlockPlanks.EnumType.BIRCH, Blocks.BIRCH_FENCE_GATE); + FENCE_GATES.put(BlockPlanks.EnumType.JUNGLE, Blocks.JUNGLE_FENCE_GATE); + FENCE_GATES.put(BlockPlanks.EnumType.ACACIA, Blocks.ACACIA_FENCE_GATE); + FENCE_GATES.put(BlockPlanks.EnumType.DARK_OAK, Blocks.DARK_OAK_FENCE_GATE); + } + + @Nullable + @Override + public Template.BlockInfo processBlock(World world, BlockPos pos, Template.BlockInfo info){ + + // Why do these each have their own property key? + if(info.blockState.getBlock() instanceof BlockPlanks){ + return new Template.BlockInfo(info.pos, info.blockState.withProperty(BlockPlanks.VARIANT, woodType), info.tileentityData); + }else if(info.blockState.getBlock() instanceof BlockWoodSlab){ + return new Template.BlockInfo(info.pos, info.blockState.withProperty(BlockWoodSlab.VARIANT, woodType), info.tileentityData); + // This is a mess, no wonder the flattening happened + }else if(DOORS.containsValue(info.blockState.getBlock())){ + return new Template.BlockInfo(info.pos, WizardryUtilities.copyState(DOORS.get(woodType), info.blockState), info.tileentityData); + }else if(STAIRS.containsValue(info.blockState.getBlock())){ + return new Template.BlockInfo(info.pos, WizardryUtilities.copyState(STAIRS.get(woodType), info.blockState), info.tileentityData); + }else if(FENCES.containsValue(info.blockState.getBlock())){ + return new Template.BlockInfo(info.pos, WizardryUtilities.copyState(FENCES.get(woodType), info.blockState), info.tileentityData); + }else if(FENCE_GATES.containsValue(info.blockState.getBlock())){ + return new Template.BlockInfo(info.pos, WizardryUtilities.copyState(FENCE_GATES.get(woodType), info.blockState), info.tileentityData); + } + + return info; + } + +} diff --git a/src/main/java/electroblob/wizardry/worldgen/WorldGenCrystalFlower.java b/src/main/java/electroblob/wizardry/worldgen/WorldGenCrystalFlower.java new file mode 100644 index 00000000..8de076b8 --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/WorldGenCrystalFlower.java @@ -0,0 +1,61 @@ +package electroblob.wizardry.worldgen; + +import com.google.common.primitives.Ints; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryBlocks; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraftforge.fml.common.IWorldGenerator; + +import java.util.Random; + +public class WorldGenCrystalFlower implements IWorldGenerator { + + @Override + public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider){ + + if(Ints.contains(Wizardry.settings.flowerDimensions, world.provider.getDimension())){ + this.generatePlant(WizardryBlocks.crystal_flower.getDefaultState(), world, random, 8 + chunkX * 16, 8 + chunkZ * 16, 2, 20); + } + } + + /** + * Generates the specified plant randomly throughout the world. + * + * @param state The plant block + * @param world The world + * @param random A instance of {@code Random} to use + * @param x The x coordinate of the first block in the chunk + * @param z The y coordinate of the first block in the chunk + * @param chancesToSpawn Number of chances to spawn a flower patch + * @param groupSize The number of times to try generating a flower per flower patch spawn + */ + public void generatePlant(IBlockState state, World world, Random random, int x, int z, int chancesToSpawn, int groupSize){ + + for(int i = 0; i < chancesToSpawn; i++){ + + int randPosX = x + random.nextInt(16); + int randPosY = random.nextInt(256); + int randPosZ = z + random.nextInt(16); + + for(int l = 0; l < groupSize; ++l){ + + int i1 = randPosX + random.nextInt(8) - random.nextInt(8); + int j1 = randPosY + random.nextInt(4) - random.nextInt(4); + int k1 = randPosZ + random.nextInt(8) - random.nextInt(8); + + BlockPos pos = new BlockPos(i1, j1, k1); + + if(world.isBlockLoaded(pos) && world.isAirBlock(pos) && (!world.provider.isNether() || j1 < 127) + && state.getBlock().canPlaceBlockOnSide(world, pos, EnumFacing.UP)){ + + world.setBlockState(pos, state, 2); + } + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/worldgen/WorldGenCrystalOre.java b/src/main/java/electroblob/wizardry/worldgen/WorldGenCrystalOre.java new file mode 100644 index 00000000..151b3776 --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/WorldGenCrystalOre.java @@ -0,0 +1,61 @@ +package electroblob.wizardry.worldgen; + +import com.google.common.primitives.Ints; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryBlocks; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraft.world.gen.feature.WorldGenMinable; +import net.minecraftforge.fml.common.IWorldGenerator; + +import java.util.Random; + +public class WorldGenCrystalOre implements IWorldGenerator { + + @Override + public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider){ + + if(Ints.contains(Wizardry.settings.oreDimensions, world.provider.getDimension())){ + this.addOreSpawn(WizardryBlocks.crystal_ore.getDefaultState(), world, random, chunkX * 16, chunkZ * 16, 16, 16, 5, 7, 5, 30); + } + } + + /** + * Adds an Ore Spawn to Minecraft. Simply register all Ores to spawn with this method in your Generation method in + * your IWorldGeneration extending Class + * + * @param state The Block to spawn + * @param world The World to spawn in + * @param random A Random object for retrieving random positions within the world to spawn the Block + * @param blockXPos An int for passing the X-Coordinate for the Generation method + * @param blockZPos An int for passing the Z-Coordinate for the Generation method + * @param maxX An int for setting the maximum X-Coordinate values for spawning on the X-Axis on a Per-Chunk basis + * @param maxZ An int for setting the maximum Z-Coordinate values for spawning on the Z-Axis on a Per-Chunk basis + * @param maxVeinSize An int for setting the maximum size of a vein + * @param chancesToSpawn An int for the Number of chances available for the Block to spawn per-chunk + * @param minY An int for the minimum Y-Coordinate height at which this block may spawn + * @param maxY An int for the maximum Y-Coordinate height at which this block may spawn + **/ + public void addOreSpawn(IBlockState state, World world, Random random, int blockXPos, int blockZPos, int maxX, + int maxZ, int maxVeinSize, int chancesToSpawn, int minY, int maxY){ + // int maxPossY = minY + (maxY - 1); + assert maxY > minY : "The maximum Y must be greater than the Minimum Y"; + assert maxX > 0 && maxX <= 16 : "addOreSpawn: The Maximum X must be greater than 0 and less than 16"; + assert minY > 0 : "addOreSpawn: The Minimum Y must be greater than 0"; + assert maxY < 256 && maxY > 0 : "addOreSpawn: The Maximum Y must be less than 256 but greater than 0"; + assert maxZ > 0 && maxZ <= 16 : "addOreSpawn: The Maximum Z must be greater than 0 and less than 16"; + + int diffBtwnMinMaxY = maxY - minY; + for(int x = 0; x < chancesToSpawn; x++){ + int posX = blockXPos + random.nextInt(maxX); + int posY = minY + random.nextInt(diffBtwnMinMaxY); + int posZ = blockZPos + random.nextInt(maxZ); + // N.B. This method applies the anti-cascading-lag offset itself + (new WorldGenMinable(state, maxVeinSize)).generate(world, random, new BlockPos(posX, posY, posZ)); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/worldgen/WorldGenObelisk.java b/src/main/java/electroblob/wizardry/worldgen/WorldGenObelisk.java new file mode 100644 index 00000000..e8d6d1d2 --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/WorldGenObelisk.java @@ -0,0 +1,101 @@ +package electroblob.wizardry.worldgen; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockRunestone; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration; +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.MobSpawnerBaseLogic; +import net.minecraft.tileentity.TileEntityMobSpawner; +import net.minecraft.util.Mirror; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.template.ITemplateProcessor; +import net.minecraft.world.gen.structure.template.PlacementSettings; +import net.minecraft.world.gen.structure.template.Template; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.EnumMap; +import java.util.Map; +import java.util.Random; + +public class WorldGenObelisk extends WorldGenSurfaceStructure { + + private static final String SPAWNER_DATA_BLOCK_TAG = "spawner"; + + private static final EnumMap MOB_TYPES = new EnumMap<>(Element.class); + + static { + MOB_TYPES.put(Element.FIRE, new ResourceLocation(Wizardry.MODID, "blaze_minion")); + MOB_TYPES.put(Element.ICE, new ResourceLocation(Wizardry.MODID, "ice_wraith")); + MOB_TYPES.put(Element.LIGHTNING, new ResourceLocation(Wizardry.MODID, "lightning_wraith")); + MOB_TYPES.put(Element.NECROMANCY, new ResourceLocation(Wizardry.MODID, "wither_skeleton_minion")); + MOB_TYPES.put(Element.EARTH, new ResourceLocation(Wizardry.MODID, "spider_minion")); + MOB_TYPES.put(Element.SORCERY, new ResourceLocation(Wizardry.MODID, "vex_minion")); + MOB_TYPES.put(Element.HEALING, new ResourceLocation(Wizardry.MODID, "husk_minion")); + } + + @Override + public String getStructureName(){ + return "obelisk"; + } + + @Override + public long getRandomSeedModifier(){ + return 19348242L; + } + + @Override + public Mirror[] getValidMirrors(){ + return new Mirror[]{Mirror.NONE}; // It's symmetrical so there's no point mirroring it + } + + @Override + public boolean canGenerate(Random random, World world, int chunkX, int chunkZ){ + return ArrayUtils.contains(Wizardry.settings.obeliskDimensions, world.provider.getDimension()) + && Wizardry.settings.obeliskRarity > 0 && random.nextInt(Wizardry.settings.obeliskRarity) == 0; + } + + @Override + public ResourceLocation getStructureFile(Random random){ + return Wizardry.settings.obeliskFiles[random.nextInt(Wizardry.settings.obeliskFiles.length)]; + } + + @Override + public void spawnStructure(Random random, World world, BlockPos origin, Template template, PlacementSettings settings, ResourceLocation structureFile){ + + final Element element = Element.values()[1 + random.nextInt(Element.values().length-1)]; + + ITemplateProcessor processor = (w, p, i) -> i.blockState.getBlock() instanceof BlockRunestone ? new Template.BlockInfo( + i.pos, i.blockState.withProperty(BlockRunestone.ELEMENT, element), i.tileentityData) : i; + + template.addBlocksToWorld(world, origin, processor, settings, 2); + + WizardryAntiqueAtlasIntegration.markObelisk(world, origin.getX(), origin.getZ()); + + // Mob spawner + Map dataBlocks = template.getDataBlocks(origin, settings); + + for(Map.Entry entry : dataBlocks.entrySet()){ + + if(entry.getValue().equals(SPAWNER_DATA_BLOCK_TAG)){ + + world.setBlockState(entry.getKey(), Blocks.MOB_SPAWNER.getDefaultState()); + + if(world.getTileEntity(entry.getKey()) instanceof TileEntityMobSpawner){ + + MobSpawnerBaseLogic spawnerLogic = ((TileEntityMobSpawner)world.getTileEntity(entry.getKey())).getSpawnerBaseLogic(); + spawnerLogic.setEntityId(MOB_TYPES.get(element)); + + }else{ + Wizardry.logger.info("Tried to set the mob spawned by an obelisk, but the expected TileEntityMobSpawner was not present"); + } + + }else{ + // This probably shouldn't happen... + Wizardry.logger.info("Unrecognised data block value {} in structure {}", entry.getValue(), structureFile); + } + } + } +} diff --git a/src/main/java/electroblob/wizardry/worldgen/WorldGenShrine.java b/src/main/java/electroblob/wizardry/worldgen/WorldGenShrine.java new file mode 100644 index 00000000..076a811d --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/WorldGenShrine.java @@ -0,0 +1,95 @@ +package electroblob.wizardry.worldgen; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.block.BlockPedestal; +import electroblob.wizardry.block.BlockRunestone; +import electroblob.wizardry.constants.Element; +import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration; +import electroblob.wizardry.registry.WizardryBlocks; +import electroblob.wizardry.spell.ArcaneLock; +import electroblob.wizardry.tileentity.TileEntityShrineCore; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.template.ITemplateProcessor; +import net.minecraft.world.gen.structure.template.PlacementSettings; +import net.minecraft.world.gen.structure.template.Template; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.Map; +import java.util.Random; +import java.util.UUID; + +public class WorldGenShrine extends WorldGenSurfaceStructure { + + private static final String CORE_DATA_BLOCK_TAG = "core"; + + @Override + public String getStructureName(){ + return "shrine"; + } + + @Override + public long getRandomSeedModifier(){ + return 17502749L; + } + + @Override + public boolean canGenerate(Random random, World world, int chunkX, int chunkZ){ + return ArrayUtils.contains(Wizardry.settings.shrineDimensions, world.provider.getDimension()) + && Wizardry.settings.shrineRarity > 0 && random.nextInt(Wizardry.settings.shrineRarity) == 0; + } + + @Override + public ResourceLocation getStructureFile(Random random){ + return Wizardry.settings.shrineFiles[random.nextInt(Wizardry.settings.shrineFiles.length)]; + } + + @Override + public void spawnStructure(Random random, World world, BlockPos origin, Template template, PlacementSettings settings, ResourceLocation structureFile){ + + final Element element = Element.values()[1 + random.nextInt(Element.values().length-1)]; + + ITemplateProcessor processor = (w, p, i) -> i.blockState.getBlock() instanceof BlockRunestone ? new Template.BlockInfo( + i.pos, i.blockState.withProperty(BlockRunestone.ELEMENT, element), i.tileentityData) : i; + + template.addBlocksToWorld(world, origin, processor, settings, 2); + + WizardryAntiqueAtlasIntegration.markShrine(world, origin.getX(), origin.getZ()); + + // Shrine core + Map dataBlocks = template.getDataBlocks(origin, settings); + + for(Map.Entry entry : dataBlocks.entrySet()){ + + if(entry.getValue().equals(CORE_DATA_BLOCK_TAG)){ + // This bit could have been done with a template processor, but we also need to link the chest and lock it + world.setBlockState(entry.getKey(), WizardryBlocks.runestone_pedestal.getDefaultState() + .withProperty(BlockPedestal.ELEMENT, element).withProperty(BlockPedestal.NATURAL, true)); + + TileEntity core = world.getTileEntity(entry.getKey()); + TileEntity container = world.getTileEntity(entry.getKey().up()); + + if(container != null){ + + container.getTileData().setUniqueId(ArcaneLock.NBT_KEY, new UUID(0, 0)); // Nil UUID + + if(core instanceof TileEntityShrineCore){ + ((TileEntityShrineCore)core).linkContainer(container); + }else{ + Wizardry.logger.info("What?!"); + } + + }else{ + Wizardry.logger.info("Expected chest or other container at {} in structure {}, found no tile entity", entry.getKey(), structureFile); + } + + }else{ + // This probably shouldn't happen... + Wizardry.logger.info("Unrecognised data block value {} in structure {}", entry.getValue(), structureFile); + } + } + } + +} diff --git a/src/main/java/electroblob/wizardry/worldgen/WorldGenSurfaceStructure.java b/src/main/java/electroblob/wizardry/worldgen/WorldGenSurfaceStructure.java new file mode 100644 index 00000000..a2b58c31 --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/WorldGenSurfaceStructure.java @@ -0,0 +1,450 @@ +package electroblob.wizardry.worldgen; + +import com.google.common.math.Quantiles; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.registry.WizardryAdvancementTriggers; +import electroblob.wizardry.util.WizardryUtilities; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.block.Block; +import net.minecraft.block.BlockLeaves; +import net.minecraft.block.BlockLog; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.Mirror; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Rotation; +import net.minecraft.util.math.*; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraft.world.gen.structure.MapGenStructureData; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraft.world.gen.structure.template.PlacementSettings; +import net.minecraft.world.gen.structure.template.Template; +import net.minecraftforge.common.BiomeDictionary; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fml.common.IWorldGenerator; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import javax.annotation.Nullable; +import java.util.*; + +/** Base structure generation class which handles code common to all wizardry's above-ground structures, such as + * calculating the median ground level. */ +@Mod.EventBusSubscriber +public abstract class WorldGenSurfaceStructure implements IWorldGenerator { + + /** The maximum fraction of the area where a structure is to be spawned that may be covered by liquid. */ + private static final float MAX_LIQUID_FRACTION = 0.4f; + + /** Static map used to store all structure generators for the purpose of advancements. */ + private static final Map generators = new HashMap<>(); + + /** A random instance used solely for the purpose of emulating the world generation to predict locations. */ + private final Random random; + + private World world; + + private MapGenStructureData structureData; + + /** Stores the bounding boxes of all structures of this type that have been generated so far. */ + protected final Long2ObjectMap structureMap = new Long2ObjectOpenHashMap<>(1024); + + public WorldGenSurfaceStructure(){ + random = new Random(); // Seed will be set later + generators.put(this.getStructureName(), this); + } + + /** Returns a constant (but unique) long value used to change the random seed so that each generator produces a + * different sequence of numbers. Without this, all wizardry's generators attempt to generate in the same chunks + * when set to the same rarity. */ + public abstract long getRandomSeedModifier(); + + /** Pre-check for whether the structure can generate. Usually this is just used for randomisation so that + * calculations are only performed for chunks that will generate a structure; most placement-specific stuff + * can just be done using a check inside {@link WorldGenSurfaceStructure#spawnStructure(Random, World, BlockPos, Template, PlacementSettings, ResourceLocation)} */ + public abstract boolean canGenerate(Random random, World world, int chunkX, int chunkZ); + + /** Called each time the structure is generated to get a structure file to use. */ + public abstract ResourceLocation getStructureFile(Random random); + + /** Returns the name of this structure type, which is used as an identifier in the world save file and for + * advancement JSON files. */ + public abstract String getStructureName(); + + /** + * Spawns the structure at the given origin with the given placement settings. + * @param random A {@code Random} instance to use for any further parameters that need randomising. + * @param world The world to spawn the structure in. + * @param origin The origin coordinates of the structure in the world, pre-adjusted for floor height and rotation + * to avoid floating structures and minimise cascading worldgen lag. + * @param template The template to be generated. + * @param settings The placement settings for the structure. + * @param structureFile The location of the chosen structure file, for logging purposes. + */ + public abstract void spawnStructure(Random random, World world, BlockPos origin, Template template, PlacementSettings settings, ResourceLocation structureFile); + + /** Specifies valid rotation values for the structure. By default this returns all rotations. */ + public Rotation[] getValidRotations(){ + return Rotation.values(); + } + + /** Specifies valid rotation values for the structure. By default this returns an array of {@code Mirror.LEFT_RIGHT} + * and {@code Mirror.NONE}. */ + public Mirror[] getValidMirrors(){ + return new Mirror[]{Mirror.NONE, Mirror.LEFT_RIGHT}; + } + + /** + * Finds a random position within the given chunk at which the given template may be generated. + * In an effort to make structure rarity more uniform, they now get a number of tries to spawn in each + * randomly-selected chunk so they have a better chance of avoiding stuff that might be in the way (cliffs, + * villages, lakes, etc.). + *

    + * This method calculates the median floor height to ensure that sudden changes in level are ignored and the + * structure is always spawned at the same level as the majority of the underlying floor. Trees are also ignored + * when determining floor level, so that forests don't impede structure spawning. + * + * @param template The template to be generated + * @param settings The placement settings for the structure template + * @param random A random instance to use. This should have had its seed set according to the world seed and chunk + * coordinates. + * @param world The world in which to spawn the structure + * @param chunkX The x-coordinate of the chunk being populated + * @param chunkZ The z-coordinate of the chunk being populated + * @return The coordinates of the position found, or null if no suitable position was found. The returned + * {@code BlockPos} is always the northwest corner of the structure, and the y-coordinate is that of the + * uppermost block at those (x, z) coordinates. If the structure is being rotated this needs to be altered using + * {@link Template#getZeroPositionWithTransform(BlockPos, Mirror, Rotation)} before it can be fed into the template + * spawning methods. + */ + @Nullable + protected BlockPos findValidPosition(Template template, PlacementSettings settings, Random random, World world, + int chunkX, int chunkZ){ + + // Offset by (8, 8) to minimise cascading worldgen lag + // See https://www.reddit.com/r/feedthebeast/cowmments/5x0twz/investigating_extreme_worldgen_lag/?ref=share&ref_source=embed&utm_content=title&utm_medium=post_embed&utm_name=c07cbb545f74487793783012794733d8&utm_source=embedly&utm_term=5x0twz + // Multiplying and left-shifting are identical but it's good practice to bitshift here I guess + BlockPos origin = new BlockPos(8 + (chunkX << 4) + random.nextInt(16), 0, 8 + (chunkZ << 4) + random.nextInt(16)); + + BlockPos size = template.transformedSize(settings.getRotation()); + // Estimate a starting height for searching for the floor + BlockPos centre = world.getTopSolidOrLiquidBlock(new BlockPos(origin.add(size.getX()/2, 0, size.getZ()/2))); + Integer startingHeight = WizardryUtilities.getNearestSurface(world, centre, EnumFacing.UP, 32, true, + WizardryUtilities.SurfaceCriteria.COLLIDABLE_IGNORING_TREES); + + if(startingHeight == null) return null; + + if(Wizardry.settings.fastWorldgen){ + BlockPos result = origin.up(startingHeight); + // Fast worldgen doesn't check for water, instead it checks the biome like vanilla, which is crude but fast + return BiomeDictionary.hasType(world.getBiome(result), BiomeDictionary.Type.WATER) ? null : result; + } + + int[] floorHeights = new int[size.getX() * size.getZ()]; + + int liquidCount = 0; + + for(int i = 0; i < floorHeights.length; i++){ + // Despite what its name suggests, this method does not return the position of a liquid. It is in fact + // exactly what is needed here since it is used for placing villages and stuff, and doesn't include leaves + // or other foliage. + BlockPos pos = origin.add(i / size.getZ(), 0, i % size.getZ()); + Integer floor = WizardryUtilities.getNearestSurface(world, pos.up(startingHeight), EnumFacing.UP, 32, true, + WizardryUtilities.SurfaceCriteria.COLLIDABLE_IGNORING_TREES); + floorHeights[i] = floor == null ? 0 : floor; // Very unlikely that floor is null + // ^ That method gets the top solid block. Most non-solid blocks are ok to have around the structure, + // with the exception of liquids, so if there are too many the position is deemed unsuitable. + if(world.getBlockState(pos.up(floorHeights[i])).getMaterial().isLiquid()) liquidCount++; + if(liquidCount > floorHeights.length * MAX_LIQUID_FRACTION) return null; + } + + // Get the median floor height (rather than the mean, that way cliffs should have no effect) + int medianFloorHeight = MathHelper.floor(Quantiles.median().compute(floorHeights)); + + // Now we know the y level of the base of the structure, we can check for stuff in the way + // A structure is deemed to have stuff in the way if the floor level at any of the (x, z) positions it + // occupies differs from the base y level by more than its distance from the centre plus a constant. + // In practical terms, this means structures can't spawn on steep slopes or inside cave mouths or buildings. + + for(int i = 0; i < floorHeights.length; i++){ + int orthogonalDist = Math.max(Math.abs(i / size.getZ() - size.getX()/2), Math.abs(i % size.getZ() - size.getZ()/2)); + if(Math.abs(floorHeights[i] - medianFloorHeight) > Math.max(2, orthogonalDist)) return null; // Something is in the way + } + + return origin.up(medianFloorHeight - 1); + } + + @Override + public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider){ + + if(!world.getWorldInfo().isMapFeaturesEnabled()) return; + + // Don't need to worry about overflows because they'll just wrap around, which is fine for this purpose + random.setSeed(random.nextLong() + getRandomSeedModifier()); + + initializeStructureData(world); // Load the data from the save file if it isn't already loaded + + if(canGenerate(random, world, chunkX, chunkZ)){ + + ResourceLocation structureFile = getStructureFile(random); + + Template template = world.getSaveHandler().getStructureTemplateManager().getTemplate( + world.getMinecraftServer(), structureFile); + + Rotation[] rotations = getValidRotations(); + Mirror[] mirrors = getValidMirrors(); + + PlacementSettings settings = new PlacementSettings() + .setRotation(rotations[random.nextInt(rotations.length)]) + .setMirror(mirrors[random.nextInt(mirrors.length)]); + + int triesLeft = 10; + + BlockPos origin; + + do { + origin = findValidPosition(template, settings, random, world, chunkX, chunkZ); + triesLeft--; + }while(triesLeft > 0 && origin != null); + + if(origin == null) return; + + // Need to subtract 1 from each coordinate since both corners are inclusive + StructureBoundingBox box = new StructureBoundingBox(origin, origin.add(template.transformedSize(settings.getRotation())).add(-1, -1, -1)); + + // DEBUG +// world.setBlockState(new BlockPos(box.minX, box.minY, box.minZ), Blocks.CONCRETE.getDefaultState().withProperty(BlockColored.COLOR, EnumDyeColor.MAGENTA)); +// world.setBlockState(new BlockPos(box.maxX, box.maxY, box.maxZ), Blocks.CONCRETE.getDefaultState().withProperty(BlockColored.COLOR, EnumDyeColor.MAGENTA)); + + if(!Wizardry.settings.fastWorldgen){ + for(WorldGenSurfaceStructure generator : generators.values()){ + StructureBoundingBox otherbox = generator.structureMap.get(ChunkPos.asLong(origin.getX() >> 4, origin.getZ() >> 4)); + if(otherbox != null && otherbox.intersectsWith(box)) return; + } + } + + settings.setBoundingBox(box); + + // PlacementSettings rotates and mirrors the structure around the origin, keeping the origin in the same + // place in the world. This means the structure can be rotated/mirrored into the 8 block border, undoing all + // our hard work to try and prevent cascading worldgen lag! + + // To properly minimise cascading worldgen lag, the method below returns the position where the corner needs + // to be such that the original structure's NW (-X, -Z) corner is at the origin. + origin = template.getZeroPositionWithTransform(origin, settings.getMirror(), settings.getRotation()); + + spawnStructure(random, world, origin, template, settings, structureFile); + + if(!Wizardry.settings.fastWorldgen) removeFloatingTrees(world, box); + + structureMap.put(ChunkPos.asLong(origin.getX() >> 4, origin.getZ() >> 4), settings.getBoundingBox()); + + NBTTagCompound tag = new NBTTagCompound(); + tag.setInteger("ChunkX", chunkX); + tag.setInteger("ChunkZ", chunkZ); + tag.setTag("BB", settings.getBoundingBox().toNBTTagIntArray()); + structureData.writeInstance(tag, chunkX, chunkZ); + structureData.markDirty(); + } + } + + /** Copied from MapGenStructure. Unlike most NBT loading, this is lazy - it only gets read from NBT when requested. */ + protected void initializeStructureData(World world){ + + // If the world that was last generated is not this world, load the data for the new world + // This is a bit of a dirty hack, it would be better if we had separate instances per-world but... effort... + // For now it works, maybe one day I'll improve it + if(world != this.world){ + + this.world = world; + + this.structureData = (MapGenStructureData)world.getPerWorldStorage().getOrLoadData(MapGenStructureData.class, this.getStructureName()); + + // This has to be cleared or worlds will interfere with each other! + // Vanilla doesn't have to do this because each world has a separate ChunkGenerator which stores MapGenBase + // instances + this.structureMap.clear(); + + if(this.structureData == null){ + + this.structureData = new MapGenStructureData(this.getStructureName()); + world.getPerWorldStorage().setData(this.getStructureName(), this.structureData); + + }else{ + + NBTTagCompound nbt = this.structureData.getTagCompound(); + + for(String s : nbt.getKeySet()){ + + NBTBase nbtbase = nbt.getTag(s); + + if(nbtbase.getId() == Constants.NBT.TAG_COMPOUND){ + + NBTTagCompound entry = (NBTTagCompound)nbtbase; + + if(entry.hasKey("ChunkX") && entry.hasKey("ChunkZ") && entry.hasKey("BB")){ + + int i = entry.getInteger("ChunkX"); + int j = entry.getInteger("ChunkZ"); + int[] coords = entry.getIntArray("BB"); + + this.structureMap.put(ChunkPos.asLong(i, j), new StructureBoundingBox(coords)); + } + } + } + } + } + } + + /** Finds and removes any floating bits of tree in and above the given structure bounding box. */ + protected static void removeFloatingTrees(World world, StructureBoundingBox boundingBox){ + + boolean changed = true; + int y = boundingBox.minY; + + // Remove all the logs + + while(changed && y < world.getHeight()){ // I do hope the trees don't reach the world height... + + // Always checks at least the first layer above the bounding box in case the structure cut the rest off + if(y > boundingBox.maxY + 1) changed = false; + + for(int x = boundingBox.minX; x <= boundingBox.maxX; x++){ + for(int z = boundingBox.minZ; z <= boundingBox.maxZ; z++){ + + BlockPos pos = new BlockPos(x, y, z); + + Block block = world.getBlockState(pos).getBlock(); + Block below = world.getBlockState(pos.down()).getBlock(); + + if(block instanceof BlockLog){ + if(below != Blocks.GRASS && below != Blocks.DIRT && !(below instanceof BlockLog) && + !below.isLeaves(world.getBlockState(pos.down()), world, pos.down())){ + world.setBlockToAir(pos); + changed = true; + } + } + } + } + + y++; + } + + // Now update all leaves in the area 16 times to make them decay + + int border = 8; + + List leaves = new ArrayList<>(); + + for(int x = boundingBox.minX - border; x <= boundingBox.maxX + border; x++){ + for(int y1 = boundingBox.minY - border; y1 <= y + border; y1++){ + for(int z = boundingBox.minZ - border; z <= boundingBox.maxZ + border; z++){ + BlockPos pos = new BlockPos(x, y1, z); + if(world.getBlockState(pos).getBlock() instanceof BlockLeaves) leaves.add(pos); + } + } + } + + for(int i=0; i<16; i++){ + leaves.forEach(p -> world.getBlockState(p).getBlock().updateTick(world, p, world.getBlockState(p), null)); + } + + // Finally, remove all the items that were dropped as a result of leaf decay + + AxisAlignedBB box = new AxisAlignedBB(boundingBox.minX, boundingBox.minY, boundingBox.minZ, boundingBox.maxX, y, boundingBox.maxZ).grow(border); + + world.getEntitiesWithinAABB(EntityItem.class, box).forEach(Entity::setDead); + + } + + /** Returns true if the given position is within a structure of this type in the given world, false + * otherwise. This will not work on chunks that are yet to be generated; attempting to do so will print a + * warning to the console. */ + public boolean isInsideStructure(World world, double x, double y, double z){ + + initializeStructureData(world); // Load the data from the save file if it isn't already loaded + + int chunkX = (int)x >> 4; + int chunkZ = (int)z >> 4; + + if(!world.isChunkGeneratedAt(chunkX, chunkZ)){ + Wizardry.logger.warn("Testing whether position ({}, {}, {}) is inside a structure, but that chunk hasn't been generated yet", x, y, z); + return false; + } + + // Vanilla just iterates through the entire structure map, but we can be a little more intelligent + // about it by only testing the chunks near the player (since all the structures are smaller than 32x32) + long[] chunks = {ChunkPos.asLong(chunkX - 1, chunkZ - 1), ChunkPos.asLong(chunkX - 1, chunkZ), ChunkPos.asLong(chunkX - 1, chunkZ + 1), + ChunkPos.asLong(chunkX, chunkZ - 1), ChunkPos.asLong(chunkX, chunkZ), ChunkPos.asLong(chunkX, chunkZ + 1), + ChunkPos.asLong(chunkX + 1, chunkZ - 1), ChunkPos.asLong(chunkX + 1, chunkZ), ChunkPos.asLong(chunkX + 1, chunkZ + 1)}; + + for(long chunkPos : chunks){ + if(structureMap.containsKey(chunkPos) && structureMap.get(chunkPos).isVecInside(new Vec3i(x, y, z))) + return true; + } + + return false; + } + + /** Copied from MapGenMineshaft. The general idea (it seems) is to emulate the world generator's randomisation + * without actually placing any blocks. Presumably mineshafts don't need sub-chunk randomisation? */ + public BlockPos getNearestStructurePos(World world, BlockPos pos, boolean findUnexplored){ + + // TODO: We have a problem here, in that the 'pragmatic' placement algorithm (good as it is) requires + // the chunk to have already been generated, so we can't be sure if a structure actually exists until + // the chunk is actually generated. + + int j = pos.getX() >> 4; + int k = pos.getZ() >> 4; + + for (int l = 0; l <= 1000; ++l) + { + for (int i1 = -l; i1 <= l; ++i1) + { + boolean flag = i1 == -l || i1 == l; + + for (int j1 = -l; j1 <= l; ++j1) + { + boolean flag1 = j1 == -l || j1 == l; + + if (flag || flag1) + { + // TESTME: Is this the same as Forge's per-chunk seeds? (see caller of generate()) + int k1 = j + i1; + int l1 = k + j1; + this.random.setSeed((long)(k1 ^ l1) ^ world.getSeed()); + this.random.nextInt(); + + if(this.canGenerate(this.random, world, k1, l1) && (!findUnexplored || !world.isChunkGeneratedAt(k1, l1))){ + return new BlockPos((k1 << 4) + 8, 64, (l1 << 4) + 8); + } + } + } + } + } + + return null; + } + + /** Returns the world generator with the given name. */ + public static WorldGenSurfaceStructure byName(String name){ + return generators.get(name); + } + + @SubscribeEvent + public static void onPlayerTick(TickEvent.PlayerTickEvent event){ + if(event.player instanceof EntityPlayerMP && event.player.ticksExisted % 20 == 0){ + WizardryAdvancementTriggers.visit_structure.trigger((EntityPlayerMP)event.player); + } + } + +} diff --git a/src/main/java/electroblob/wizardry/worldgen/WorldGenWizardTower.java b/src/main/java/electroblob/wizardry/worldgen/WorldGenWizardTower.java new file mode 100644 index 00000000..64882da9 --- /dev/null +++ b/src/main/java/electroblob/wizardry/worldgen/WorldGenWizardTower.java @@ -0,0 +1,165 @@ +package electroblob.wizardry.worldgen; + +import com.google.common.collect.ImmutableMap; +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.entity.living.EntityEvilWizard; +import electroblob.wizardry.entity.living.EntityWizard; +import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration; +import electroblob.wizardry.util.WizardryUtilities; +import net.minecraft.block.BlockPlanks; +import net.minecraft.block.BlockStainedHardenedClay; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Biomes; +import net.minecraft.init.Blocks; +import net.minecraft.item.EnumDyeColor; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.structure.template.ITemplateProcessor; +import net.minecraft.world.gen.structure.template.PlacementSettings; +import net.minecraft.world.gen.structure.template.Template; +import net.minecraftforge.common.BiomeDictionary; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.HashSet; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +public class WorldGenWizardTower extends WorldGenSurfaceStructure { + + // TODO: Add wizard towers to the /locate command + // This requires some careful manipulation of Random objects to replicate the positions exactly for the current + // world. See the end of ChunkGeneratorOverworld for the relevant methods. + + private static final String WIZARD_DATA_BLOCK_TAG = "wizard"; + private static final String EVIL_WIZARD_DATA_BLOCK_TAG = "evil_wizard"; + + private final Map SPECIAL_WALL_BLOCKS; + + public WorldGenWizardTower(){ + // These are initialised here because it's a convenient point after the blocks are registered + SPECIAL_WALL_BLOCKS = ImmutableMap.of( + BiomeDictionary.Type.MESA, Blocks.RED_SANDSTONE.getDefaultState(), + BiomeDictionary.Type.MOUNTAIN, Blocks.STONEBRICK.getDefaultState(), + BiomeDictionary.Type.NETHER, Blocks.NETHER_BRICK.getDefaultState(), + BiomeDictionary.Type.SANDY, Blocks.SANDSTONE.getDefaultState() + ); + } + + @Override + public String getStructureName(){ + return "wizard_tower"; + } + + @Override + public long getRandomSeedModifier(){ + return 10473957L; // Yep, I literally typed 8 digits at random + } + + @Override + public boolean canGenerate(Random random, World world, int chunkX, int chunkZ){ + return ArrayUtils.contains(Wizardry.settings.towerDimensions, world.provider.getDimension()) + && Wizardry.settings.towerRarity > 0 && random.nextInt(Wizardry.settings.towerRarity) == 0; + } + + @Override + public ResourceLocation getStructureFile(Random random){ + return random.nextDouble() < Wizardry.settings.evilWizardChance ? + Wizardry.settings.towerWithChestFiles[random.nextInt(Wizardry.settings.towerWithChestFiles.length)] : + Wizardry.settings.towerFiles[random.nextInt(Wizardry.settings.towerFiles.length)]; + } + + @Override + public void spawnStructure(Random random, World world, BlockPos origin, Template template, PlacementSettings settings, ResourceLocation structureFile){ + + final EnumDyeColor colour = EnumDyeColor.values()[random.nextInt(EnumDyeColor.values().length)]; + final Biome biome = world.getBiome(origin); + + final IBlockState wallMaterial = SPECIAL_WALL_BLOCKS.keySet().stream().filter(t -> BiomeDictionary.hasType(biome, t)) + .findFirst().map(SPECIAL_WALL_BLOCKS::get).orElse(Blocks.COBBLESTONE.getDefaultState()); + + final float mossiness = getBiomeMossiness(biome); + final BlockPlanks.EnumType woodType = getBiomeWoodVariant(biome); + + final Set blocksPlaced = new HashSet<>(); + + ITemplateProcessor processor = new MultiTemplateProcessor(true, + // Roof colour + (w, p, i) -> i.blockState.getBlock() instanceof BlockStainedHardenedClay ? new Template.BlockInfo( + i.pos, i.blockState.withProperty(BlockStainedHardenedClay.COLOR, colour), i.tileentityData) : i, + // Wall material + (w, p, i) -> i.blockState.getBlock() == Blocks.COBBLESTONE ? new Template.BlockInfo(i.pos, + wallMaterial, i.tileentityData) : i, + // Wood type + new WoodTypeTemplateProcessor(woodType), + // Mossifier + new MossifierTemplateProcessor(mossiness, 0.04f, origin.getY() + 1), + // Block recording (the process() method doesn't get called for structure voids) + (w, p, i) -> {if(i.blockState.getBlock() != Blocks.AIR) blocksPlaced.add(p); return i;} + ); + + template.addBlocksToWorld(world, origin, processor, settings, 2); + + WizardryAntiqueAtlasIntegration.markTower(world, origin.getX(), origin.getZ()); + + // Wizard spawning + Map dataBlocks = template.getDataBlocks(origin, settings); + + for(Map.Entry entry : dataBlocks.entrySet()){ + + Vec3d vec = WizardryUtilities.getCentre(entry.getKey()); + + if(entry.getValue().equals(WIZARD_DATA_BLOCK_TAG)){ + + EntityWizard wizard = new EntityWizard(world); + wizard.setLocationAndAngles(vec.x, vec.y, vec.z, 0, 0); + wizard.onInitialSpawn(world.getDifficultyForLocation(origin), null); + wizard.setTowerBlocks(blocksPlaced); + world.spawnEntity(wizard); + + }else if(entry.getValue().equals(EVIL_WIZARD_DATA_BLOCK_TAG)){ + + EntityEvilWizard wizard = new EntityEvilWizard(world); + wizard.setLocationAndAngles(vec.x, vec.y, vec.z, 0, 0); + wizard.hasStructure = true; // Stops it despawning + wizard.onInitialSpawn(world.getDifficultyForLocation(origin), null); + world.spawnEntity(wizard); + + }else{ + // This probably shouldn't happen... + Wizardry.logger.info("Unrecognised data block value {} in structure {}", entry.getValue(), structureFile); + } + } + } + + private static float getBiomeMossiness(Biome biome){ + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.DENSE)) return 0.7f; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.JUNGLE)) return 0.7f; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.WET)) return 0.5f; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.SWAMP)) return 0.5f; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.FOREST)) return 0.3f; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.LUSH)) return 0.3f; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.DRY)) return 0; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.COLD)) return 0; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.DEAD)) return 0; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.WASTELAND)) return 0; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.NETHER)) return 0; + return 0.1f; // Everything else (plains, etc.) has a small amount of moss + } + + private static BlockPlanks.EnumType getBiomeWoodVariant(Biome biome){ + // Unfortunately, I can't check all the wood types with the biome dictionary + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.CONIFEROUS)) return BlockPlanks.EnumType.SPRUCE; + if(biome == Biomes.BIRCH_FOREST || biome == Biomes.BIRCH_FOREST_HILLS) return BlockPlanks.EnumType.BIRCH; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.JUNGLE)) return BlockPlanks.EnumType.JUNGLE; + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.SAVANNA)) return BlockPlanks.EnumType.ACACIA; + // Not technically a tree type, but I think it fits quite well anyway + if(BiomeDictionary.hasType(biome, BiomeDictionary.Type.SPOOKY)) return BlockPlanks.EnumType.DARK_OAK; + // Everything else is oak + return BlockPlanks.EnumType.OAK; + } + +} diff --git a/src/main/resources/assets/ebwizardry/advancements/advanced.json b/src/main/resources/assets/ebwizardry/advancements/advanced.json new file mode 100644 index 00000000..7bc58eb8 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/advanced.json @@ -0,0 +1,108 @@ +{ + "display": { + "icon": { + "item": "ebwizardry:advanced_wand" + }, + "title": { + "translate": "advancement.ebwizardry:advanced" + }, + "description": { + "translate": "advancement.ebwizardry:advanced.desc" + } + }, + "parent": "ebwizardry:apprentice", + "criteria": { + "magic": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:advanced_wand" + } + ] + } + }, + "fire": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:advanced_fire_wand" + } + ] + } + }, + "ice": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:advanced_ice_wand" + } + ] + } + }, + "lightning": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:advanced_lightning_wand" + } + ] + } + }, + "necromancy": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:advanced_necromancy_wand" + } + ] + } + }, + "earth": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:advanced_earth_wand" + } + ] + } + }, + "sorcery": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:advanced_sorcery_wand" + } + ] + } + }, + "healing": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:advanced_healing_wand" + } + ] + } + } + }, + "requirements": [ + [ + "magic", + "fire", + "ice", + "lightning", + "necromancy", + "earth", + "sorcery", + "healing" + ] + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/all_artefacts.json b/src/main/resources/assets/ebwizardry/advancements/all_artefacts.json new file mode 100644 index 00000000..1ad658b9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/all_artefacts.json @@ -0,0 +1,647 @@ +{ + "display": { + "title": { + "translate": "advancement.ebwizardry:all_artefacts" + }, + "description": { + "translate": "advancement.ebwizardry:all_artefacts.desc" + }, + "icon": { + "item": "ebwizardry:amulet_resurrection" + }, + "frame": "challenge" + }, + "parent": "ebwizardry:artefact", + "criteria": { + "ring_condensing": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_condensing" + } + ] + } + }, + "ring_siphoning": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_siphoning" + } + ] + } + }, + "ring_battlemage": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_battlemage" + } + ] + } + }, + "ring_combustion": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_combustion" + } + ] + } + }, + "ring_fire_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_fire_melee" + } + ] + } + }, + "ring_fire_biome": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_fire_biome" + } + ] + } + }, + "ring_disintegration": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_disintegration" + } + ] + } + }, + "ring_ice_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_ice_melee" + } + ] + } + }, + "ring_ice_biome": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_ice_biome" + } + ] + } + }, + "ring_arcane_frost": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_arcane_frost" + } + ] + } + }, + "ring_shattering": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_shattering" + } + ] + } + }, + "ring_lightning_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_lightning_melee" + } + ] + } + }, + "ring_storm": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_storm" + } + ] + } + }, + "ring_seeking": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_seeking" + } + ] + } + }, + "ring_hammer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_hammer" + } + ] + } + }, + "ring_soulbinding": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_soulbinding" + } + ] + } + }, + "ring_leeching": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_leeching" + } + ] + } + }, + "ring_necromancy_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_necromancy_melee" + } + ] + } + }, + "ring_mind_control": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_mind_control" + } + ] + } + }, + "ring_poison": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_poison" + } + ] + } + }, + "ring_earth_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_earth_melee" + } + ] + } + }, + "ring_earth_biome": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_earth_biome" + } + ] + } + }, + "ring_full_moon": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_full_moon" + } + ] + } + }, + "ring_extraction": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_extraction" + } + ] + } + }, + "ring_mana_return": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_mana_return" + } + ] + } + }, + "ring_blockwrangler": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_blockwrangler" + } + ] + } + }, + "ring_conjurer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_conjurer" + } + ] + } + }, + "ring_defender": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_defender" + } + ] + } + }, + "ring_paladin": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_paladin" + } + ] + } + }, + "ring_interdiction": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_interdiction" + } + ] + } + }, + "amulet_arcane_defence": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_arcane_defence" + } + ] + } + }, + "amulet_warding": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_warding" + } + ] + } + }, + "amulet_wisdom": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_wisdom" + } + ] + } + }, + "amulet_fire_protection": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_fire_protection" + } + ] + } + }, + "amulet_fire_cloaking": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_fire_cloaking" + } + ] + } + }, + "amulet_ice_immunity": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_ice_immunity" + } + ] + } + }, + "amulet_ice_protection": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_ice_protection" + } + ] + } + }, + "amulet_potential": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_potential" + } + ] + } + }, + "amulet_channeling": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_channeling" + } + ] + } + }, + "amulet_lich": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_lich" + } + ] + } + }, + "amulet_wither_immunity": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_wither_immunity" + } + ] + } + }, + "amulet_glide": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_glide" + } + ] + } + }, + "amulet_banishing": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_banishing" + } + ] + } + }, + "amulet_anchoring": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_anchoring" + } + ] + } + }, + "amulet_recovery": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_recovery" + } + ] + } + }, + "amulet_transience": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_transience" + } + ] + } + }, + "amulet_resurrection": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_resurrection" + } + ] + } + }, + "amulet_auto_shield": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_auto_shield" + } + ] + } + }, + "charm_haggler": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_haggler" + } + ] + } + }, + "charm_experience_tome": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_experience_tome" + } + ] + } + }, + "charm_auto_smelt": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_auto_smelt" + } + ] + } + }, + "charm_lava_walking": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_lava_walking" + } + ] + } + }, + "charm_storm": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_storm" + } + ] + } + }, + "charm_minion_health": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_minion_health" + } + ] + } + }, + "charm_minion_variants": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_minion_variants" + } + ] + } + }, + "charm_flight": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_flight" + } + ] + } + }, + "charm_growth": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_growth" + } + ] + } + }, + "charm_abseiling": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_abseiling" + } + ] + } + }, + "charm_silk_touch": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_silk_touch" + } + ] + } + }, + "charm_stop_time": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_stop_time" + } + ] + } + }, + "charm_light": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_light" + } + ] + } + }, + "charm_transportation": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_transportation" + } + ] + } + }, + "charm_feeding": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_feeding" + } + ] + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/all_spells.json b/src/main/resources/assets/ebwizardry/advancements/all_spells.json index ce7c75c1..16a35949 100644 --- a/src/main/resources/assets/ebwizardry/advancements/all_spells.json +++ b/src/main/resources/assets/ebwizardry/advancements/all_spells.json @@ -1,20 +1,1393 @@ { "display": { "icon": { - "item": "ebwizardry:wizard_handbook" + "item": "ebwizardry:spell_book" }, "title": { - "translate": "advancement.wizardry:all_spells" + "translate": "advancement.ebwizardry:all_spells" }, "description": { - "translate": "advancement.wizardry:all_spells.desc" + "translate": "advancement.ebwizardry:all_spells.desc" }, - "frame": "challenge" + "frame": "challenge" }, "parent": "ebwizardry:master", "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_all_spells" + "agility": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "agility" + } + } + }, + "arc": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "arc" + } + } + }, + "arcane_jammer": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "arcane_jammer" + } + } + }, + "arcane_lock": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "arcane_lock" + } + } + }, + "arrow_rain": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "arrow_rain" + } + } + }, + "banish": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "banish" + } + } + }, + "black_hole": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "black_hole" + } + } + }, + "blink": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "blink" + } + } + }, + "blizzard": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "blizzard" + } + } + }, + "bubble": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "bubble" + } + } + }, + "chain_lightning": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "chain_lightning" + } + } + }, + "charge": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "charge" + } + } + }, + "clairvoyance": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "clairvoyance" + } + } + }, + "cobwebs": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "cobwebs" + } + } + }, + "combustion_rune": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "combustion_rune" + } + } + }, + "conjure_armour": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "conjure_armour" + } + } + }, + "conjure_block": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "conjure_block" + } + } + }, + "conjure_bow": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "conjure_bow" + } + } + }, + "conjure_pickaxe": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "conjure_pickaxe" + } + } + }, + "conjure_sword": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "conjure_sword" + } + } + }, + "containment": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "containment" + } + } + }, + "cure_effects": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "cure_effects" + } + } + }, + "curse_of_enfeeblement": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "curse_of_enfeeblement" + } + } + }, + "curse_of_soulbinding": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "curse_of_soulbinding" + } + } + }, + "curse_of_undeath": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "curse_of_undeath" + } + } + }, + "darkness_orb": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "darkness_orb" + } + } + }, + "darkvision": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "darkvision" + } + } + }, + "dart": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "dart" + } + } + }, + "decay": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "decay" + } + } + }, + "decoy": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "decoy" + } + } + }, + "detonate": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "detonate" + } + } + }, + "diamondflesh": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "diamondflesh" + } + } + }, + "disintegration": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "disintegration" + } + } + }, + "divination": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "divination" + } + } + }, + "dragon_fireball": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "dragon_fireball" + } + } + }, + "earthquake": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "earthquake" + } + } + }, + "empowering_presence": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "empowering_presence" + } + } + }, + "entrapment": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "entrapment" + } + } + }, + "evade": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "evade" + } + } + }, + "fireball": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "fireball" + } + } + }, + "firebolt": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "firebolt" + } + } + }, + "firebomb": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "firebomb" + } + } + }, + "fire_resistance": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "fire_resistance" + } + } + }, + "fire_sigil": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "fire_sigil" + } + } + }, + "fireskin": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "fireskin" + } + } + }, + "fire_breath": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "fire_breath" + } + } + }, + "flame_ray": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "flame_ray" + } + } + }, + "flaming_axe": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "flaming_axe" + } + } + }, + "flaming_weapon": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "flaming_weapon" + } + } + }, + "flight": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "flight" + } + } + }, + "font_of_mana": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "font_of_mana" + } + } + }, + "font_of_vitality": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "font_of_vitality" + } + } + }, + "force_arrow": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "force_arrow" + } + } + }, + "forcefield": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "forcefield" + } + } + }, + "force_orb": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "force_orb" + } + } + }, + "forests_curse": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "forests_curse" + } + } + }, + "forest_of_thorns": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "forest_of_thorns" + } + } + }, + "freeze": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "freeze" + } + } + }, + "freezing_weapon": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "freezing_weapon" + } + } + }, + "frost_axe": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "frost_axe" + } + } + }, + "frost_ray": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "frost_ray" + } + } + }, + "frost_sigil": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "frost_sigil" + } + } + }, + "frost_step": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "frost_step" + } + } + }, + "glide": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "glide" + } + } + }, + "grapple": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "grapple" + } + } + }, + "greater_fireball": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "greater_fireball" + } + } + }, + "greater_heal": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "greater_heal" + } + } + }, + "greater_telekinesis": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "greater_telekinesis" + } + } + }, + "greater_ward": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "greater_ward" + } + } + }, + "group_heal": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "group_heal" + } + } + }, + "growth_aura": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "growth_aura" + } + } + }, + "hailstorm": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "hailstorm" + } + } + }, + "heal": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "heal" + } + } + }, + "heal_ally": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "heal_ally" + } + } + }, + "healing_aura": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "healing_aura" + } + } + }, + "homing_spark": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "homing_spark" + } + } + }, + "iceball": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "iceball" + } + } + }, + "ice_age": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ice_age" + } + } + }, + "ice_charge": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ice_charge" + } + } + }, + "ice_lance": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ice_lance" + } + } + }, + "ice_shard": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ice_shard" + } + } + }, + "ice_shroud": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ice_shroud" + } + } + }, + "ice_spikes": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ice_spikes" + } + } + }, + "ice_statue": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ice_statue" + } + } + }, + "ignite": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ignite" + } + } + }, + "imbue_weapon": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "imbue_weapon" + } + } + }, + "intimidate": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "intimidate" + } + } + }, + "invigorating_presence": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "invigorating_presence" + } + } + }, + "invisibility": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "invisibility" + } + } + }, + "invoke_weather": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "invoke_weather" + } + } + }, + "ironflesh": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ironflesh" + } + } + }, + "leap": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "leap" + } + } + }, + "levitation": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "levitation" + } + } + }, + "life_drain": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "life_drain" + } + } + }, + "light": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "light" + } + } + }, + "lightning_arrow": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "lightning_arrow" + } + } + }, + "lightning_bolt": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "lightning_bolt" + } + } + }, + "lightning_disc": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "lightning_disc" + } + } + }, + "lightning_hammer": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "lightning_hammer" + } + } + }, + "lightning_pulse": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "lightning_pulse" + } + } + }, + "lightning_ray": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "lightning_ray" + } + } + }, + "lightning_sigil": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "lightning_sigil" + } + } + }, + "lightning_web": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "lightning_web" + } + } + }, + "magic_missile": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "magic_missile" + } + } + }, + "metamorphosis": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "metamorphosis" + } + } + }, + "meteor": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "meteor" + } + } + }, + "mind_control": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "mind_control" + } + } + }, + "mind_trick": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "mind_trick" + } + } + }, + "mine": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "mine" + } + } + }, + "muffle": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "muffle" + } + } + }, + "oakflesh": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "oakflesh" + } + } + }, + "paralysis": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "paralysis" + } + } + }, + "petrify": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "petrify" + } + } + }, + "phase_step": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "phase_step" + } + } + }, + "plague_of_darkness": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "plague_of_darkness" + } + } + }, + "pocket_furnace": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "pocket_furnace" + } + } + }, + "pocket_workbench": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "pocket_workbench" + } + } + }, + "poison": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "poison" + } + } + }, + "poison_bomb": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "poison_bomb" + } + } + }, + "possession": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "possession" + } + } + }, + "ray_of_purification": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ray_of_purification" + } + } + }, + "remove_curse": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "remove_curse" + } + } + }, + "replenish_hunger": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "replenish_hunger" + } + } + }, + "resurrection": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "resurrection" + } + } + }, + "reversal": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "reversal" + } + } + }, + "ring_of_fire": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ring_of_fire" + } + } + }, + "satiety": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "satiety" + } + } + }, + "shadow_ward": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "shadow_ward" + } + } + }, + "shield": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "shield" + } + } + }, + "shockwave": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "shockwave" + } + } + }, + "shulker_bullet": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "shulker_bullet" + } + } + }, + "silverfish_swarm": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "silverfish_swarm" + } + } + }, + "sixth_sense": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "sixth_sense" + } + } + }, + "slime": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "slime" + } + } + }, + "slow_time": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "slow_time" + } + } + }, + "smoke_bomb": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "smoke_bomb" + } + } + }, + "snare": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "snare" + } + } + }, + "snowball": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "snowball" + } + } + }, + "spark_bomb": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "spark_bomb" + } + } + }, + "spectral_pathway": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "spectral_pathway" + } + } + }, + "speed_time": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "speed_time" + } + } + }, + "spider_swarm": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "spider_swarm" + } + } + }, + "static_aura": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "static_aura" + } + } + }, + "summon_blaze": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_blaze" + } + } + }, + "summon_ice_giant": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_ice_giant" + } + } + }, + "summon_ice_wraith": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_ice_wraith" + } + } + }, + "summon_iron_golem": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_iron_golem" + } + } + }, + "summon_lightning_wraith": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_lightning_wraith" + } + } + }, + "summon_phoenix": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_phoenix" + } + } + }, + "summon_shadow_wraith": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_shadow_wraith" + } + } + }, + "summon_skeleton": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_skeleton" + } + } + }, + "summon_skeleton_legion": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_skeleton_legion" + } + } + }, + "summon_snow_golem": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_snow_golem" + } + } + }, + "summon_spirit_horse": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_spirit_horse" + } + } + }, + "summon_spirit_wolf": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_spirit_wolf" + } + } + }, + "summon_storm_elemental": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_storm_elemental" + } + } + }, + "summon_wither_skeleton": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_wither_skeleton" + } + } + }, + "summon_zombie": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_zombie" + } + } + }, + "telekinesis": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "telekinesis" + } + } + }, + "thunderbolt": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "thunderbolt" + } + } + }, + "thunderstorm": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "thunderstorm" + } + } + }, + "tornado": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "tornado" + } + } + }, + "transience": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "transience" + } + } + }, + "transportation": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "transportation" + } + } + }, + "vanishing_box": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "vanishing_box" + } + } + }, + "vex_swarm": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "vex_swarm" + } + } + }, + "wall_of_frost": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "wall_of_frost" + } + } + }, + "ward": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "ward" + } + } + }, + "water_breathing": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "water_breathing" + } + } + }, + "whirlwind": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "whirlwind" + } + } + }, + "wither": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "wither" + } + } + }, + "wither_skull": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "wither_skull" + } + } } } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/anger_wizard.json b/src/main/resources/assets/ebwizardry/advancements/anger_wizard.json index ea1b5070..b9d5dee3 100644 --- a/src/main/resources/assets/ebwizardry/advancements/anger_wizard.json +++ b/src/main/resources/assets/ebwizardry/advancements/anger_wizard.json @@ -4,10 +4,10 @@ "item": "minecraft:iron_sword" }, "title": { - "translate": "advancement.wizardry:anger_wizard" + "translate": "advancement.ebwizardry:anger_wizard" }, "description": { - "translate": "advancement.wizardry:anger_wizard.desc" + "translate": "advancement.ebwizardry:anger_wizard.desc" } }, "parent": "ebwizardry:wizard_trade", diff --git a/src/main/resources/assets/ebwizardry/advancements/apprentice.json b/src/main/resources/assets/ebwizardry/advancements/apprentice.json index 493f7963..12596e68 100644 --- a/src/main/resources/assets/ebwizardry/advancements/apprentice.json +++ b/src/main/resources/assets/ebwizardry/advancements/apprentice.json @@ -4,16 +4,105 @@ "item": "ebwizardry:apprentice_wand" }, "title": { - "translate": "advancement.wizardry:apprentice" + "translate": "advancement.ebwizardry:apprentice" }, "description": { - "translate": "advancement.wizardry:apprentice.desc" + "translate": "advancement.ebwizardry:apprentice.desc" } }, "parent": "ebwizardry:arcane_initiate", "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_apprentice" + "magic": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:apprentice_wand" + } + ] + } + }, + "fire": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:apprentice_fire_wand" + } + ] + } + }, + "ice": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:apprentice_ice_wand" + } + ] + } + }, + "lightning": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:apprentice_lightning_wand" + } + ] + } + }, + "necromancy": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:apprentice_necromancy_wand" + } + ] + } + }, + "earth": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:apprentice_earth_wand" + } + ] + } + }, + "sorcery": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:apprentice_sorcery_wand" + } + ] + } + }, + "healing": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:apprentice_healing_wand" + } + ] + } } - } + }, + "requirements": [ + [ + "magic", + "fire", + "ice", + "lightning", + "necromancy", + "earth", + "sorcery", + "healing" + ] + ] } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/arcane_initiate.json b/src/main/resources/assets/ebwizardry/advancements/arcane_initiate.json index 927f6fe4..6d4bcc33 100644 --- a/src/main/resources/assets/ebwizardry/advancements/arcane_initiate.json +++ b/src/main/resources/assets/ebwizardry/advancements/arcane_initiate.json @@ -1,10 +1,10 @@ { "display": { "title": { - "translate": "advancement.wizardry:arcane_initiate" + "translate": "advancement.ebwizardry:arcane_initiate" }, "description": { - "translate": "advancement.wizardry:arcane_initiate.desc" + "translate": "advancement.ebwizardry:arcane_initiate.desc" }, "icon": { "item": "ebwizardry:magic_wand" diff --git a/src/main/resources/assets/ebwizardry/advancements/armour_set.json b/src/main/resources/assets/ebwizardry/advancements/armour_set.json index 7e36d47c..c69d5c65 100644 --- a/src/main/resources/assets/ebwizardry/advancements/armour_set.json +++ b/src/main/resources/assets/ebwizardry/advancements/armour_set.json @@ -1,10 +1,10 @@ { "display": { "title": { - "translate": "advancement.wizardry:armour_set" + "translate": "advancement.ebwizardry:armour_set" }, "description": { - "translate": "advancement.wizardry:armour_set.desc" + "translate": "advancement.ebwizardry:armour_set.desc" }, "icon": { "item": "ebwizardry:wizard_hat" @@ -12,8 +12,24 @@ }, "parent": "ebwizardry:arcane_initiate", "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_armour_set" + "wizard_hat": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:wizard_hat" + }, + { + "item": "ebwizardry:wizard_robe" + }, + { + "item": "ebwizardry:wizard_leggings" + }, + { + "item": "ebwizardry:wizard_boots" + } + ] + } } } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/artefact.json b/src/main/resources/assets/ebwizardry/advancements/artefact.json new file mode 100644 index 00000000..a5287409 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/artefact.json @@ -0,0 +1,713 @@ +{ + "display": { + "title": { + "translate": "advancement.ebwizardry:artefact" + }, + "description": { + "translate": "advancement.ebwizardry:artefact.desc" + }, + "icon": { + "item": "ebwizardry:ring_condensing" + } + }, + "parent": "ebwizardry:visit_shrine", + "criteria": { + "ring_condensing": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_condensing" + } + ] + } + }, + "ring_siphoning": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_siphoning" + } + ] + } + }, + "ring_battlemage": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_battlemage" + } + ] + } + }, + "ring_combustion": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_combustion" + } + ] + } + }, + "ring_fire_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_fire_melee" + } + ] + } + }, + "ring_fire_biome": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_fire_biome" + } + ] + } + }, + "ring_disintegration": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_disintegration" + } + ] + } + }, + "ring_ice_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_ice_melee" + } + ] + } + }, + "ring_ice_biome": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_ice_biome" + } + ] + } + }, + "ring_arcane_frost": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_arcane_frost" + } + ] + } + }, + "ring_shattering": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_shattering" + } + ] + } + }, + "ring_lightning_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_lightning_melee" + } + ] + } + }, + "ring_storm": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_storm" + } + ] + } + }, + "ring_seeking": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_seeking" + } + ] + } + }, + "ring_hammer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_hammer" + } + ] + } + }, + "ring_soulbinding": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_soulbinding" + } + ] + } + }, + "ring_leeching": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_leeching" + } + ] + } + }, + "ring_necromancy_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_necromancy_melee" + } + ] + } + }, + "ring_mind_control": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_mind_control" + } + ] + } + }, + "ring_poison": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_poison" + } + ] + } + }, + "ring_earth_melee": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_earth_melee" + } + ] + } + }, + "ring_earth_biome": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_earth_biome" + } + ] + } + }, + "ring_full_moon": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_full_moon" + } + ] + } + }, + "ring_extraction": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_extraction" + } + ] + } + }, + "ring_mana_return": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_mana_return" + } + ] + } + }, + "ring_blockwrangler": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_blockwrangler" + } + ] + } + }, + "ring_conjurer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_conjurer" + } + ] + } + }, + "ring_defender": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_defender" + } + ] + } + }, + "ring_paladin": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_paladin" + } + ] + } + }, + "ring_interdiction": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:ring_interdiction" + } + ] + } + }, + "amulet_arcane_defence": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_arcane_defence" + } + ] + } + }, + "amulet_warding": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_warding" + } + ] + } + }, + "amulet_wisdom": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_wisdom" + } + ] + } + }, + "amulet_fire_protection": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_fire_protection" + } + ] + } + }, + "amulet_fire_cloaking": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_fire_cloaking" + } + ] + } + }, + "amulet_ice_immunity": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_ice_immunity" + } + ] + } + }, + "amulet_ice_protection": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_ice_protection" + } + ] + } + }, + "amulet_potential": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_potential" + } + ] + } + }, + "amulet_channeling": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_channeling" + } + ] + } + }, + "amulet_lich": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_lich" + } + ] + } + }, + "amulet_wither_immunity": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_wither_immunity" + } + ] + } + }, + "amulet_glide": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_glide" + } + ] + } + }, + "amulet_banishing": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_banishing" + } + ] + } + }, + "amulet_anchoring": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_anchoring" + } + ] + } + }, + "amulet_recovery": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_recovery" + } + ] + } + }, + "amulet_transience": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_transience" + } + ] + } + }, + "amulet_resurrection": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_resurrection" + } + ] + } + }, + "amulet_auto_shield": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:amulet_auto_shield" + } + ] + } + }, + "charm_haggler": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_haggler" + } + ] + } + }, + "charm_experience_tome": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_experience_tome" + } + ] + } + }, + "charm_auto_smelt": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_auto_smelt" + } + ] + } + }, + "charm_lava_walking": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_lava_walking" + } + ] + } + }, + "charm_storm": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_storm" + } + ] + } + }, + "charm_minion_health": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_minion_health" + } + ] + } + }, + "charm_minion_variants": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_minion_variants" + } + ] + } + }, + "charm_flight": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_flight" + } + ] + } + }, + "charm_growth": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_growth" + } + ] + } + }, + "charm_abseiling": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_abseiling" + } + ] + } + }, + "charm_silk_touch": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_silk_touch" + } + ] + } + }, + "charm_stop_time": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_stop_time" + } + ] + } + }, + "charm_light": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_light" + } + ] + } + }, + "charm_transportation": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_transportation" + } + ] + } + }, + "charm_feeding": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:charm_feeding" + } + ] + } + } + }, + "requirements": [ + [ + "ring_condensing", + "ring_siphoning", + "ring_battlemage", + "ring_combustion", + "ring_fire_melee", + "ring_fire_biome", + "ring_disintegration", + "ring_ice_melee", + "ring_ice_biome", + "ring_arcane_frost", + "ring_shattering", + "ring_lightning_melee", + "ring_storm", + "ring_seeking", + "ring_hammer", + "ring_soulbinding", + "ring_leeching", + "ring_necromancy_melee", + "ring_mind_control", + "ring_poison", + "ring_earth_melee", + "ring_earth_biome", + "ring_full_moon", + "ring_extraction", + "ring_mana_return", + "ring_blockwrangler", + "ring_conjurer", + "ring_defender", + "ring_paladin", + "ring_interdiction", + "amulet_arcane_defence", + "amulet_warding", + "amulet_wisdom", + "amulet_fire_protection", + "amulet_fire_cloaking", + "amulet_ice_immunity", + "amulet_ice_protection", + "amulet_potential", + "amulet_channeling", + "amulet_lich", + "amulet_wither_immunity", + "amulet_glide", + "amulet_banishing", + "amulet_anchoring", + "amulet_recovery", + "amulet_transience", + "amulet_resurrection", + "amulet_auto_shield", + "charm_haggler", + "charm_experience_tome", + "charm_auto_smelt", + "charm_lava_walking", + "charm_storm", + "charm_minion_health", + "charm_minion_variants", + "charm_flight", + "charm_growth", + "charm_abseiling", + "charm_silk_touch", + "charm_stop_time", + "charm_light", + "charm_transportation", + "charm_feeding" + ] + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/buy_master_spell.json b/src/main/resources/assets/ebwizardry/advancements/buy_master_spell.json index 1f00f8b4..3cf455d4 100644 --- a/src/main/resources/assets/ebwizardry/advancements/buy_master_spell.json +++ b/src/main/resources/assets/ebwizardry/advancements/buy_master_spell.json @@ -1,13 +1,13 @@ { "display": { "title": { - "translate": "advancement.wizardry:buy_master_spell" + "translate": "advancement.ebwizardry:buy_master_spell" }, "description": { - "translate": "advancement.wizardry:buy_master_spell.desc" + "translate": "advancement.ebwizardry:buy_master_spell.desc" }, "icon": { - "item": "ebwizardry:spell_book" + "item": "ebwizardry:astral_diamond" }, "frame": "goal" }, diff --git a/src/main/resources/assets/ebwizardry/advancements/charge_creeper.json b/src/main/resources/assets/ebwizardry/advancements/charge_creeper.json deleted file mode 100644 index 8fad22e1..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/charge_creeper.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:charge_creeper" - }, - "description": { - "translate": "advancement.wizardry:charge_creeper.desc" - }, - "icon": { - "item": "minecraft:gunpowder" - } - }, - "parent": "ebwizardry:arcane_initiate", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_charge_creeper" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/craft_flask.json b/src/main/resources/assets/ebwizardry/advancements/craft_flask.json deleted file mode 100644 index 7ae4cba2..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/craft_flask.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:craft_flask" - }, - "description": { - "translate": "advancement.wizardry:craft_flask.desc" - }, - "icon": { - "item": "ebwizardry:mana_flask" - } - }, - "parent": "ebwizardry:arcane_initiate", - "criteria": { - "criteria_0": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "ebwizardry:mana_flask" - } - ] - } - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/crystal.json b/src/main/resources/assets/ebwizardry/advancements/crystal.json index ddbbf5f4..9dcc0773 100644 --- a/src/main/resources/assets/ebwizardry/advancements/crystal.json +++ b/src/main/resources/assets/ebwizardry/advancements/crystal.json @@ -1,13 +1,14 @@ { "display": { "title": { - "translate": "advancement.wizardry:crystal" + "translate": "advancement.ebwizardry:crystal" }, "description": { - "translate": "advancement.wizardry:crystal.desc" + "translate": "advancement.ebwizardry:crystal.desc" }, "icon": { - "item": "ebwizardry:magic_crystal" + "item": "ebwizardry:magic_crystal", + "data": 0 } }, "parent": "ebwizardry:root", @@ -17,7 +18,8 @@ "conditions": { "items": [ { - "item": "ebwizardry:magic_crystal" + "item": "ebwizardry:magic_crystal", + "data": 0 } ] } diff --git a/src/main/resources/assets/ebwizardry/advancements/defeat_evil_wizard.json b/src/main/resources/assets/ebwizardry/advancements/defeat_evil_wizard.json index 7faa2467..810f1074 100644 --- a/src/main/resources/assets/ebwizardry/advancements/defeat_evil_wizard.json +++ b/src/main/resources/assets/ebwizardry/advancements/defeat_evil_wizard.json @@ -1,16 +1,16 @@ { "display": { "title": { - "translate": "advancement.wizardry:defeat_evil_wizard" + "translate": "advancement.ebwizardry:defeat_evil_wizard" }, "description": { - "translate": "advancement.wizardry:defeat_evil_wizard.desc" + "translate": "advancement.ebwizardry:defeat_evil_wizard.desc" }, "icon": { "item": "ebwizardry:wizard_boots_necromancy" } }, - "parent": "ebwizardry:wizard_trade", + "parent": "ebwizardry:arcane_initiate", "criteria": { "criteria_0": { "trigger": "minecraft:player_killed_entity", diff --git a/src/main/resources/assets/ebwizardry/advancements/discover_master_spell.json b/src/main/resources/assets/ebwizardry/advancements/discover_master_spell.json new file mode 100644 index 00000000..35b38fd0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/discover_master_spell.json @@ -0,0 +1,28 @@ +{ + "display": { + "title": { + "translate": "advancement.ebwizardry:discover_master_spell" + }, + "description": { + "translate": "advancement.ebwizardry:discover_master_spell.desc" + }, + "icon": { + "item": "minecraft:blaze_powder" + }, + "frame": "challenge" + }, + "parent": "ebwizardry:spell_failure", + "criteria": { + "criteria_0": { + "trigger": "ebwizardry:discover_spell", + "conditions": { + "spell": { + "tiers": [ + "master" + ] + }, + "source": "casting" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/discover_spell.json b/src/main/resources/assets/ebwizardry/advancements/discover_spell.json new file mode 100644 index 00000000..ba0b2d72 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/discover_spell.json @@ -0,0 +1,22 @@ +{ + "display": { + "title": { + "translate": "advancement.ebwizardry:discover_spell" + }, + "description": { + "translate": "advancement.ebwizardry:discover_spell.desc" + }, + "icon": { + "item": "minecraft:paper" + } + }, + "parent": "ebwizardry:arcane_initiate", + "criteria": { + "criteria_0": { + "trigger": "ebwizardry:discover_spell", + "conditions": { + "source": "casting" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/element_master.json b/src/main/resources/assets/ebwizardry/advancements/element_master.json deleted file mode 100644 index bf8d38f4..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/element_master.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:element_master" - }, - "description": { - "translate": "advancement.wizardry:element_master.desc" - }, - "icon": { - "item": "ebwizardry:master_ice_wand" - }, - "frame": "challenge" - }, - "parent": "ebwizardry:elemental", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_element_master" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/elemental.json b/src/main/resources/assets/ebwizardry/advancements/elemental.json deleted file mode 100644 index 43eb4c16..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/elemental.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:elemental" - }, - "description": { - "translate": "advancement.wizardry:elemental.desc" - }, - "icon": { - "item": "ebwizardry:basic_fire_wand" - } - }, - "parent": "ebwizardry:arcane_initiate", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_elemental" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/enchant_scroll.json b/src/main/resources/assets/ebwizardry/advancements/enchant_scroll.json new file mode 100644 index 00000000..abf5782b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/enchant_scroll.json @@ -0,0 +1,24 @@ +{ + "display": { + "icon": { + "item": "ebwizardry:scroll" + }, + "title": { + "translate": "advancement.ebwizardry:enchant_scroll" + }, + "description": { + "translate": "advancement.ebwizardry:enchant_scroll.desc" + } + }, + "parent": "ebwizardry:arcane_initiate", + "criteria": { + "criteria_0": { + "trigger": "ebwizardry:arcane_workbench", + "conditions": { + "item": { + "item": "ebwizardry:scroll" + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/frankenstein.json b/src/main/resources/assets/ebwizardry/advancements/frankenstein.json deleted file mode 100644 index d197636c..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/frankenstein.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:frankenstein" - }, - "description": { - "translate": "advancement.wizardry:frankenstein.desc" - }, - "icon": { - "item": "ebwizardry:advanced_lightning_wand" - }, - "frame": "challenge" - }, - "parent": "ebwizardry:charge_creeper", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_frankenstein" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/freeze_blaze.json b/src/main/resources/assets/ebwizardry/advancements/freeze_blaze.json deleted file mode 100644 index 595fdabe..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/freeze_blaze.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:freeze_blaze" - }, - "description": { - "translate": "advancement.wizardry:freeze_blaze.desc" - }, - "icon": { - "item": "minecraft:ice" - } - }, - "parent": "ebwizardry:apprentice", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_freeze_blaze" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/arcane_workbench.json b/src/main/resources/assets/ebwizardry/advancements/handbook/arcane_workbench.json new file mode 100644 index 00000000..0822d951 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/arcane_workbench.json @@ -0,0 +1,14 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:arcane_workbench" + } + ] + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/crystal_flowers.json b/src/main/resources/assets/ebwizardry/advancements/handbook/crystal_flowers.json new file mode 100644 index 00000000..b336c1d3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/crystal_flowers.json @@ -0,0 +1,14 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:crystal_flower" + } + ] + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/elements.json b/src/main/resources/assets/ebwizardry/advancements/handbook/elements.json new file mode 100644 index 00000000..de48f0b3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/elements.json @@ -0,0 +1,92 @@ +{ + "criteria": { + "fire": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:magic_crystal", + "data": 1 + } + ] + } + }, + "ice": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:magic_crystal", + "data": 2 + } + ] + } + }, + "lightning": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:magic_crystal", + "data": 3 + } + ] + } + }, + "necromancy": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:magic_crystal", + "data": 4 + } + ] + } + }, + "earth": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:magic_crystal", + "data": 5 + } + ] + } + }, + "sorcery": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:magic_crystal", + "data": 6 + } + ] + } + }, + "healing": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:magic_crystal", + "data": 7 + } + ] + } + } + }, + "requirements": [ + [ + "fire", + "ice", + "lightning", + "necromancy", + "earth", + "sorcery", + "healing" + ] + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/magical_creatures.json b/src/main/resources/assets/ebwizardry/advancements/handbook/magical_creatures.json new file mode 100644 index 00000000..4bcdae10 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/magical_creatures.json @@ -0,0 +1,242 @@ +{ + "criteria": { + "ice_wraith": { + "trigger": "minecraft:player_killed_entity", + "conditions": { + "entity": { + "type": "ebwizardry:ice_wraith" + } + } + }, + "lightning_wraith": { + "trigger": "minecraft:player_killed_entity", + "conditions": { + "entity": { + "type": "ebwizardry:lightning_wraith" + } + } + }, + "spirit_wolf": { + "trigger": "minecraft:player_killed_entity", + "conditions": { + "entity": { + "type": "ebwizardry:spirit_wolf" + } + } + }, + "spirit_horse": { + "trigger": "minecraft:player_killed_entity", + "conditions": { + "entity": { + "type": "ebwizardry:spirit_horse" + } + } + }, + "phoenix": { + "trigger": "minecraft:player_killed_entity", + "conditions": { + "entity": { + "type": "ebwizardry:phoenix" + } + } + }, + "ice_giant": { + "trigger": "minecraft:player_killed_entity", + "conditions": { + "entity": { + "type": "ebwizardry:ice_giant" + } + } + }, + "shadow_wraith": { + "trigger": "minecraft:player_killed_entity", + "conditions": { + "entity": { + "type": "ebwizardry:shadow_wraith" + } + } + }, + "storm_elemental": { + "trigger": "minecraft:player_killed_entity", + "conditions": { + "entity": { + "type": "ebwizardry:storm_elemental" + } + } + }, + "silverfish_swarm": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "silverfish_swarm" + } + } + }, + "spider_swarm": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "spider_swarm" + } + } + }, + "vex_swarm": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "vex_swarm" + } + } + }, + "summon_blaze": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_blaze" + } + } + }, + "summon_ice_giant": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_ice_giant" + } + } + }, + "summon_ice_wraith": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_ice_wraith" + } + } + }, + "summon_iron_golem": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_iron_golem" + } + } + }, + "summon_lightning_wraith": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_lightning_wraith" + } + } + }, + "summon_phoenix": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_phoenix" + } + } + }, + "summon_shadow_wraith": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_shadow_wraith" + } + } + }, + "summon_skeleton": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_skeleton" + } + } + }, + "summon_skeleton_legion": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_skeleton_legion" + } + } + }, + "summon_snow_golem": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_snow_golem" + } + } + }, + "summon_spirit_horse": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_spirit_horse" + } + } + }, + "summon_spirit_wolf": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_spirit_wolf" + } + } + }, + "summon_storm_elemental": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_storm_elemental" + } + } + }, + "summon_wither_skeleton": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_wither_skeleton" + } + } + }, + "summon_zombie": { + "trigger": "ebwizardry:cast_spell", + "conditions": { + "spell": { + "spell": "summon_zombie" + } + } + } + }, + "requirements": [ + [ + "ice_wraith", + "lightning_wraith", + "spirit_wolf", + "spirit_horse", + "phoenix", + "ice_giant", + "shadow_wraith", + "storm_elemental", + "silverfish_swarm", + "spider_swarm", + "vex_swarm", + "summon_blaze", + "summon_ice_giant", + "summon_ice_wraith", + "summon_iron_golem", + "summon_lightning_wraith", + "summon_phoenix", + "summon_shadow_wraith", + "summon_skeleton", + "summon_skeleton_legion", + "summon_snow_golem", + "summon_spirit_horse", + "summon_spirit_wolf", + "summon_storm_elemental", + "summon_wither_skeleton", + "summon_zombie" + ] + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/mana_flasks.json b/src/main/resources/assets/ebwizardry/advancements/handbook/mana_flasks.json new file mode 100644 index 00000000..05c91520 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/mana_flasks.json @@ -0,0 +1,10 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "ebwizardry:medium_mana_flask" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/obelisks.json b/src/main/resources/assets/ebwizardry/advancements/handbook/obelisks.json new file mode 100644 index 00000000..07f802c8 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/obelisks.json @@ -0,0 +1,10 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "ebwizardry:visit_structure", + "conditions": { + "structure_type": "obelisk" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/on_subsection_unlock.json b/src/main/resources/assets/ebwizardry/advancements/handbook/on_subsection_unlock.json new file mode 100644 index 00000000..52e2393c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/on_subsection_unlock.json @@ -0,0 +1,7 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "minecraft:impossible" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/scrolls.json b/src/main/resources/assets/ebwizardry/advancements/handbook/scrolls.json new file mode 100644 index 00000000..22dfe99a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/scrolls.json @@ -0,0 +1,14 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:scroll" + } + ] + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/spells.json b/src/main/resources/assets/ebwizardry/advancements/handbook/spells.json new file mode 100644 index 00000000..1bc8d817 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/spells.json @@ -0,0 +1,14 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:spell_book" + } + ] + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/throwables.json b/src/main/resources/assets/ebwizardry/advancements/handbook/throwables.json new file mode 100644 index 00000000..43b8e1e9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/throwables.json @@ -0,0 +1,14 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:firebomb" + } + ] + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/handbook/tome_of_arcana.json b/src/main/resources/assets/ebwizardry/advancements/handbook/tome_of_arcana.json new file mode 100644 index 00000000..40ee0c46 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/handbook/tome_of_arcana.json @@ -0,0 +1,14 @@ +{ + "criteria": { + "criteria_0": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:arcane_tome" + } + ] + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/identify_spell.json b/src/main/resources/assets/ebwizardry/advancements/identify_spell.json index 3f58890b..b8c1aaae 100644 --- a/src/main/resources/assets/ebwizardry/advancements/identify_spell.json +++ b/src/main/resources/assets/ebwizardry/advancements/identify_spell.json @@ -1,19 +1,22 @@ { "display": { "title": { - "translate": "advancement.wizardry:identify_spell" + "translate": "advancement.ebwizardry:identify_spell" }, "description": { - "translate": "advancement.wizardry:identify_spell.desc" + "translate": "advancement.ebwizardry:identify_spell.desc" }, "icon": { "item": "ebwizardry:identification_scroll" } }, - "parent": "ebwizardry:arcane_initiate", + "parent": "ebwizardry:discover_spell", "criteria": { "criteria_0": { - "trigger": "ebwizardry:trigger_identify_spell" + "trigger": "ebwizardry:discover_spell", + "conditions": { + "source": "identification_scroll" + } } } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/jam_wizard.json b/src/main/resources/assets/ebwizardry/advancements/jam_wizard.json deleted file mode 100644 index f860835e..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/jam_wizard.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:jam_wizard" - }, - "description": { - "translate": "advancement.wizardry:jam_wizard.desc" - }, - "icon": { - "item": "minecraft:web" - } - }, - "parent": "ebwizardry:apprentice", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_jam_wizard" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/legendary.json b/src/main/resources/assets/ebwizardry/advancements/legendary.json index f1473e47..691e7a2b 100644 --- a/src/main/resources/assets/ebwizardry/advancements/legendary.json +++ b/src/main/resources/assets/ebwizardry/advancements/legendary.json @@ -1,10 +1,10 @@ { "display": { "title": { - "translate": "advancement.wizardry:legendary" + "translate": "advancement.ebwizardry:legendary" }, "description": { - "translate": "advancement.wizardry:legendary.desc" + "translate": "advancement.ebwizardry:legendary.desc" }, "icon": { "item": "ebwizardry:armour_upgrade" diff --git a/src/main/resources/assets/ebwizardry/advancements/master.json b/src/main/resources/assets/ebwizardry/advancements/master.json index bd6b24fe..12236cbf 100644 --- a/src/main/resources/assets/ebwizardry/advancements/master.json +++ b/src/main/resources/assets/ebwizardry/advancements/master.json @@ -1,19 +1,108 @@ { "display": { "title": { - "translate": "advancement.wizardry:master" + "translate": "advancement.ebwizardry:master" }, "description": { - "translate": "advancement.wizardry:master.desc" + "translate": "advancement.ebwizardry:master.desc" }, "icon": { "item": "ebwizardry:master_wand" } }, - "parent": "ebwizardry:apprentice", + "parent": "ebwizardry:advanced", "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_master" + "magic": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:master_wand" + } + ] + } + }, + "fire": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:master_fire_wand" + } + ] + } + }, + "ice": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:master_ice_wand" + } + ] + } + }, + "lightning": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:master_lightning_wand" + } + ] + } + }, + "necromancy": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:master_necromancy_wand" + } + ] + } + }, + "earth": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:master_earth_wand" + } + ] + } + }, + "sorcery": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:master_sorcery_wand" + } + ] + } + }, + "healing": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "ebwizardry:master_healing_wand" + } + ] + } } - } + }, + "requirements": [ + [ + "magic", + "fire", + "ice", + "lightning", + "necromancy", + "earth", + "sorcery", + "healing" + ] + ] } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/max_out_wand.json b/src/main/resources/assets/ebwizardry/advancements/max_out_wand.json index 2a779459..7a571967 100644 --- a/src/main/resources/assets/ebwizardry/advancements/max_out_wand.json +++ b/src/main/resources/assets/ebwizardry/advancements/max_out_wand.json @@ -1,17 +1,17 @@ { "display": { "title": { - "translate": "advancement.wizardry:max_out_wand" + "translate": "advancement.ebwizardry:max_out_wand" }, "description": { - "translate": "advancement.wizardry:max_out_wand.desc" + "translate": "advancement.ebwizardry:max_out_wand.desc" }, "icon": { "item": "ebwizardry:arcane_tome" }, "frame": "goal" }, - "parent": "ebwizardry:special_upgrade", + "parent": "ebwizardry:master", "criteria": { "criteria_0": { "trigger": "ebwizardry:trigger_max_out_wand" diff --git a/src/main/resources/assets/ebwizardry/advancements/pig_tornado.json b/src/main/resources/assets/ebwizardry/advancements/pig_tornado.json deleted file mode 100644 index 04770269..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/pig_tornado.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:pig_tornado" - }, - "description": { - "translate": "advancement.wizardry:pig_tornado.desc" - }, - "icon": { - "item": "minecraft:saddle" - }, - "frame": "challenge" - }, - "parent": "ebwizardry:apprentice", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_pig_tornado" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/root.json b/src/main/resources/assets/ebwizardry/advancements/root.json index 63212c97..6c80c1fb 100644 --- a/src/main/resources/assets/ebwizardry/advancements/root.json +++ b/src/main/resources/assets/ebwizardry/advancements/root.json @@ -1,10 +1,10 @@ { "display": { "title": { - "translate": "advancement.wizardry:root" + "translate": "advancement.ebwizardry:root" }, "description": { - "translate": "advancement.wizardry:root.desc" + "translate": "advancement.ebwizardry:root.desc" }, "show_toast": false, "announce_to_chat": false, diff --git a/src/main/resources/assets/ebwizardry/advancements/self_destruct.json b/src/main/resources/assets/ebwizardry/advancements/self_destruct.json deleted file mode 100644 index d0253a73..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/self_destruct.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:self_destruct" - }, - "description": { - "translate": "advancement.wizardry:self_destruct.desc" - }, - "icon": { - "item": "minecraft:pumpkin" - }, - "frame": "challenge" - }, - "parent": "ebwizardry:arcane_initiate", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_self_destruct" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/slime_skeleton.json b/src/main/resources/assets/ebwizardry/advancements/slime_skeleton.json deleted file mode 100644 index 90a982bb..00000000 --- a/src/main/resources/assets/ebwizardry/advancements/slime_skeleton.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "display": { - "title": { - "translate": "advancement.wizardry:slime_skeleton" - }, - "description": { - "translate": "advancement.wizardry:slime_skeleton.desc" - }, - "icon": { - "item": "minecraft:slime_ball" - } - }, - "parent": "ebwizardry:apprentice", - "criteria": { - "criteria_0": { - "trigger": "ebwizardry:trigger_slime_skeleton" - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/special_upgrade.json b/src/main/resources/assets/ebwizardry/advancements/special_upgrade.json index 41b48fd4..324c4973 100644 --- a/src/main/resources/assets/ebwizardry/advancements/special_upgrade.json +++ b/src/main/resources/assets/ebwizardry/advancements/special_upgrade.json @@ -1,16 +1,16 @@ { "display": { "title": { - "translate": "advancement.wizardry:special_upgrade" + "translate": "advancement.ebwizardry:special_upgrade" }, "description": { - "translate": "advancement.wizardry:special_upgrade.desc" + "translate": "advancement.ebwizardry:special_upgrade.desc" }, "icon": { "item": "ebwizardry:condenser_upgrade" } }, - "parent": "ebwizardry:arcane_initiate", + "parent": "ebwizardry:apprentice", "criteria": { "criteria_0": { "trigger": "ebwizardry:trigger_special_upgrade" diff --git a/src/main/resources/assets/ebwizardry/advancements/spell_failure.json b/src/main/resources/assets/ebwizardry/advancements/spell_failure.json new file mode 100644 index 00000000..eed72bdf --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/spell_failure.json @@ -0,0 +1,19 @@ +{ + "display": { + "title": { + "translate": "advancement.ebwizardry:spell_failure" + }, + "description": { + "translate": "advancement.ebwizardry:spell_failure.desc" + }, + "icon": { + "item": "minecraft:pumpkin" + } + }, + "parent": "ebwizardry:discover_spell", + "criteria": { + "criteria_0": { + "trigger": "ebwizardry:trigger_spell_failure" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/visit_shrine.json b/src/main/resources/assets/ebwizardry/advancements/visit_shrine.json new file mode 100644 index 00000000..01060fb9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/visit_shrine.json @@ -0,0 +1,23 @@ +{ + "display": { + "title": { + "translate": "advancement.ebwizardry:visit_shrine" + }, + "description": { + "translate": "advancement.ebwizardry:visit_shrine.desc" + }, + "icon": { + "item": "ebwizardry:runestone", + "data": 5 + } + }, + "parent": "ebwizardry:defeat_evil_wizard", + "criteria": { + "criteria_0": { + "trigger": "ebwizardry:visit_structure", + "conditions": { + "structure_type": "shrine" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/wizard_tower.json b/src/main/resources/assets/ebwizardry/advancements/wizard_tower.json new file mode 100644 index 00000000..2bdd8c0e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/advancements/wizard_tower.json @@ -0,0 +1,22 @@ +{ + "display": { + "title": { + "translate": "advancement.ebwizardry:wizard_tower" + }, + "description": { + "translate": "advancement.ebwizardry:wizard_tower.desc" + }, + "icon": { + "item": "minecraft:bookshelf" + } + }, + "parent": "ebwizardry:arcane_initiate", + "criteria": { + "criteria_0": { + "trigger": "ebwizardry:visit_structure", + "conditions": { + "structure_type": "wizard_tower" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/advancements/wizard_trade.json b/src/main/resources/assets/ebwizardry/advancements/wizard_trade.json index b5e6312d..f86668ab 100644 --- a/src/main/resources/assets/ebwizardry/advancements/wizard_trade.json +++ b/src/main/resources/assets/ebwizardry/advancements/wizard_trade.json @@ -1,16 +1,16 @@ { "display": { "title": { - "translate": "advancement.wizardry:wizard_trade" + "translate": "advancement.ebwizardry:wizard_trade" }, "description": { - "translate": "advancement.wizardry:wizard_trade.desc" + "translate": "advancement.ebwizardry:wizard_trade.desc" }, "icon": { "item": "minecraft:emerald" } }, - "parent": "ebwizardry:arcane_initiate", + "parent": "ebwizardry:wizard_tower", "criteria": { "criteria_0": { "trigger": "ebwizardry:trigger_wizard_trade" diff --git a/src/main/resources/assets/ebwizardry/blockstates/crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/crystal_block.json deleted file mode 100644 index e86e78b6..00000000 --- a/src/main/resources/assets/ebwizardry/blockstates/crystal_block.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "forge_marker": 1, - "variants": { - "normal": { "model": "ebwizardry:crystal_block" } - } -} diff --git a/src/main/resources/assets/ebwizardry/blockstates/dry_frosted_ice.json b/src/main/resources/assets/ebwizardry/blockstates/dry_frosted_ice.json new file mode 100644 index 00000000..6ed17a19 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/dry_frosted_ice.json @@ -0,0 +1,8 @@ +{ + "variants": { + "age=0": { "model": "minecraft:frosted_ice_0" }, + "age=1": { "model": "minecraft:frosted_ice_1" }, + "age=2": { "model": "minecraft:frosted_ice_2" }, + "age=3": { "model": "minecraft:frosted_ice_3" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/earth_crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/earth_crystal_block.json new file mode 100644 index 00000000..b2e41d3a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/earth_crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:earth_crystal_block" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/earth_runestone.json b/src/main/resources/assets/ebwizardry/blockstates/earth_runestone.json new file mode 100644 index 00000000..235ad22c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/earth_runestone.json @@ -0,0 +1,31 @@ +{ + "forge_marker": 1, + "variants": { + "normal": [ + { "model": "ebwizardry:earth_runestone_1", "uvlock": true }, + { "model": "ebwizardry:earth_runestone_1", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:earth_runestone_1", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:earth_runestone_1", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:earth_runestone_1", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:earth_runestone_1", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:earth_runestone_2", "uvlock": true }, + { "model": "ebwizardry:earth_runestone_2", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:earth_runestone_2", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:earth_runestone_2", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:earth_runestone_2", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:earth_runestone_2", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:earth_runestone_3", "uvlock": true }, + { "model": "ebwizardry:earth_runestone_3", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:earth_runestone_3", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:earth_runestone_3", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:earth_runestone_3", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:earth_runestone_3", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:earth_runestone_4", "uvlock": true }, + { "model": "ebwizardry:earth_runestone_4", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:earth_runestone_4", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:earth_runestone_4", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:earth_runestone_4", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:earth_runestone_4", "uvlock": true, "x": 270 } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/earth_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/blockstates/earth_runestone_pedestal.json new file mode 100644 index 00000000..1eda064c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/earth_runestone_pedestal.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:earth_runestone_pedestal" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/fire_crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/fire_crystal_block.json new file mode 100644 index 00000000..05979ee4 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/fire_crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:fire_crystal_block" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/fire_runestone.json b/src/main/resources/assets/ebwizardry/blockstates/fire_runestone.json new file mode 100644 index 00000000..8fbbdbc1 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/fire_runestone.json @@ -0,0 +1,31 @@ +{ + "forge_marker": 1, + "variants": { + "normal": [ + { "model": "ebwizardry:fire_runestone_1", "uvlock": true }, + { "model": "ebwizardry:fire_runestone_1", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:fire_runestone_1", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:fire_runestone_1", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:fire_runestone_1", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:fire_runestone_1", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:fire_runestone_2", "uvlock": true }, + { "model": "ebwizardry:fire_runestone_2", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:fire_runestone_2", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:fire_runestone_2", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:fire_runestone_2", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:fire_runestone_2", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:fire_runestone_3", "uvlock": true }, + { "model": "ebwizardry:fire_runestone_3", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:fire_runestone_3", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:fire_runestone_3", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:fire_runestone_3", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:fire_runestone_3", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:fire_runestone_4", "uvlock": true }, + { "model": "ebwizardry:fire_runestone_4", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:fire_runestone_4", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:fire_runestone_4", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:fire_runestone_4", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:fire_runestone_4", "uvlock": true, "x": 270 } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/fire_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/blockstates/fire_runestone_pedestal.json new file mode 100644 index 00000000..d7a37acc --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/fire_runestone_pedestal.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:fire_runestone_pedestal" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/healing_crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/healing_crystal_block.json new file mode 100644 index 00000000..37b3f3a6 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/healing_crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:healing_crystal_block" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/healing_runestone.json b/src/main/resources/assets/ebwizardry/blockstates/healing_runestone.json new file mode 100644 index 00000000..c2af1a54 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/healing_runestone.json @@ -0,0 +1,31 @@ +{ + "forge_marker": 1, + "variants": { + "normal": [ + { "model": "ebwizardry:healing_runestone_1", "uvlock": true }, + { "model": "ebwizardry:healing_runestone_1", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:healing_runestone_1", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:healing_runestone_1", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:healing_runestone_1", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:healing_runestone_1", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:healing_runestone_2", "uvlock": true }, + { "model": "ebwizardry:healing_runestone_2", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:healing_runestone_2", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:healing_runestone_2", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:healing_runestone_2", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:healing_runestone_2", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:healing_runestone_3", "uvlock": true }, + { "model": "ebwizardry:healing_runestone_3", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:healing_runestone_3", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:healing_runestone_3", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:healing_runestone_3", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:healing_runestone_3", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:healing_runestone_4", "uvlock": true }, + { "model": "ebwizardry:healing_runestone_4", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:healing_runestone_4", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:healing_runestone_4", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:healing_runestone_4", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:healing_runestone_4", "uvlock": true, "x": 270 } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/healing_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/blockstates/healing_runestone_pedestal.json new file mode 100644 index 00000000..c1017a01 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/healing_runestone_pedestal.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:healing_runestone_pedestal" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/ice_crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/ice_crystal_block.json new file mode 100644 index 00000000..711ad5d9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/ice_crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:ice_crystal_block" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/ice_runestone.json b/src/main/resources/assets/ebwizardry/blockstates/ice_runestone.json new file mode 100644 index 00000000..b50a395f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/ice_runestone.json @@ -0,0 +1,31 @@ +{ + "forge_marker": 1, + "variants": { + "normal": [ + { "model": "ebwizardry:ice_runestone_1", "uvlock": true }, + { "model": "ebwizardry:ice_runestone_1", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:ice_runestone_1", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:ice_runestone_1", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:ice_runestone_1", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:ice_runestone_1", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:ice_runestone_2", "uvlock": true }, + { "model": "ebwizardry:ice_runestone_2", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:ice_runestone_2", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:ice_runestone_2", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:ice_runestone_2", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:ice_runestone_2", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:ice_runestone_3", "uvlock": true }, + { "model": "ebwizardry:ice_runestone_3", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:ice_runestone_3", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:ice_runestone_3", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:ice_runestone_3", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:ice_runestone_3", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:ice_runestone_4", "uvlock": true }, + { "model": "ebwizardry:ice_runestone_4", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:ice_runestone_4", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:ice_runestone_4", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:ice_runestone_4", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:ice_runestone_4", "uvlock": true, "x": 270 } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/ice_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/blockstates/ice_runestone_pedestal.json new file mode 100644 index 00000000..d11cb9a1 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/ice_runestone_pedestal.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:ice_runestone_pedestal" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/lightning_crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/lightning_crystal_block.json new file mode 100644 index 00000000..5b8deac4 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/lightning_crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:lightning_crystal_block" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/lightning_runestone.json b/src/main/resources/assets/ebwizardry/blockstates/lightning_runestone.json new file mode 100644 index 00000000..9905b6ef --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/lightning_runestone.json @@ -0,0 +1,31 @@ +{ + "forge_marker": 1, + "variants": { + "normal": [ + { "model": "ebwizardry:lightning_runestone_1", "uvlock": true }, + { "model": "ebwizardry:lightning_runestone_1", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:lightning_runestone_1", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:lightning_runestone_1", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:lightning_runestone_1", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:lightning_runestone_1", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:lightning_runestone_2", "uvlock": true }, + { "model": "ebwizardry:lightning_runestone_2", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:lightning_runestone_2", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:lightning_runestone_2", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:lightning_runestone_2", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:lightning_runestone_2", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:lightning_runestone_3", "uvlock": true }, + { "model": "ebwizardry:lightning_runestone_3", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:lightning_runestone_3", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:lightning_runestone_3", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:lightning_runestone_3", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:lightning_runestone_3", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:lightning_runestone_4", "uvlock": true }, + { "model": "ebwizardry:lightning_runestone_4", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:lightning_runestone_4", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:lightning_runestone_4", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:lightning_runestone_4", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:lightning_runestone_4", "uvlock": true, "x": 270 } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/lightning_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/blockstates/lightning_runestone_pedestal.json new file mode 100644 index 00000000..42616710 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/lightning_runestone_pedestal.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:lightning_runestone_pedestal" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/magic_crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/magic_crystal_block.json new file mode 100644 index 00000000..f3f2353c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/magic_crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:magic_crystal_block" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/necromancy_crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/necromancy_crystal_block.json new file mode 100644 index 00000000..bfe3888a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/necromancy_crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:necromancy_crystal_block" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/necromancy_runestone.json b/src/main/resources/assets/ebwizardry/blockstates/necromancy_runestone.json new file mode 100644 index 00000000..3541a5fd --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/necromancy_runestone.json @@ -0,0 +1,31 @@ +{ + "forge_marker": 1, + "variants": { + "normal": [ + { "model": "ebwizardry:necromancy_runestone_1", "uvlock": true }, + { "model": "ebwizardry:necromancy_runestone_1", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:necromancy_runestone_1", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:necromancy_runestone_1", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:necromancy_runestone_1", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:necromancy_runestone_1", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:necromancy_runestone_2", "uvlock": true }, + { "model": "ebwizardry:necromancy_runestone_2", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:necromancy_runestone_2", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:necromancy_runestone_2", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:necromancy_runestone_2", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:necromancy_runestone_2", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:necromancy_runestone_3", "uvlock": true }, + { "model": "ebwizardry:necromancy_runestone_3", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:necromancy_runestone_3", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:necromancy_runestone_3", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:necromancy_runestone_3", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:necromancy_runestone_3", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:necromancy_runestone_4", "uvlock": true }, + { "model": "ebwizardry:necromancy_runestone_4", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:necromancy_runestone_4", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:necromancy_runestone_4", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:necromancy_runestone_4", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:necromancy_runestone_4", "uvlock": true, "x": 270 } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/necromancy_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/blockstates/necromancy_runestone_pedestal.json new file mode 100644 index 00000000..50c7ce28 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/necromancy_runestone_pedestal.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:necromancy_runestone_pedestal" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/obsidian_crust.json b/src/main/resources/assets/ebwizardry/blockstates/obsidian_crust.json new file mode 100644 index 00000000..1d21f4ff --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/obsidian_crust.json @@ -0,0 +1,8 @@ +{ + "variants": { + "age=0": { "model": "ebwizardry:obsidian_crust_0" }, + "age=1": { "model": "ebwizardry:obsidian_crust_1" }, + "age=2": { "model": "ebwizardry:obsidian_crust_2" }, + "age=3": { "model": "ebwizardry:obsidian_crust_3" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/sorcery_crystal_block.json b/src/main/resources/assets/ebwizardry/blockstates/sorcery_crystal_block.json new file mode 100644 index 00000000..77fbcb9a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/sorcery_crystal_block.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:sorcery_crystal_block" } + } +} diff --git a/src/main/resources/assets/ebwizardry/blockstates/sorcery_runestone.json b/src/main/resources/assets/ebwizardry/blockstates/sorcery_runestone.json new file mode 100644 index 00000000..4e626b9d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/sorcery_runestone.json @@ -0,0 +1,31 @@ +{ + "forge_marker": 1, + "variants": { + "normal": [ + { "model": "ebwizardry:sorcery_runestone_1", "uvlock": true }, + { "model": "ebwizardry:sorcery_runestone_1", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:sorcery_runestone_1", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:sorcery_runestone_1", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:sorcery_runestone_1", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:sorcery_runestone_1", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:sorcery_runestone_2", "uvlock": true }, + { "model": "ebwizardry:sorcery_runestone_2", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:sorcery_runestone_2", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:sorcery_runestone_2", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:sorcery_runestone_2", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:sorcery_runestone_2", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:sorcery_runestone_3", "uvlock": true }, + { "model": "ebwizardry:sorcery_runestone_3", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:sorcery_runestone_3", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:sorcery_runestone_3", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:sorcery_runestone_3", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:sorcery_runestone_3", "uvlock": true, "x": 270 }, + { "model": "ebwizardry:sorcery_runestone_4", "uvlock": true }, + { "model": "ebwizardry:sorcery_runestone_4", "uvlock": true, "y": 90 }, + { "model": "ebwizardry:sorcery_runestone_4", "uvlock": true, "y": 180 }, + { "model": "ebwizardry:sorcery_runestone_4", "uvlock": true, "y": 270 }, + { "model": "ebwizardry:sorcery_runestone_4", "uvlock": true, "x": 90 }, + { "model": "ebwizardry:sorcery_runestone_4", "uvlock": true, "x": 270 } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/sorcery_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/blockstates/sorcery_runestone_pedestal.json new file mode 100644 index 00000000..02e1d413 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/sorcery_runestone_pedestal.json @@ -0,0 +1,6 @@ +{ + "forge_marker": 1, + "variants": { + "normal": { "model": "ebwizardry:sorcery_runestone_pedestal" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/blockstates/thorns.json b/src/main/resources/assets/ebwizardry/blockstates/thorns.json new file mode 100644 index 00000000..c60cd8cb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/blockstates/thorns.json @@ -0,0 +1,20 @@ +{ + "variants": { + "age=0,half=lower": { "model": "ebwizardry:thorns_lower_0" }, + "age=1,half=lower": { "model": "ebwizardry:thorns_lower_1" }, + "age=2,half=lower": { "model": "ebwizardry:thorns_lower_2" }, + "age=3,half=lower": { "model": "ebwizardry:thorns_lower_3" }, + "age=4,half=lower": { "model": "ebwizardry:thorns_lower_4" }, + "age=5,half=lower": { "model": "ebwizardry:thorns_lower_5" }, + "age=6,half=lower": { "model": "ebwizardry:thorns_lower_6" }, + "age=7,half=lower": { "model": "ebwizardry:thorns_lower_7" }, + "age=0,half=upper": { "model": "ebwizardry:thorns_upper_0" }, + "age=1,half=upper": { "model": "ebwizardry:thorns_upper_1" }, + "age=2,half=upper": { "model": "ebwizardry:thorns_upper_2" }, + "age=3,half=upper": { "model": "ebwizardry:thorns_upper_3" }, + "age=4,half=upper": { "model": "ebwizardry:thorns_upper_4" }, + "age=5,half=upper": { "model": "ebwizardry:thorns_upper_5" }, + "age=6,half=upper": { "model": "ebwizardry:thorns_upper_6" }, + "age=7,half=upper": { "model": "ebwizardry:thorns_upper_7" } + } +} diff --git a/src/main/resources/assets/ebwizardry/lang/en_gb.lang b/src/main/resources/assets/ebwizardry/lang/en_gb.lang index 79604949..7e733c22 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_gb.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_gb.lang @@ -1,285 +1,515 @@ -tile.ebwizardry:arcane_workbench.name=Arcane Workbench -tile.ebwizardry:crystal_ore.name=Crystal Ore -tile.ebwizardry:petrified_stone.name=Petrified Stone -tile.ebwizardry:ice_statue.name=Ice Statue -tile.ebwizardry:crystal_flower.name=Crystal Flower -tile.ebwizardry:snare.name=Snare -tile.ebwizardry:transportation_stone.name=Stone of Transportation -tile.ebwizardry:spectral_block.name=Spectral Block -tile.ebwizardry:crystal_block.name=Block of Crystal +#PARSE_ESCAPES +tile.ebwizardry\:arcane_workbench.name=Arcane Workbench +tile.ebwizardry\:crystal_ore.name=Crystal Ore +tile.ebwizardry\:petrified_stone.name=Petrified Stone +tile.ebwizardry\:ice_statue.name=Ice Statue +tile.ebwizardry\:crystal_flower.name=Crystal Flower +tile.ebwizardry\:snare.name=Snare +tile.ebwizardry\:transportation_stone.name=Stone of Transportation +tile.ebwizardry\:transportation_stone.confirm=You will now be returned here upon casting %1$s +tile.ebwizardry\:transportation_stone.remember=Remembered the location %s, %s, %s in dimension %s +tile.ebwizardry\:transportation_stone.forget=Forgot the location %s, %s, %s in dimension %s +tile.ebwizardry\:transportation_stone.invalid=You must make a circle with 8 stones of transportation first! +tile.ebwizardry\:spectral_block.name=Spectral Block +tile.ebwizardry\:runestone.name=Runestone +tile.ebwizardry\:runestone_pedestal.name=Runestone Pedestal +tile.ebwizardry\:thorns.name=Thorns +tile.ebwizardry\:obsidian_crust.name=Obsidian Crust +tile.ebwizardry\:dry_frosted_ice.name=Dry Frosted Ice -item.ebwizardry:magic_crystal.name=Magic Crystal -item.ebwizardry:magic_wand.name=Magic Wand -item.ebwizardry:apprentice_wand.name=Apprentice Wand -item.ebwizardry:advanced_wand.name=Advanced Wand -item.ebwizardry:master_wand.name=Master Wand -item.ebwizardry:spell_book.name=Spell Book +tile.ebwizardry\:magic_crystal_block.name=Block of Crystal +tile.ebwizardry\:fire_crystal_block.name=Block of Fiery Crystal +tile.ebwizardry\:ice_crystal_block.name=Block of Icy Crystal +tile.ebwizardry\:lightning_crystal_block.name=Block of Stormy Crystal +tile.ebwizardry\:necromancy_crystal_block.name=Block of Dark Crystal +tile.ebwizardry\:earth_crystal_block.name=Block of Verdant Crystal +tile.ebwizardry\:sorcery_crystal_block.name=Block of Mystical Crystal +tile.ebwizardry\:healing_crystal_block.name=Block of Radiant Crystal -item.ebwizardry:spell_book.apply_to_wizard=Replaced %1$s's spell %2$s with %3$s +item.ebwizardry\:crystal_magic.name=Magic Crystal +item.ebwizardry\:crystal_fire.name=Fiery Crystal +item.ebwizardry\:crystal_ice.name=Icy Crystal +item.ebwizardry\:crystal_lightning.name=Stormy Crystal +item.ebwizardry\:crystal_necromancy.name=Dark Crystal +item.ebwizardry\:crystal_earth.name=Verdant Crystal +item.ebwizardry\:crystal_sorcery.name=Mystical Crystal +item.ebwizardry\:crystal_healing.name=Radiant Crystal -item.ebwizardry:arcane_tome.name=Tome of Arcana -item.ebwizardry:arcane_tome.desc1=Upgrades any %1$s -item.ebwizardry:arcane_tome.desc2=wand to %1$s tier +item.ebwizardry\:magic_wand.name=Magic Wand +item.ebwizardry\:apprentice_wand.name=Apprentice Wand +item.ebwizardry\:advanced_wand.name=Advanced Wand +item.ebwizardry\:master_wand.name=Master Wand +item.ebwizardry\:spell_book.name=Spell Book -item.ebwizardry:wizard_handbook.name=The Wizard's Handbook -item.ebwizardry:wizard_handbook.desc=by %1$s +item.ebwizardry\:spell_book.apply_to_wizard=Replaced %1$s's spell %2$s with %3$s -item.ebwizardry:wand.buff=+%1$s %2$s potency -item.ebwizardry:wand.spell=Current Spell: %1$s -item.ebwizardry:wand.mana=Mana: %1$s/%2$s +item.ebwizardry\:arcane_tome.name=Tome of Arcana +item.ebwizardry\:arcane_tome.desc1=Upgrades any %1$s +item.ebwizardry\:arcane_tome.desc2=wand to %1$s tier -item.ebwizardry:wand.addally=%1$s has been added to your list of allies -item.ebwizardry:wand.removeally=%1$s has been removed from your list of allies +item.ebwizardry\:wizard_handbook.name=The Wizard's Handbook +item.ebwizardry\:wizard_handbook.desc=by %1$s -item.ebwizardry:basic_fire_wand.name=Wand of Embers -item.ebwizardry:basic_ice_wand.name=Wand of Frost -item.ebwizardry:basic_lightning_wand.name=Wand of Sparks -item.ebwizardry:basic_necromancy_wand.name=Wand of Shadows -item.ebwizardry:basic_earth_wand.name=Wand of the Forest -item.ebwizardry:basic_sorcery_wand.name=Wand of Mystery -item.ebwizardry:basic_healing_wand.name=Wand of Healing +item.ebwizardry\:wand.generic=wand -item.ebwizardry:apprentice_fire_wand.name=Apprentice Pyromancer Wand -item.ebwizardry:apprentice_ice_wand.name=Apprentice Ice Mage Wand -item.ebwizardry:apprentice_lightning_wand.name=Apprentice Storm Mage Wand -item.ebwizardry:apprentice_necromancy_wand.name=Apprentice Necromancer Wand -item.ebwizardry:apprentice_earth_wand.name=Apprentice Earth Mage Wand -item.ebwizardry:apprentice_sorcery_wand.name=Apprentice Sorcerer Wand -item.ebwizardry:apprentice_healing_wand.name=Apprentice Healer Wand +item.ebwizardry\:wand.buff=+%1$s %2$s potency +item.ebwizardry\:wand.spell=Current Spell\: %1$s +item.ebwizardry\:wand.mana=Mana\: %1$s/%2$s +item.ebwizardry\:wand.progression=Progression\: %1$s/%2$s -item.ebwizardry:advanced_fire_wand.name=Wand of the Pyromancer -item.ebwizardry:advanced_ice_wand.name=Wand of the Ice Mage -item.ebwizardry:advanced_lightning_wand.name=Wand of the Storm Mage -item.ebwizardry:advanced_necromancy_wand.name=Wand of the Necromancer -item.ebwizardry:advanced_earth_wand.name=Wand of the Earth Mage -item.ebwizardry:advanced_sorcery_wand.name=Wand of the Sorcerer -item.ebwizardry:advanced_healing_wand.name=Wand of the Healer +item.ebwizardry\:wand.levelup=%1$s is ready to upgrade to %2$s tier -item.ebwizardry:master_fire_wand.name=Master Pyromancer Wand -item.ebwizardry:master_ice_wand.name=Master Ice Mage Wand -item.ebwizardry:master_lightning_wand.name=Master Storm Mage Wand -item.ebwizardry:master_necromancy_wand.name=Master Necromancer Wand -item.ebwizardry:master_earth_wand.name=Master Earth Mage Wand -item.ebwizardry:master_sorcery_wand.name=Master Sorcerer Wand -item.ebwizardry:master_healing_wand.name=Master Healer Wand +item.ebwizardry\:wand.addally=%1$s has been added to your list of allies +item.ebwizardry\:wand.removeally=%1$s has been removed from your list of allies -item.ebwizardry:spectral_sword.name=Spectral Sword -item.ebwizardry:spectral_pickaxe.name=Spectral Pickaxe -item.ebwizardry:spectral_bow.name=Spectral Bow +item.ebwizardry\:novice_fire_wand.name=Wand of Embers +item.ebwizardry\:novice_ice_wand.name=Wand of Frost +item.ebwizardry\:novice_lightning_wand.name=Wand of Sparks +item.ebwizardry\:novice_necromancy_wand.name=Wand of Shadows +item.ebwizardry\:novice_earth_wand.name=Wand of the Forest +item.ebwizardry\:novice_sorcery_wand.name=Wand of Mystery +item.ebwizardry\:novice_healing_wand.name=Wand of Healing -item.ebwizardry:mana_flask.name=Mana Flask -item.ebwizardry:storage_upgrade.name=Wand Storage Upgrade -item.ebwizardry:siphon_upgrade.name=Wand Siphon Upgrade -item.ebwizardry:condenser_upgrade.name=Wand Condenser Upgrade -item.ebwizardry:range_upgrade.name=Wand Range Upgrade -item.ebwizardry:duration_upgrade.name=Wand Duration Upgrade -item.ebwizardry:cooldown_upgrade.name=Wand Cooldown Upgrade -item.ebwizardry:blast_upgrade.name=Wand Blast Upgrade -item.ebwizardry:attunement_upgrade.name=Wand Attunement Upgrade +item.ebwizardry\:apprentice_fire_wand.name=Apprentice Pyromancer Wand +item.ebwizardry\:apprentice_ice_wand.name=Apprentice Ice Mage Wand +item.ebwizardry\:apprentice_lightning_wand.name=Apprentice Storm Mage Wand +item.ebwizardry\:apprentice_necromancy_wand.name=Apprentice Necromancer Wand +item.ebwizardry\:apprentice_earth_wand.name=Apprentice Earth Mage Wand +item.ebwizardry\:apprentice_sorcery_wand.name=Apprentice Sorcerer Wand +item.ebwizardry\:apprentice_healing_wand.name=Apprentice Healer Wand -item.ebwizardry:flaming_axe.name=Flaming Axe -item.ebwizardry:frost_axe.name=Frost Axe +item.ebwizardry\:advanced_fire_wand.name=Wand of the Pyromancer +item.ebwizardry\:advanced_ice_wand.name=Wand of the Ice Mage +item.ebwizardry\:advanced_lightning_wand.name=Wand of the Storm Mage +item.ebwizardry\:advanced_necromancy_wand.name=Wand of the Necromancer +item.ebwizardry\:advanced_earth_wand.name=Wand of the Earth Mage +item.ebwizardry\:advanced_sorcery_wand.name=Wand of the Sorcerer +item.ebwizardry\:advanced_healing_wand.name=Wand of the Healer -item.ebwizardry:firebomb.name=Firebomb -item.ebwizardry:poison_bomb.name=Poison Bomb -item.ebwizardry:smoke_bomb.name=Smoke Bomb +item.ebwizardry\:master_fire_wand.name=Master Pyromancer Wand +item.ebwizardry\:master_ice_wand.name=Master Ice Mage Wand +item.ebwizardry\:master_lightning_wand.name=Master Storm Mage Wand +item.ebwizardry\:master_necromancy_wand.name=Master Necromancer Wand +item.ebwizardry\:master_earth_wand.name=Master Earth Mage Wand +item.ebwizardry\:master_sorcery_wand.name=Master Sorcerer Wand +item.ebwizardry\:master_healing_wand.name=Master Healer Wand -item.ebwizardry:blank_scroll.name=Blank Scroll -item.ebwizardry:scroll.name=Scroll of %1$s -item.ebwizardry:scroll.undiscovered.name=Scroll "%1$s" -item.ebwizardry:identification_scroll.name=Scroll of Identification -item.ebwizardry:identification_scroll.desc1=%1$sIdentifies an unknown -item.ebwizardry:identification_scroll.desc2=%1$sspell book or scroll -item.ebwizardry:identification_scroll.nothing_to_identify=Nothing to identify! +item.ebwizardry\:spectral_sword.name=Spectral Sword +item.ebwizardry\:spectral_pickaxe.name=Spectral Pickaxe +item.ebwizardry\:spectral_bow.name=Spectral Bow -item.ebwizardry:armour_upgrade.name=Arcane Seal of Protection -item.ebwizardry:armour_upgrade.desc1=%1$sUpgrades any wizard armour -item.ebwizardry:armour_upgrade.desc2=%1$sto make it %2$slegendary +item.ebwizardry\:spectral_sword_upgraded.name=Spectral Sword +item.ebwizardry\:spectral_pickaxe_upgraded.name=Spectral Pickaxe -item.ebwizardry:magic_silk.name=Magical Silk +item.ebwizardry\:small_mana_flask.name=Small Mana Flask +item.ebwizardry\:medium_mana_flask.name=Medium Mana Flask +item.ebwizardry\:large_mana_flask.name=Large Mana Flask -item.ebwizardry:wizard_armour.legendary=Legendary -item.ebwizardry:wizard_armour.buff=-%1$s %2$s cost -item.ebwizardry:wizard_armour.mana=Mana: %1$s/%2$s +item.ebwizardry\:grand_crystal.name=Grand Magic Crystal +item.ebwizardry\:crystal_shard.name=Magic Crystal Shard -item.ebwizardry:wizard_hat.name=Wizard Hat -item.ebwizardry:wizard_robe.name=Wizard Robes -item.ebwizardry:wizard_leggings.name=Wizard Leggings -item.ebwizardry:wizard_boots.name=Wizard Boots +item.ebwizardry\:astral_diamond.name=Astral Diamond -item.ebwizardry:wizard_hat_fire.name=Pyromancer Hat -item.ebwizardry:wizard_robe_fire.name=Pyromancer Robes -item.ebwizardry:wizard_leggings_fire.name=Pyromancer Leggings -item.ebwizardry:wizard_boots_fire.name=Pyromancer Boots +item.ebwizardry\:purifying_elixir.name=Purifying Elixir +item.ebwizardry\:purifying_elixir.desc=Removes curses when consumed -item.ebwizardry:wizard_hat_ice.name=Ice Mage Hat -item.ebwizardry:wizard_robe_ice.name=Ice Mage Robes -item.ebwizardry:wizard_leggings_ice.name=Ice Mage Leggings -item.ebwizardry:wizard_boots_ice.name=Ice Mage Boots +item.ebwizardry\:storage_upgrade.name=Wand Storage Upgrade +item.ebwizardry\:siphon_upgrade.name=Wand Siphon Upgrade +item.ebwizardry\:condenser_upgrade.name=Wand Condenser Upgrade +item.ebwizardry\:range_upgrade.name=Wand Range Upgrade +item.ebwizardry\:duration_upgrade.name=Wand Duration Upgrade +item.ebwizardry\:cooldown_upgrade.name=Wand Cooldown Upgrade +item.ebwizardry\:blast_upgrade.name=Wand Blast Upgrade +item.ebwizardry\:attunement_upgrade.name=Wand Attunement Upgrade +item.ebwizardry\:melee_upgrade.name=Wand Melee Upgrade -item.ebwizardry:wizard_hat_lightning.name=Storm Mage Hat -item.ebwizardry:wizard_robe_lightning.name=Storm Mage Robes -item.ebwizardry:wizard_leggings_lightning.name=Storm Mage Leggings -item.ebwizardry:wizard_boots_lightning.name=Storm Mage Boots +item.ebwizardry\:storage_upgrade.desc=Upgrades the mana capacity of a wand +item.ebwizardry\:siphon_upgrade.desc=Upgrades a wand to extract mana from mobs when killed +item.ebwizardry\:condenser_upgrade.desc=Upgrades a wand to slowly regenerate mana over time +item.ebwizardry\:range_upgrade.desc=Upgrades the effective range of spells cast by a wand +item.ebwizardry\:duration_upgrade.desc=Upgrades the duration of effects cast by a wand +item.ebwizardry\:cooldown_upgrade.desc=Upgrades the spell cooldown speed of a wand +item.ebwizardry\:blast_upgrade.desc=Upgrades the area of effect of spells cast by a wand +item.ebwizardry\:attunement_upgrade.desc=Upgrades the number of spells that can be bound to a wand +item.ebwizardry\:melee_upgrade.desc=Upgrades a wand to use mana to deal more damage to mobs when hit -item.ebwizardry:wizard_hat_necromancy.name=Necromancer Hat -item.ebwizardry:wizard_robe_necromancy.name=Necromancer Robes -item.ebwizardry:wizard_leggings_necromancy.name=Necromancer Leggings -item.ebwizardry:wizard_boots_necromancy.name=Necromancer Boots +item.ebwizardry\:flaming_axe.name=Flaming Axe +item.ebwizardry\:frost_axe.name=Frost Axe -item.ebwizardry:wizard_hat_earth.name=Earth Mage Hat -item.ebwizardry:wizard_robe_earth.name=Earth Mage Robes -item.ebwizardry:wizard_leggings_earth.name=Earth Mage Leggings -item.ebwizardry:wizard_boots_earth.name=Earth Mage Boots +item.ebwizardry\:flaming_axe_upgraded.name=Flaming Axe +item.ebwizardry\:frost_axe_upgraded.name=Frost Axe -item.ebwizardry:wizard_hat_sorcery.name=Sorcerer Hat -item.ebwizardry:wizard_robe_sorcery.name=Sorcerer Robes -item.ebwizardry:wizard_leggings_sorcery.name=Sorcerer Leggings -item.ebwizardry:wizard_boots_sorcery.name=Sorcerer Boots +item.ebwizardry\:firebomb.name=Firebomb +item.ebwizardry\:poison_bomb.name=Poison Bomb +item.ebwizardry\:smoke_bomb.name=Smoke Bomb +item.ebwizardry\:spark_bomb.name=Spark Bomb -item.ebwizardry:wizard_hat_healing.name=Healer Hat -item.ebwizardry:wizard_robe_healing.name=Healer Robes -item.ebwizardry:wizard_leggings_healing.name=Healer Leggings -item.ebwizardry:wizard_boots_healing.name=Healer Boots +item.ebwizardry\:blank_scroll.name=Blank Scroll +item.ebwizardry\:scroll.generic=scroll +item.ebwizardry\:scroll.name=Scroll of %1$s +item.ebwizardry\:scroll.undiscovered.name=Scroll "%1$s" +item.ebwizardry\:identification_scroll.name=Scroll of Identification +item.ebwizardry\:identification_scroll.desc=Identifies an unknown spell book or scroll +item.ebwizardry\:identification_scroll.nothing_to_identify=Nothing to identify! -item.ebwizardry:spawn_wizard.name=Spawn Wizard -item.ebwizardry:spawn_evil_wizard.name=Spawn Evil Wizard +item.ebwizardry\:armour_upgrade.name=Arcane Seal of Protection +item.ebwizardry\:armour_upgrade.desc1=%1$sUpgrades any wizard armour +item.ebwizardry\:armour_upgrade.desc2=%1$sto make it %2$slegendary -item.ebwizardry:spectral_helmet.name=Spectral Helmet -item.ebwizardry:spectral_chestplate.name=Spectral Chestplate -item.ebwizardry:spectral_leggings.name=Spectral Leggings -item.ebwizardry:spectral_boots.name=Spectral Boots +item.ebwizardry\:magic_silk.name=Magical Silk -entity.ebwizardry:summonedcreature.nameplate=%1$s's %2$s -entity.ebwizardry:summonedcreature.nameplate_fallback=Someone's %1$s +item.ebwizardry\:wizard_armour.legendary=Legendary +item.ebwizardry\:wizard_armour.buff=-%1$s %2$s cost +item.ebwizardry\:wizard_armour.mana=Mana\: %1$s/%2$s -entity.ebwizardry:zombie_minion.name=Zombie -entity.ebwizardry:skeleton_minion.name=Skeleton -entity.ebwizardry:spider_minion.name=Spider -entity.ebwizardry:blaze_minion.name=Blaze -entity.ebwizardry:wither_skeleton_minion.name=Wither Skeleton -entity.ebwizardry:ice_wraith.name=Ice Wraith -entity.ebwizardry:lightning_wraith.name=Lightning Wraith -entity.ebwizardry:shadow_wraith.name=Shadow Wraith -entity.ebwizardry:spirit_wolf.name=Spirit Wolf -entity.ebwizardry:spirit_horse.name=Spirit Horse -entity.ebwizardry:ice_giant.name=Ice Giant -entity.ebwizardry:phoenix.name=Phoenix -entity.ebwizardry:wizard.name=Wizard -entity.ebwizardry:magic_slime.name=Magical Slime -entity.ebwizardry:silverfish_minion.name=Silverfish -entity.ebwizardry:storm_elemental.name=Storm Elemental -entity.ebwizardry:evil_wizard.name=Wizard -entity.ebwizardry:decoy.name=Decoy +item.ebwizardry\:wizard_hat.name=Wizard Hat +item.ebwizardry\:wizard_robe.name=Wizard Robes +item.ebwizardry\:wizard_leggings.name=Wizard Leggings +item.ebwizardry\:wizard_boots.name=Wizard Boots -entity.ebwizardry:magic_missile.name=Magic -entity.ebwizardry:arc.name=Magic -entity.ebwizardry:spark_bomb.name=Magic -entity.ebwizardry:ice_shard.name=Magic -entity.ebwizardry:firebomb.name=Magic -entity.ebwizardry:poison_bomb.name=Magic -entity.ebwizardry:force_orb.name=Magic -entity.ebwizardry:spark.name=Magic -entity.ebwizardry:darkness_orb.name=Magic -entity.ebwizardry:fire_sigil.name=Magic -entity.ebwizardry:frost_sigil.name=Magic -entity.ebwizardry:lightning_sigil.name=Magic -entity.ebwizardry:lightning_arrow.name=Magic -entity.ebwizardry:firebolt.name=Magic -entity.ebwizardry:ice_charge.name=Magic -entity.ebwizardry:force_arrow.name=Magic -entity.ebwizardry:dart.name=Magic -entity.ebwizardry:lightning_disc.name=Magic -entity.ebwizardry:thunderbolt.name=Magic -entity.ebwizardry:decay.name=Magic -entity.ebwizardry:ice_lance.name=Magic -entity.ebwizardry:smoke_bomb.name=Magic -entity.ebwizardry:ice_spike.name=Magic +item.ebwizardry\:wizard_hat_fire.name=Pyromancer Hat +item.ebwizardry\:wizard_robe_fire.name=Pyromancer Robes +item.ebwizardry\:wizard_leggings_fire.name=Pyromancer Leggings +item.ebwizardry\:wizard_boots_fire.name=Pyromancer Boots -entity.ebwizardry:black_hole.name=Black Hole -entity.ebwizardry:shield.name=Shield -entity.ebwizardry:meteor.name=Meteor -entity.ebwizardry:blizzard.name=Blizzard -entity.ebwizardry:bubble.name=Bubble -entity.ebwizardry:tornado.name=Tornado -entity.ebwizardry:lightning_hammer.name=Lightning Hammer -entity.ebwizardry:arrow_rain.name=Arrow Rain -entity.ebwizardry:healing_aura.name=Healing Aura -entity.ebwizardry:forcefield.name=Forcefield -entity.ebwizardry:ring_of_fire.name=Ring of Fire -entity.ebwizardry:earthquake.name=Earthquake -entity.ebwizardry:falling_grass.name=Falling Grass -entity.ebwizardry:hailstorm.name=Hailstorm -entity.ebwizardry:lightning_pulse.name=Lightning Pulse +item.ebwizardry\:wizard_hat_ice.name=Ice Mage Hat +item.ebwizardry\:wizard_robe_ice.name=Ice Mage Robes +item.ebwizardry\:wizard_leggings_ice.name=Ice Mage Leggings +item.ebwizardry\:wizard_boots_ice.name=Ice Mage Boots -item_group.ebwizardry=Wizardry -item_group.wizardryspells=Spells +item.ebwizardry\:wizard_hat_lightning.name=Storm Mage Hat +item.ebwizardry\:wizard_robe_lightning.name=Storm Mage Robes +item.ebwizardry\:wizard_leggings_lightning.name=Storm Mage Leggings +item.ebwizardry\:wizard_boots_lightning.name=Storm Mage Boots -advancement.wizardry:root=Wizardry -advancement.wizardry:root.desc=A wizard's journey to mastering the arcane -advancement.wizardry:crystal=A Curious Crystal... -advancement.wizardry:crystal.desc=Mine a magic crystal -advancement.wizardry:arcane_initiate=Arcane Initiate -advancement.wizardry:arcane_initiate.desc=Craft a magic wand with a gold nugget, a stick and a magic crystal -advancement.wizardry:apprentice=Wizard's Apprentice -advancement.wizardry:apprentice.desc=Use a tome of arcana to upgrade your wand -advancement.wizardry:master=Arcane Master -advancement.wizardry:master.desc=Obtain a master wand -advancement.wizardry:all_spells=Mage of All Trades -advancement.wizardry:all_spells.desc=Cast every single spell in the game -advancement.wizardry:wizard_trade=Magic Dealing -advancement.wizardry:wizard_trade.desc=Purchase an item from a wizard -advancement.wizardry:buy_master_spell=Knowledge is Power -advancement.wizardry:buy_master_spell.desc=Purchase a master spell from a wizard -advancement.wizardry:freeze_blaze=Not So Hot Now -advancement.wizardry:freeze_blaze.desc=Freeze a blaze solid -advancement.wizardry:charge_creeper=It's Gonna Blow -advancement.wizardry:charge_creeper.desc='Accidentally' charge a creeper -advancement.wizardry:frankenstein=Frankenstein -advancement.wizardry:frankenstein.desc=Turn a pig into a zombie pigman using the lightning bolt spell -advancement.wizardry:special_upgrade=Arcane Tinkering -advancement.wizardry:special_upgrade.desc=Apply a special upgrade to a wand -advancement.wizardry:craft_flask=It's Magic, Bottled! -advancement.wizardry:craft_flask.desc=Craft a mana flask -advancement.wizardry:elemental=Elemental -advancement.wizardry:elemental.desc=Obtain an elemental wand -advancement.wizardry:armour_set=Now You're a Proper Wizard -advancement.wizardry:armour_set.desc=Craft and equip a full set of wizard armour -advancement.wizardry:legendary=Legendary -advancement.wizardry:legendary.desc=Obtain a piece of legendary wizard armour -advancement.wizardry:self_destruct=That Backfired -advancement.wizardry:self_destruct.desc=Get killed by your own magic -advancement.wizardry:pig_tornado=Not Again... -advancement.wizardry:pig_tornado.desc=Ride a pig into a tornado -advancement.wizardry:jam_wizard=Jamming Session -advancement.wizardry:jam_wizard.desc=Use the arcane jammer spell on a wizard -advancement.wizardry:slime_skeleton=Sticky Situation -advancement.wizardry:slime_skeleton.desc=Engulf a skeleton in slime -advancement.wizardry:anger_wizard=You'll Regret That -advancement.wizardry:anger_wizard.desc=Make a wizard angry -advancement.wizardry:defeat_evil_wizard=Righteousness -advancement.wizardry:defeat_evil_wizard.desc=Defeat an evil wizard -advancement.wizardry:max_out_wand=Fully Equipped -advancement.wizardry:max_out_wand.desc=Apply the maximum number of upgrades to a master wand -advancement.wizardry:element_master=Element Mastery -advancement.wizardry:element_master.desc=Cast all the spells of any element -advancement.wizardry:identify_spell=Arcane Appraisal -advancement.wizardry:identify_spell.desc=Use a scroll of identification to identify a spell book or scroll +item.ebwizardry\:wizard_hat_necromancy.name=Necromancer Hat +item.ebwizardry\:wizard_robe_necromancy.name=Necromancer Robes +item.ebwizardry\:wizard_leggings_necromancy.name=Necromancer Leggings +item.ebwizardry\:wizard_boots_necromancy.name=Necromancer Boots -tile.ebwizardry:transportation_stone.confirm=You will now be returned here upon casting %1$s -tile.ebwizardry:transportation_stone.invalid=You must make a circle with 8 stones of transportation first! +item.ebwizardry\:wizard_hat_earth.name=Earth Mage Hat +item.ebwizardry\:wizard_robe_earth.name=Earth Mage Robes +item.ebwizardry\:wizard_leggings_earth.name=Earth Mage Leggings +item.ebwizardry\:wizard_boots_earth.name=Earth Mage Boots -container.ebwizardry:arcane_workbench=Arcane Workbench -container.ebwizardry:arcane_workbench.apply=Apply -container.ebwizardry:arcane_workbench.mana=Mana: -container.ebwizardry:arcane_workbench.upgrades=Applied Upgrades: +item.ebwizardry\:wizard_hat_sorcery.name=Sorcerer Hat +item.ebwizardry\:wizard_robe_sorcery.name=Sorcerer Robes +item.ebwizardry\:wizard_leggings_sorcery.name=Sorcerer Leggings +item.ebwizardry\:wizard_boots_sorcery.name=Sorcerer Boots -tier.basic=Novice +item.ebwizardry\:wizard_hat_healing.name=Healer Hat +item.ebwizardry\:wizard_robe_healing.name=Healer Robes +item.ebwizardry\:wizard_leggings_healing.name=Healer Leggings +item.ebwizardry\:wizard_boots_healing.name=Healer Boots + +item.ebwizardry\:spawn_wizard.name=Spawn Wizard +item.ebwizardry\:spawn_evil_wizard.name=Spawn Evil Wizard + +item.ebwizardry\:spectral_helmet.name=Spectral Helmet +item.ebwizardry\:spectral_chestplate.name=Spectral Chestplate +item.ebwizardry\:spectral_leggings.name=Spectral Leggings +item.ebwizardry\:spectral_boots.name=Spectral Boots + +item.ebwizardry\:lightning_hammer.name=Lightning Hammer + +item.ebwizardry\:ring_condensing.name=Ring of Condensing +item.ebwizardry\:ring_condensing.desc=Slowly regenerates mana for all wands on your hotbar +item.ebwizardry\:ring_siphoning.name=Ring of Siphoning +item.ebwizardry\:ring_siphoning.desc=Increases siphoned mana by 30%% +item.ebwizardry\:ring_battlemage.name=Ring of the Battlemage +item.ebwizardry\:ring_battlemage.desc=Holding a wand in your offhand and a sword in your main hand grants 10%% extra magic damage +item.ebwizardry\:ring_combustion.name=Ring of Combustion +item.ebwizardry\:ring_combustion.desc=Creatures killed by fire spells explode +item.ebwizardry\:ring_fire_melee.name=Ring of Fiery Touch +item.ebwizardry\:ring_fire_melee.desc=Hitting a creature with a fire wand sets it on fire +item.ebwizardry\:ring_fire_biome.name=Ring of the Desert Sun +item.ebwizardry\:ring_fire_biome.desc=Fire spells are 30%% more potent in hot biomes +item.ebwizardry\:ring_disintegration.name=Ring of Searing Embers +item.ebwizardry\:ring_disintegration.desc=All fire attack spells cause their victims to disintegrate +item.ebwizardry\:ring_ice_melee.name=Ring of Icy Touch +item.ebwizardry\:ring_ice_melee.desc=Hitting a creature with an ice wand gives it the frostbite effect +item.ebwizardry\:ring_ice_biome.name=Ring of Glaciation +item.ebwizardry\:ring_ice_biome.desc=Ice spells are 30%% more potent in snowy biomes +item.ebwizardry\:ring_arcane_frost.name=Ring of Arcane Frost +item.ebwizardry\:ring_arcane_frost.desc=Creatures killed by ice spells release ice shards in all directions +item.ebwizardry\:ring_shattering.name=Ring of Shattering +item.ebwizardry\:ring_shattering.desc=Melee attacks on mobs with the frostbite effect have a chance to shatter them into ice shards +item.ebwizardry\:ring_lightning_melee.name=Ring of Chaining +item.ebwizardry\:ring_lightning_melee.desc=Hitting a creature with a lightning wand shoots lightning at another nearby creature +item.ebwizardry\:ring_storm.name=Ring of the Gathering Storm +item.ebwizardry\:ring_storm.desc=During thunderstorms, lightning spells have dramatically reduced cooldowns +item.ebwizardry\:ring_seeking.name=Ring of Attraction +item.ebwizardry\:ring_seeking.desc=All projectile spells seek their targets +item.ebwizardry\:ring_hammer.name=Ring of Thalek the Almighty +item.ebwizardry\:ring_hammer.desc=Lightning hammers can be picked up and thrown +item.ebwizardry\:ring_soulbinding.name=Soulwalker's Ring +item.ebwizardry\:ring_soulbinding.desc=Creatures damaged by necromancy spells become soulbound to you +item.ebwizardry\:ring_leeching.name=Ring of Leeching +item.ebwizardry\:ring_leeching.desc=All necromancy attacks have a 30%% chance to trigger a life drain effect +item.ebwizardry\:ring_necromancy_melee.name=Ring of Necrotic Touch +item.ebwizardry\:ring_necromancy_melee.desc=Hitting a creature with a necromancy wand gives it the wither effect +item.ebwizardry\:ring_mind_control.name=Ring of the Psychic +item.ebwizardry\:ring_mind_control.desc=Mind-controlled creatures have a chance to mind control other nearby creatures +item.ebwizardry\:ring_poison.name=Serpentine Ring +item.ebwizardry\:ring_poison.desc=All earth spells poison their target +item.ebwizardry\:ring_earth_melee.name=Ring of Venomous Touch +item.ebwizardry\:ring_earth_melee.desc=Hitting a creature with an earth wand poisons it +item.ebwizardry\:ring_earth_biome.name=Dryad's Ring +item.ebwizardry\:ring_earth_biome.desc=Earth spells are 30%% more potent in forests and roofed forests +item.ebwizardry\:ring_full_moon.name=Ring of the Howling Wolf +item.ebwizardry\:ring_full_moon.desc=Earth spells have dramatically reduced cooldowns under a full moon +item.ebwizardry\:ring_extraction.name=Ring of Extraction +item.ebwizardry\:ring_extraction.desc=Kills with sorcery spells grant bonus mana +item.ebwizardry\:ring_mana_return.name=Ring of the Perfectionist +item.ebwizardry\:ring_mana_return.desc=Force arrows that miss their target return the mana they used to your wand +item.ebwizardry\:ring_blockwrangler.name=Blockwrangler's Ring +item.ebwizardry\:ring_blockwrangler.desc=Thrown blocks deal twice their normal damage +item.ebwizardry\:ring_conjurer.name=Conjurer's Ring +item.ebwizardry\:ring_conjurer.desc=Conjured items last twice as long +item.ebwizardry\:ring_defender.name=Ring of the Defender +item.ebwizardry\:ring_defender.desc=Your projectiles pass through forcefields belonging to you or an ally +item.ebwizardry\:ring_paladin.name=Paladin's Ring +item.ebwizardry\:ring_paladin.desc=When you heal yourself or an ally, nearby allies will also gain some health +item.ebwizardry\:ring_interdiction.name=Ring of Interdiction +item.ebwizardry\:ring_interdiction.desc=Your forcefield damages creatures that touch it + +item.ebwizardry\:amulet_arcane_defence.name=Amulet of Arcane Defence +item.ebwizardry\:amulet_arcane_defence.desc=Slowly regenerates mana for all worn wizard armour +item.ebwizardry\:amulet_warding.name=Amulet of Warding +item.ebwizardry\:amulet_warding.desc=Reduces all incoming magic damage by 10%% +item.ebwizardry\:amulet_wisdom.name=Amulet of Wisdom +item.ebwizardry\:amulet_wisdom.desc=Greatly reduces the chance of negative effects when using undiscovered spells +item.ebwizardry\:amulet_fire_protection.name=Flamefast Amulet +item.ebwizardry\:amulet_fire_protection.desc=Reduces fire damage by 30%% +item.ebwizardry\:amulet_fire_cloaking.name=Amulet of Cloaking Flame +item.ebwizardry\:amulet_fire_cloaking.desc=Reduces incoming damage by 75%% whilst standing within a ring of fire belonging to you or an ally +item.ebwizardry\:amulet_ice_immunity.name=Permafrost Amulet +item.ebwizardry\:amulet_ice_immunity.desc=Grants total immunity to frostbite effects +item.ebwizardry\:amulet_ice_protection.name=Frostbound Amulet +item.ebwizardry\:amulet_ice_protection.desc=Reduces frost damage by 30%% +item.ebwizardry\:amulet_potential.name=Amulet of Potential +item.ebwizardry\:amulet_potential.desc=Grants a 15%% chance to shoot lightning at creatures that melee attack you +item.ebwizardry\:amulet_channeling.name=Amulet of Channeling +item.ebwizardry\:amulet_channeling.desc=Grants a 30%% chance to negate incoming shock damage +item.ebwizardry\:amulet_lich.name=Amulet of the Lich +item.ebwizardry\:amulet_lich.desc=Grants a 15%% chance for incoming damage to be dealt to a nearby minion instead +item.ebwizardry\:amulet_wither_immunity.name=Wither Pearl Amulet +item.ebwizardry\:amulet_wither_immunity.desc=Grants total immunity to wither effects +item.ebwizardry\:amulet_glide.name=Windfeather Amulet +item.ebwizardry\:amulet_glide.desc=Falling more than 3 blocks has a 50%% chance to activate the glide effect +item.ebwizardry\:amulet_banishing.name=Enderbound Amulet +item.ebwizardry\:amulet_banishing.desc=Creatures that melee attack you have a 15%% chance to be teleported to a random nearby location +item.ebwizardry\:amulet_anchoring.name=Amulet of Anchoring +item.ebwizardry\:amulet_anchoring.desc=Grants immunity to being moved by magic +item.ebwizardry\:amulet_recovery.name=Amulet of Recovery +item.ebwizardry\:amulet_recovery.desc=When on less than 50%% health, mana from your armour will be used to heal you over time +item.ebwizardry\:amulet_transience.name=Amulet of Transience +item.ebwizardry\:amulet_transience.desc=Grants a 25%% chance to activate a transience effect when critically wounded +item.ebwizardry\:amulet_resurrection.name=Amulet of the Immortal +item.ebwizardry\:amulet_resurrection.desc=The resurrection spell can be used on yourself from beyond the grave +item.ebwizardry\:amulet_auto_shield.name=Hyeleth's Amulet +item.ebwizardry\:amulet_auto_shield.desc=Grants a 25%% chance to trigger the shield spell for a few seconds when bound to a wand on your hotbar + +item.ebwizardry\:charm_haggler.name=Haggler's Sign +item.ebwizardry\:charm_haggler.desc=Wizards are guaranteed to offer a new trade every time you trade with them +item.ebwizardry\:charm_experience_tome.name=Tome of the Diligent +item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 40%% +item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark +item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar +item.ebwizardry\:charm_lava_walking.name=Nether Ice Core +item.ebwizardry\:charm_lava_walking.desc=Frost step freezes lava to form an obsidian crust +item.ebwizardry\:charm_storm.name=Bottled Thundercloud +item.ebwizardry\:charm_storm.desc=Invoke weather is guaranteed to summon storms +item.ebwizardry\:charm_minion_health.name=Obsidian Zombie Head +item.ebwizardry\:charm_minion_health.desc=Summoned creatures are 25%% stronger +item.ebwizardry\:charm_minion_variants.name=Talisman of Transformation +item.ebwizardry\:charm_minion_variants.desc=Summoned zombies are husks; summoned skeletons are strays +item.ebwizardry\:charm_flight.name=Emerald Beetle Wing +item.ebwizardry\:charm_flight.desc=Flight and Glide are 50%% faster +item.ebwizardry\:charm_growth.name=Crystal Flower Charm +item.ebwizardry\:charm_growth.desc=Growth aura has a 35%% chance to instantly grow crops to fully-grown +item.ebwizardry\:charm_abseiling.name=Enchanted Twine +item.ebwizardry\:charm_abseiling.desc=Holding sneak whilst grappling slowly pays out the line +item.ebwizardry\:charm_silk_touch.name=Moonstone Orb +item.ebwizardry\:charm_silk_touch.desc=Blocks broken with the mine spell always drop themselves +item.ebwizardry\:charm_stop_time.name=Peculiar Pocketwatch +item.ebwizardry\:charm_stop_time.desc=The slow time spell makes time stand still +item.ebwizardry\:charm_light.name=Elevinia's Everburning Lantern +item.ebwizardry\:charm_light.desc=Conjured light sources last forever and may be dispelled by right-clicking with a wand +item.ebwizardry\:charm_transportation.name=Ancient Compass +item.ebwizardry\:charm_transportation.desc=Up to four stone circles may be remembered and selected from when using transportation +item.ebwizardry\:charm_feeding.name=Bottomless Provisions +item.ebwizardry\:charm_feeding.desc=Replenish hunger triggers automatically when bound to a wand on your hotbar + +item.charge_status.full=Full +item.charge_status.almost_full=Almost full +item.charge_status.mostly_full=Mostly full +item.charge_status.half_full=Half full +item.charge_status.mostly_empty=Mostly empty +item.charge_status.almost_empty=Almost empty +item.charge_status.empty=Empty + +entity.ebwizardry\:summonedcreature.nameplate=%1$s's %2$s +entity.ebwizardry\:summonedcreature.nameplate_fallback=Someone's %1$s + +entity.ebwizardry\:wizard.greeting_0=Good day, fellow wanderer. +entity.ebwizardry\:wizard.greeting_1=Greetings, traveller. What brings you here? +entity.ebwizardry\:wizard.greeting_2=Ah, nice to see another person around here. +entity.ebwizardry\:wizard.speech_0=Might I interest you in any spells, perhaps? +entity.ebwizardry\:wizard.speech_1=Magic is everywhere, if you know where to look. +entity.ebwizardry\:wizard.speech_2=There is still much to be learned about the arcane arts, adventurer. +entity.ebwizardry\:wizard.speech_3=Perhaps you have learned something yourself that you wish to share? +entity.ebwizardry\:wizard.speech_4=Studying the arcane is most fascinating, don't you think? +entity.ebwizardry\:wizard.farewell_0=Good luck in your quest, adventurer. +entity.ebwizardry\:wizard.farewell_1=I trust that we will meet again soon, friend. +entity.ebwizardry\:wizard.farewell_2=Goodbye then, traveller. +entity.ebwizardry\:wizard.combat_0=Be gone, foul creatures! +entity.ebwizardry\:wizard.combat_1=Leave me alone, pests! +entity.ebwizardry\:wizard.combat_2=Undead beings are not welcome here, shoo! +entity.ebwizardry\:wizard.combat_3=Away with you, creatures of darkness! +entity.ebwizardry\:wizard.combat_4=This is all I need! Get out of here, monsters! +entity.ebwizardry\:wizard.combat_5=Return to the caves from whence you came, evil creatures! +entity.ebwizardry\:wizard.player_combat_0=You will regret that decision, traveller! +entity.ebwizardry\:wizard.player_combat_1=What do you think you are doing?! +entity.ebwizardry\:wizard.player_combat_2=Only a fool dares to anger a wizard! +entity.ebwizardry\:wizard.player_combat_3=You will pay for your carelessness, adventurer! +entity.ebwizardry\:wizard.player_combat_4=Be ready to defend yourself, villain! +entity.ebwizardry\:wizard.player_combat_5=Prepare to feel my wrath! + +entity.ebwizardry\:zombie_minion.name=Zombie +entity.ebwizardry\:husk_minion.name=Husk +entity.ebwizardry\:skeleton_minion.name=Skeleton +entity.ebwizardry\:stray_minion.name=Stray +entity.ebwizardry\:spider_minion.name=Spider +entity.ebwizardry\:blaze_minion.name=Blaze +entity.ebwizardry\:wither_skeleton_minion.name=Wither Skeleton +entity.ebwizardry\:ice_wraith.name=Ice Wraith +entity.ebwizardry\:lightning_wraith.name=Lightning Wraith +entity.ebwizardry\:shadow_wraith.name=Shadow Wraith +entity.ebwizardry\:spirit_wolf.name=Spirit Wolf +entity.ebwizardry\:spirit_horse.name=Spirit Horse +entity.ebwizardry\:ice_giant.name=Ice Giant +entity.ebwizardry\:phoenix.name=Phoenix +entity.ebwizardry\:wizard.name=Wizard +entity.ebwizardry\:magic_slime.name=Magical Slime +entity.ebwizardry\:silverfish_minion.name=Silverfish +entity.ebwizardry\:storm_elemental.name=Storm Elemental +entity.ebwizardry\:evil_wizard.name=Wizard +entity.ebwizardry\:decoy.name=Decoy +entity.ebwizardry\:vex_minion.name=Vex + +entity.ebwizardry\:magic_missile.name=Magic +entity.ebwizardry\:arc.name=Magic +entity.ebwizardry\:spark_bomb.name=Magic +entity.ebwizardry\:ice_shard.name=Magic +entity.ebwizardry\:firebomb.name=Magic +entity.ebwizardry\:poison_bomb.name=Magic +entity.ebwizardry\:force_orb.name=Magic +entity.ebwizardry\:spark.name=Magic +entity.ebwizardry\:darkness_orb.name=Magic +entity.ebwizardry\:fire_sigil.name=Magic +entity.ebwizardry\:frost_sigil.name=Magic +entity.ebwizardry\:lightning_sigil.name=Magic +entity.ebwizardry\:lightning_arrow.name=Magic +entity.ebwizardry\:firebolt.name=Magic +entity.ebwizardry\:ice_charge.name=Magic +entity.ebwizardry\:force_arrow.name=Magic +entity.ebwizardry\:dart.name=Magic +entity.ebwizardry\:lightning_disc.name=Magic +entity.ebwizardry\:thunderbolt.name=Magic +entity.ebwizardry\:decay.name=Magic +entity.ebwizardry\:ice_lance.name=Magic +entity.ebwizardry\:smoke_bomb.name=Magic +entity.ebwizardry\:ice_spike.name=Magic +entity.ebwizardry\:combustion_rune.name=Magic + +entity.ebwizardry\:black_hole.name=Black Hole +entity.ebwizardry\:shield.name=Shield +entity.ebwizardry\:meteor.name=Meteor +entity.ebwizardry\:blizzard.name=Blizzard +entity.ebwizardry\:bubble.name=Bubble +entity.ebwizardry\:tornado.name=Tornado +entity.ebwizardry\:lightning_hammer.name=Lightning Hammer +entity.ebwizardry\:arrow_rain.name=Arrow Rain +entity.ebwizardry\:healing_aura.name=Healing Aura +entity.ebwizardry\:forcefield.name=Forcefield +entity.ebwizardry\:ring_of_fire.name=Ring of Fire +entity.ebwizardry\:earthquake.name=Earthquake +entity.ebwizardry\:hailstorm.name=Hailstorm +entity.ebwizardry\:lightning_pulse.name=Lightning Pulse + +itemGroup.ebwizardry=Wizardry +itemGroup.ebwizardryspells=Spells +itemGroup.ebwizardrygear=Wizard Gear + +advancement.ebwizardry\:root=Wizardry +advancement.ebwizardry\:root.desc=A wizard's journey to mastering the arcane +advancement.ebwizardry\:crystal=A Curious Crystal... +advancement.ebwizardry\:crystal.desc=Mine a magic crystal +advancement.ebwizardry\:arcane_initiate=Arcane Initiate +advancement.ebwizardry\:arcane_initiate.desc=Craft a magic wand with a gold nugget, a stick and a magic crystal + +advancement.ebwizardry\:apprentice=Wizard's Apprentice +advancement.ebwizardry\:apprentice.desc=Use a tome of arcana to upgrade your wand +advancement.ebwizardry\:special_upgrade=Arcane Tinkering +advancement.ebwizardry\:special_upgrade.desc=Apply a special upgrade to a wand +advancement.ebwizardry\:advanced=Advancing Rapidly +advancement.ebwizardry\:advanced.desc=Upgrade your wand to advanced tier +advancement.ebwizardry\:master=Arcane Master +advancement.ebwizardry\:master.desc=Obtain a master wand +advancement.ebwizardry\:max_out_wand=Fully Equipped +advancement.ebwizardry\:max_out_wand.desc=Apply the maximum number of upgrades to a master wand +advancement.ebwizardry\:all_spells=Mage of All Trades +advancement.ebwizardry\:all_spells.desc=Cast every single spell in the game + +advancement.ebwizardry\:wizard_tower=Who Lives Here? +advancement.ebwizardry\:wizard_tower.desc=Visit a wizard's tower +advancement.ebwizardry\:wizard_trade=Magic Dealing +advancement.ebwizardry\:wizard_trade.desc=Purchase an item from a wizard +advancement.ebwizardry\:anger_wizard=You'll Regret That +advancement.ebwizardry\:anger_wizard.desc=Make a wizard angry +advancement.ebwizardry\:defeat_evil_wizard=Righteousness +advancement.ebwizardry\:defeat_evil_wizard.desc=Defeat an evil wizard +advancement.ebwizardry\:buy_master_spell=Knowledge is Power +advancement.ebwizardry\:buy_master_spell.desc=Purchase a master spell from a wizard + +advancement.ebwizardry\:discover_spell=Trial And Error +advancement.ebwizardry\:discover_spell.desc=Identify an unknown spell by casting it and seeing what happens +advancement.ebwizardry\:identify_spell=Arcane Appraisal +advancement.ebwizardry\:identify_spell.desc=Find a more reliable way of identifying spells +advancement.ebwizardry\:spell_failure=That Backfired +advancement.ebwizardry\:spell_failure.desc=Find out the hard way how spells can go wrong +advancement.ebwizardry\:discover_master_spell=Dicing With Danger +advancement.ebwizardry\:discover_master_spell.desc=Successfully identify a master spell by trial and error + +advancement.ebwizardry\:visit_shrine=Enshrined +advancement.ebwizardry\:visit_shrine.desc=Enter a shrine and awaken its ancient magic +advancement.ebwizardry\:artefact=A Forgotten Relic +advancement.ebwizardry\:artefact.desc=Lift the protective enchantments from a shrine and claim the treasures within +advancement.ebwizardry\:all_artefacts=A Veritable Museum +advancement.ebwizardry\:all_artefacts.desc=Collect all of the rings, amulets and charms + +advancement.ebwizardry\:armour_set=Now You're a Proper Wizard +advancement.ebwizardry\:armour_set.desc=Craft and equip a full set of wizard armour +advancement.ebwizardry\:legendary=Legendary +advancement.ebwizardry\:legendary.desc=Obtain a piece of legendary wizard armour + +advancement.ebwizardry\:enchant_scroll=Scroll Up! +advancement.ebwizardry\:enchant_scroll.desc=Craft a blank scroll and enchant it with a spell at an arcane workbench + +handbook.toast.title=New Handbook Section Unlocked! + +container.ebwizardry\:arcane_workbench=Arcane Workbench +container.ebwizardry\:arcane_workbench.apply=Apply +container.ebwizardry\:arcane_workbench.mana=Mana\: +container.ebwizardry\:arcane_workbench.upgrades=Applied Upgrades\: + +tier.novice=Novice tier.apprentice=Apprentice tier.advanced=Advanced tier.master=Master -element.simple=None +element.magic=None element.fire=Fire element.ice=Ice element.lightning=Lightning @@ -288,7 +518,7 @@ element.earth=Earth element.sorcery=Sorcery element.healing=Healing -element.simple.wizard=Wizard +element.magic.wizard=Wizard element.fire.wizard=Pyromancer element.ice.wizard=Ice Mage element.lightning.wizard=Storm Mage @@ -301,323 +531,477 @@ spelltype.attack=Attack spelltype.defence=Defence spelltype.utility=Utility spelltype.minion=Minion +spelltype.buff=Buff +spelltype.construct=Construct +spelltype.projectile=Projectile +spelltype.alteration=Alteration spell.disabled=%1$s has been disabled in the config spell.resist=%1$s resisted %2$s spell.discover=Discovered the spell %1$s! -spell.ebwizardry:agility=Agility -spell.ebwizardry:arc=Arc -spell.ebwizardry:arcane_jammer=Arcane Jammer -spell.ebwizardry:arrow_rain=Arrow Rain -spell.ebwizardry:banish=Banish -spell.ebwizardry:black_hole=Black Hole -spell.ebwizardry:blink=Blink -spell.ebwizardry:blizzard=Blizzard -spell.ebwizardry:bubble=Bubble -spell.ebwizardry:chain_lightning=Chain Lightning -spell.ebwizardry:clairvoyance=Clairvoyance -spell.ebwizardry:cobwebs=Cobwebs -spell.ebwizardry:conjure_armour=Conjure Armour -spell.ebwizardry:conjure_bow=Conjure Bow -spell.ebwizardry:conjure_pickaxe=Conjure Pickaxe -spell.ebwizardry:conjure_sword=Conjure Sword -spell.ebwizardry:cure_effects=Cure Effects -spell.ebwizardry:curse_of_soulbinding=Curse of Soulbinding -spell.ebwizardry:darkness_orb=Darkness Orb -spell.ebwizardry:darkvision=Darkvision -spell.ebwizardry:dart=Dart -spell.ebwizardry:decay=Decay -spell.ebwizardry:decoy=Decoy -spell.ebwizardry:detonate=Detonate -spell.ebwizardry:diamondflesh=Diamondflesh -spell.ebwizardry:earthquake=Earthquake -spell.ebwizardry:entrapment=Entrapment -spell.ebwizardry:fireball=Fireball -spell.ebwizardry:firebolt=Firebolt -spell.ebwizardry:firebomb=Firebomb -spell.ebwizardry:fire_resistance=Fire Resistance -spell.ebwizardry:fire_sigil=Fire Sigil -spell.ebwizardry:fireskin=Fireskin -spell.ebwizardry:firestorm=Firestorm -spell.ebwizardry:flame_ray=Flame Ray -spell.ebwizardry:flaming_axe=Flaming Axe -spell.ebwizardry:flaming_weapon=Flaming Weapon -spell.ebwizardry:flight=Flight -spell.ebwizardry:font_of_mana=Font of Mana -spell.ebwizardry:font_of_vitality=Font of Vitality -spell.ebwizardry:force_arrow=Force Arrow -spell.ebwizardry:forcefield=Forcefield -spell.ebwizardry:force_orb=Force Orb -spell.ebwizardry:forests_curse=Forest's Curse -spell.ebwizardry:freeze=Freeze -spell.ebwizardry:freezing_weapon=Freezing Weapon -spell.ebwizardry:frost_axe=Frost Axe -spell.ebwizardry:frost_ray=Frost Ray -spell.ebwizardry:frost_sigil=Frost Sigil -spell.ebwizardry:glide=Glide -spell.ebwizardry:greater_fireball=Greater Fireball -spell.ebwizardry:greater_heal=Greater Heal -spell.ebwizardry:group_heal=Group Heal -spell.ebwizardry:growth_aura=Growth Aura -spell.ebwizardry:hailstorm=Hailstorm -spell.ebwizardry:heal=Heal -spell.ebwizardry:heal_ally=Heal Ally -spell.ebwizardry:healing_aura=Healing Aura -spell.ebwizardry:homing_spark=Homing Spark -spell.ebwizardry:ice_age=Ice Age -spell.ebwizardry:ice_charge=Ice Charge -spell.ebwizardry:ice_lance=Ice Lance -spell.ebwizardry:ice_shard=Ice Shard -spell.ebwizardry:ice_shroud=Ice Shroud -spell.ebwizardry:ice_spikes=Ice Spikes -spell.ebwizardry:ice_statue=Ice Statue -spell.ebwizardry:ignite=Ignite -spell.ebwizardry:imbue_weapon=Imbue Weapon -spell.ebwizardry:intimidate=Intimidate -spell.ebwizardry:invigorating_presence=Invigorating Presence -spell.ebwizardry:invisibility=Invisibility -spell.ebwizardry:invoke_weather=Invoke Weather -spell.ebwizardry:ironflesh=Ironflesh -spell.ebwizardry:leap=Leap -spell.ebwizardry:levitation=Levitation -spell.ebwizardry:life_drain=Life Drain -spell.ebwizardry:light=Light -spell.ebwizardry:lightning_arrow=Lightning Arrow -spell.ebwizardry:lightning_bolt=Lightning Bolt -spell.ebwizardry:lightning_disc=Lightning Disc -spell.ebwizardry:lightning_hammer=Lightning Hammer -spell.ebwizardry:lightning_pulse=Lightning Pulse -spell.ebwizardry:lightning_ray=Lightning Ray -spell.ebwizardry:lightning_sigil=Lightning Sigil -spell.ebwizardry:lightning_web=Lightning Web -spell.ebwizardry:magic_missile=Magic Missile -spell.ebwizardry:metamorphosis=Metamorphosis -spell.ebwizardry:meteor=Meteor -spell.ebwizardry:mind_control=Mind Control -spell.ebwizardry:mind_trick=Mind Trick -spell.ebwizardry:none=[Empty Slot] -spell.ebwizardry:oakflesh=Oakflesh -spell.ebwizardry:petrify=Petrify -spell.ebwizardry:phase_step=Phase Step -spell.ebwizardry:plague_of_darkness=Plague of Darkness -spell.ebwizardry:pocket_furnace=Pocket Furnace -spell.ebwizardry:pocket_workbench=Pocket Workbench -spell.ebwizardry:poison=Poison -spell.ebwizardry:poison_bomb=Poison Bomb -spell.ebwizardry:replenish_hunger=Replenish Hunger -spell.ebwizardry:ring_of_fire=Ring of Fire -spell.ebwizardry:shadow_ward=Shadow Ward -spell.ebwizardry:shield=Shield -spell.ebwizardry:shockwave=Shockwave -spell.ebwizardry:silverfish_swarm=Silverfish Swarm -spell.ebwizardry:sixth_sense=Sixth Sense -spell.ebwizardry:slime=Slime -spell.ebwizardry:smoke_bomb=Smoke Bomb -spell.ebwizardry:snare=Snare -spell.ebwizardry:snowball=Snowball -spell.ebwizardry:spark_bomb=Spark Bomb -spell.ebwizardry:spectral_pathway=Spectral Pathway -spell.ebwizardry:spider_swarm=Spider Swarm -spell.ebwizardry:static_aura=Static Aura -spell.ebwizardry:summon_blaze=Summon Blaze -spell.ebwizardry:summon_ice_giant=Summon Ice Giant -spell.ebwizardry:summon_ice_wraith=Summon Ice Wraith -spell.ebwizardry:summon_iron_golem=Summon Iron Golem -spell.ebwizardry:summon_lightning_wraith=Summon Lightning Wraith -spell.ebwizardry:summon_phoenix=Summon Phoenix -spell.ebwizardry:summon_shadow_wraith=Summon Shadow Wraith -spell.ebwizardry:summon_skeleton=Summon Skeleton -spell.ebwizardry:summon_skeleton_legion=Summon Skeleton Legion -spell.ebwizardry:summon_snow_golem=Summon Snow Golem -spell.ebwizardry:summon_spirit_horse=Summon Spirit Horse -spell.ebwizardry:summon_spirit_wolf=Summon Spirit Wolf -spell.ebwizardry:summon_storm_elemental=Summon Storm Elemental -spell.ebwizardry:summon_wither_skeleton=Summon Wither Skeleton -spell.ebwizardry:summon_zombie=Summon Zombie -spell.ebwizardry:telekinesis=Telekinesis -spell.ebwizardry:thunderbolt=Thunderbolt -spell.ebwizardry:thunderstorm=Thunderstorm -spell.ebwizardry:tornado=Tornado -spell.ebwizardry:transience=Transience -spell.ebwizardry:transportation=Transportation -spell.ebwizardry:vanishing_box=Vanishing Box -spell.ebwizardry:wall_of_frost=Wall of Frost -spell.ebwizardry:water_breathing=Water Breathing -spell.ebwizardry:whirlwind=Whirlwind -spell.ebwizardry:wither=Wither -spell.ebwizardry:wither_skull=Wither Skull +spell.ebwizardry\:agility=Agility +spell.ebwizardry\:arc=Arc +spell.ebwizardry\:arcane_jammer=Arcane Jammer +spell.ebwizardry\:arcane_lock=Arcane Lock +spell.ebwizardry\:arrow_rain=Arrow Rain +spell.ebwizardry\:banish=Banish +spell.ebwizardry\:black_hole=Black Hole +spell.ebwizardry\:blink=Blink +spell.ebwizardry\:blizzard=Blizzard +spell.ebwizardry\:bubble=Bubble +spell.ebwizardry\:chain_lightning=Chain Lightning +spell.ebwizardry\:charge=Charge +spell.ebwizardry\:clairvoyance=Clairvoyance +spell.ebwizardry\:cobwebs=Cobwebs +spell.ebwizardry\:combustion_rune=Combustion Rune +spell.ebwizardry\:conjure_armour=Conjure Armour +spell.ebwizardry\:conjure_block=Conjure Block +spell.ebwizardry\:conjure_bow=Conjure Bow +spell.ebwizardry\:conjure_pickaxe=Conjure Pickaxe +spell.ebwizardry\:conjure_sword=Conjure Sword +spell.ebwizardry\:containment=Containment +spell.ebwizardry\:cure_effects=Cure Effects +spell.ebwizardry\:curse_of_enfeeblement=Curse of Enfeeblement +spell.ebwizardry\:curse_of_soulbinding=Curse of Soulbinding +spell.ebwizardry\:curse_of_undeath=Curse of Undeath +spell.ebwizardry\:darkness_orb=Darkness Orb +spell.ebwizardry\:darkvision=Darkvision +spell.ebwizardry\:dart=Dart +spell.ebwizardry\:decay=Decay +spell.ebwizardry\:decoy=Decoy +spell.ebwizardry\:detonate=Detonate +spell.ebwizardry\:diamondflesh=Diamondflesh +spell.ebwizardry\:disintegration=Disintegration +spell.ebwizardry\:divination=Divination +spell.ebwizardry\:dragon_fireball=Dragon Fireball +spell.ebwizardry\:earthquake=Earthquake +spell.ebwizardry\:empowering_presence=Empowering Presence +spell.ebwizardry\:entrapment=Entrapment +spell.ebwizardry\:evade=Evade +spell.ebwizardry\:fireball=Fireball +spell.ebwizardry\:firebolt=Firebolt +spell.ebwizardry\:firebomb=Firebomb +spell.ebwizardry\:fire_resistance=Fire Resistance +spell.ebwizardry\:fire_sigil=Fire Sigil +spell.ebwizardry\:fireskin=Fireskin +spell.ebwizardry\:fire_breath=Fire Breath +spell.ebwizardry\:flame_ray=Flame Ray +spell.ebwizardry\:flaming_axe=Flaming Axe +spell.ebwizardry\:flaming_weapon=Flaming Weapon +spell.ebwizardry\:flight=Flight +spell.ebwizardry\:font_of_mana=Font of Mana +spell.ebwizardry\:font_of_vitality=Font of Vitality +spell.ebwizardry\:force_arrow=Force Arrow +spell.ebwizardry\:forcefield=Forcefield +spell.ebwizardry\:force_orb=Force Orb +spell.ebwizardry\:forests_curse=Forest's Curse +spell.ebwizardry\:forest_of_thorns=Forest of Thorns +spell.ebwizardry\:freeze=Freeze +spell.ebwizardry\:freezing_weapon=Freezing Weapon +spell.ebwizardry\:frost_axe=Frost Axe +spell.ebwizardry\:frost_ray=Frost Ray +spell.ebwizardry\:frost_sigil=Frost Sigil +spell.ebwizardry\:frost_step=Frost Step +spell.ebwizardry\:glide=Glide +spell.ebwizardry\:grapple=Grapple +spell.ebwizardry\:greater_fireball=Greater Fireball +spell.ebwizardry\:greater_heal=Greater Heal +spell.ebwizardry\:greater_telekinesis=Greater Telekinesis +spell.ebwizardry\:greater_ward=Greater Ward +spell.ebwizardry\:group_heal=Group Heal +spell.ebwizardry\:growth_aura=Growth Aura +spell.ebwizardry\:hailstorm=Hailstorm +spell.ebwizardry\:heal=Heal +spell.ebwizardry\:heal_ally=Heal Ally +spell.ebwizardry\:healing_aura=Healing Aura +spell.ebwizardry\:homing_spark=Homing Spark +spell.ebwizardry\:iceball=Iceball +spell.ebwizardry\:ice_age=Ice Age +spell.ebwizardry\:ice_charge=Ice Charge +spell.ebwizardry\:ice_lance=Ice Lance +spell.ebwizardry\:ice_shard=Ice Shard +spell.ebwizardry\:ice_shroud=Ice Shroud +spell.ebwizardry\:ice_spikes=Ice Spikes +spell.ebwizardry\:ice_statue=Ice Statue +spell.ebwizardry\:ignite=Ignite +spell.ebwizardry\:imbue_weapon=Imbue Weapon +spell.ebwizardry\:intimidate=Intimidate +spell.ebwizardry\:invigorating_presence=Invigorating Presence +spell.ebwizardry\:invisibility=Invisibility +spell.ebwizardry\:invoke_weather=Invoke Weather +spell.ebwizardry\:ironflesh=Ironflesh +spell.ebwizardry\:leap=Leap +spell.ebwizardry\:levitation=Levitation +spell.ebwizardry\:life_drain=Life Drain +spell.ebwizardry\:light=Light +spell.ebwizardry\:lightning_arrow=Lightning Arrow +spell.ebwizardry\:lightning_bolt=Lightning Bolt +spell.ebwizardry\:lightning_disc=Lightning Disc +spell.ebwizardry\:lightning_hammer=Lightning Hammer +spell.ebwizardry\:lightning_pulse=Lightning Pulse +spell.ebwizardry\:lightning_ray=Lightning Ray +spell.ebwizardry\:lightning_sigil=Lightning Sigil +spell.ebwizardry\:lightning_web=Lightning Web +spell.ebwizardry\:magic_missile=Magic Missile +spell.ebwizardry\:metamorphosis=Metamorphosis +spell.ebwizardry\:meteor=Meteor +spell.ebwizardry\:mind_control=Mind Control +spell.ebwizardry\:mind_trick=Mind Trick +spell.ebwizardry\:mine=Mine +spell.ebwizardry\:muffle=Muffle +spell.ebwizardry\:none=[Empty Slot] +spell.ebwizardry\:oakflesh=Oakflesh +spell.ebwizardry\:paralysis=Paralysis +spell.ebwizardry\:petrify=Petrify +spell.ebwizardry\:phase_step=Phase Step +spell.ebwizardry\:plague_of_darkness=Plague of Darkness +spell.ebwizardry\:pocket_furnace=Pocket Furnace +spell.ebwizardry\:pocket_workbench=Pocket Workbench +spell.ebwizardry\:poison=Poison +spell.ebwizardry\:poison_bomb=Poison Bomb +spell.ebwizardry\:possession=Possession +spell.ebwizardry\:ray_of_purification=Ray of Purification +spell.ebwizardry\:remove_curse=Remove Curse +spell.ebwizardry\:replenish_hunger=Replenish Hunger +spell.ebwizardry\:resurrection=Resurrection +spell.ebwizardry\:reversal=Reversal +spell.ebwizardry\:ring_of_fire=Ring of Fire +spell.ebwizardry\:satiety=Satiety +spell.ebwizardry\:shadow_ward=Shadow Ward +spell.ebwizardry\:shield=Shield +spell.ebwizardry\:shockwave=Shockwave +spell.ebwizardry\:shulker_bullet=Shulker Bullet +spell.ebwizardry\:silverfish_swarm=Silverfish Swarm +spell.ebwizardry\:sixth_sense=Sixth Sense +spell.ebwizardry\:slime=Slime +spell.ebwizardry\:slow_time=Slow Time +spell.ebwizardry\:smoke_bomb=Smoke Bomb +spell.ebwizardry\:snare=Snare +spell.ebwizardry\:snowball=Snowball +spell.ebwizardry\:spark_bomb=Spark Bomb +spell.ebwizardry\:spectral_pathway=Spectral Pathway +spell.ebwizardry\:speed_time=Speed Time +spell.ebwizardry\:spider_swarm=Spider Swarm +spell.ebwizardry\:static_aura=Static Aura +spell.ebwizardry\:summon_blaze=Summon Blaze +spell.ebwizardry\:summon_ice_giant=Summon Ice Giant +spell.ebwizardry\:summon_ice_wraith=Summon Ice Wraith +spell.ebwizardry\:summon_iron_golem=Summon Iron Golem +spell.ebwizardry\:summon_lightning_wraith=Summon Lightning Wraith +spell.ebwizardry\:summon_phoenix=Summon Phoenix +spell.ebwizardry\:summon_shadow_wraith=Summon Shadow Wraith +spell.ebwizardry\:summon_skeleton=Summon Skeleton +spell.ebwizardry\:summon_skeleton_legion=Summon Skeleton Legion +spell.ebwizardry\:summon_snow_golem=Summon Snow Golem +spell.ebwizardry\:summon_spirit_horse=Summon Spirit Horse +spell.ebwizardry\:summon_spirit_wolf=Summon Spirit Wolf +spell.ebwizardry\:summon_storm_elemental=Summon Storm Elemental +spell.ebwizardry\:summon_wither_skeleton=Summon Wither Skeleton +spell.ebwizardry\:summon_zombie=Summon Zombie +spell.ebwizardry\:telekinesis=Telekinesis +spell.ebwizardry\:thunderbolt=Thunderbolt +spell.ebwizardry\:thunderstorm=Thunderstorm +spell.ebwizardry\:tornado=Tornado +spell.ebwizardry\:transience=Transience +spell.ebwizardry\:transportation=Transportation +spell.ebwizardry\:vanishing_box=Vanishing Box +spell.ebwizardry\:vex_swarm=Vex Swarm +spell.ebwizardry\:wall_of_frost=Wall of Frost +spell.ebwizardry\:ward=Ward +spell.ebwizardry\:water_breathing=Water Breathing +spell.ebwizardry\:whirlwind=Whirlwind +spell.ebwizardry\:wither=Wither +spell.ebwizardry\:wither_skull=Wither Skull -spell.ebwizardry:agility.desc=Grants the caster faster movement speed and greater jump height for 30 seconds. -spell.ebwizardry:arc.desc=Fires a spark of lightning at the target. -spell.ebwizardry:arcane_jammer.desc=Prevents the target from using magic for 15 seconds. -spell.ebwizardry:arrow_rain.desc="Archers, fire!" -spell.ebwizardry:banish.desc=Teleports the target against its will to a random location within a certain range. -spell.ebwizardry:black_hole.desc=Tear reality asunder. -spell.ebwizardry:blink.desc=Teleports the caster over a short distance to where they are pointing. -spell.ebwizardry:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed. -spell.ebwizardry:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged. -spell.ebwizardry:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice. -spell.ebwizardry:clairvoyance.desc=Reveals the path to a remembered location. With this spell selected, sneak-right-click on a block to set the location. Cast this spell normally to reveal the path. The path will fade after 90 seconds. -spell.ebwizardry:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken. -spell.ebwizardry:conjure_armour.desc=Creates spectral armour around the caster which offers protection equal to that of iron armour. The armour lasts for 60 seconds. The caster must have an empty armour slot. -spell.ebwizardry:conjure_bow.desc=Creates a spectral bow with unlimited arrows that lasts for 30 seconds. -spell.ebwizardry:conjure_pickaxe.desc=Creates a spectral pickaxe of equal strength to an iron pickaxe that lasts for 30 seconds. -spell.ebwizardry:conjure_sword.desc=Creates a spectral sword of equal strength to an iron sword that lasts for 30 seconds. -spell.ebwizardry:cure_effects.desc=Removes all potion effects currently affecting the caster, good or bad. -spell.ebwizardry:curse_of_soulbinding.desc=Causes the target's soul to be inextricably bound to that of the caster, meaning all damage dealt to the caster is also dealt to the victim. Lasts until either the victim or the caster dies. -spell.ebwizardry:darkness_orb.desc=Fires a slow moving bolt of dark energy in the direction you are pointing, which withers whatever it hits. -spell.ebwizardry:darkvision.desc=Grants the caster night vision for 45 seconds. -spell.ebwizardry:dart.desc=Fires a dart in the direction you are pointing which damages and weakens its target. -spell.ebwizardry:decay.desc=Creates a patch of decay on the ground which infects any creature that touches it, causing lingering damage over time and spreading more decay wherever it walks. -spell.ebwizardry:decoy.desc=Creates an illusory clone of the caster which tricks mobs into attacking it instead. The decoy will vanish after 30 seconds. -spell.ebwizardry:detonate.desc=Causes an explosion where you are pointing, damaging all nearby creatures - including the caster, if they are too close. -spell.ebwizardry:diamondflesh.desc="Your arrows are no match for me!" -spell.ebwizardry:earthquake.desc=A true master of earth magic can move mountains. -spell.ebwizardry:entrapment.desc=Traps the target in a sphere of darkness which pulls it helplessly upwards and continually damages it. -spell.ebwizardry:fireball.desc=Launches a fireball in the direction you are pointing. -spell.ebwizardry:firebolt.desc=Shoots a jet of fire a short distance in front of you. -spell.ebwizardry:firebomb.desc=Lanches a firebomb in the direction you are pointing which explodes on impact, setting targets on fire. -spell.ebwizardry:fire_resistance.desc=Grants the caster fire resistance for 30 seconds. -spell.ebwizardry:fire_sigil.desc=Places a magical fire trap on the ground which damages and sets on fire the creature that triggers it. -spell.ebwizardry:fireskin.desc=Cloaks the caster in flames for 30 seconds, causing anything that attacks them to catch fire. -spell.ebwizardry:firestorm.desc="I am the dragon." -spell.ebwizardry:flame_ray.desc=Creates a stream of flames in the direction you are pointing which sets on fire and continually damages targets. -spell.ebwizardry:flaming_axe.desc=Creates a flaming axe which sets enemies on fire when hit. Lasts for 30 seconds. -spell.ebwizardry:flaming_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of flame, causing it to set fire to its victims. The magic wears off after 45 seconds. -spell.ebwizardry:flight.desc=Soar like an eagle. -spell.ebwizardry:font_of_mana.desc="We were filled with an intense magical energy appearing to emanate from the centre of the..." - Extract from the journal of a forgotten mage; the rest of the page has been burnt away. -spell.ebwizardry:font_of_vitality.desc=It feels amazing. -spell.ebwizardry:force_arrow.desc=Shoots an arrow of force in the direction you are pointing. -spell.ebwizardry:forcefield.desc=Creates a forcefield around the caster which repels creatures and deflects projectiles. -spell.ebwizardry:force_orb.desc=Launches a sphere of force which damages and repels nearby creatures on impact. -spell.ebwizardry:forests_curse.desc="How dare you enter my forest!" -spell.ebwizardry:freeze.desc=Freezes the target for 10 seconds. Will also freeze water and create snow on the ground. -spell.ebwizardry:freezing_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of frost, causing it to freeze its victims. The magic wears off after 45 seconds. -spell.ebwizardry:frost_axe.desc=Creates a frozen axe which freezes enemies when hit. Lasts for 30 seconds. -spell.ebwizardry:frost_ray.desc=Creates a stream of frost in the direction you are pointing which slows and continually damages targets. -spell.ebwizardry:frost_sigil.desc=Places a magical ice trap on the ground which damages and freezes the creature that triggers it. -spell.ebwizardry:glide.desc=Allows the caster to glide downwards while in the air and holding the use item button. -spell.ebwizardry:greater_fireball.desc=Launches a large fireball in the direction you are pointing which explodes on impact. -spell.ebwizardry:greater_heal.desc=Heals the caster by 4 hearts. -spell.ebwizardry:group_heal.desc=Heals the caster and all nearby allies and summoned creatures by 3 hearts. -spell.ebwizardry:growth_aura.desc=Grows all crops near the caster. Also grows tall grass and flowers on grass. -spell.ebwizardry:hailstorm.desc=It was during the great winter of the third age that the ice mages discovered their true power. -spell.ebwizardry:heal.desc=Heals the caster by 2 hearts. -spell.ebwizardry:heal_ally.desc=Heals the target by 2 and a half hearts. -spell.ebwizardry:healing_aura.desc=Creates a zone of healing energy which regenerates the health of any ally inside it. Any undead inside the healing aura will slowly take damage. -spell.ebwizardry:homing_spark.desc=Creates a floating spark which moves towards enemies. -spell.ebwizardry:ice_age.desc="You shall be frozen for an eternity!" -spell.ebwizardry:ice_charge.desc=Launches an ice charge which explodes on impact, freezing nearby creatures and releasing shards in all directions. -spell.ebwizardry:ice_lance.desc=Fires a great spear of ice in the direction you are pointing which overpenetrates targets, damaging and freezing them in the process. -spell.ebwizardry:ice_shard.desc=Fires a shard of ice in the direction you are pointing which damages and slows targets when hit. -spell.ebwizardry:ice_shroud.desc=Creates a shroud of cold around the caster for 30 seconds, causing anything that attacks them to be frozen. -spell.ebwizardry:ice_spikes.desc=Causes razor-sharp ice spikes to rise from the ground where you are pointing, skewering any creatures caught amongst them. -spell.ebwizardry:ice_statue.desc=Freezes the target solid for 20 seconds or until broken out. The target cannot move or do anything while frozen but is also impervious to all damage. -spell.ebwizardry:ignite.desc=Sets the target on fire for 10 seconds. Also works like a flint and steel. -spell.ebwizardry:imbue_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with magic, rendering it more effective. The magic wears off after 45 seconds. -spell.ebwizardry:intimidate.desc=Emits an intimidating growl which causes nearby creatures to run away in fear. Fear stricken creatures will recover after 30 seconds. -spell.ebwizardry:invigorating_presence.desc=Grants the caster and all nearby allies increased strength for 45 seconds. -spell.ebwizardry:invisibility.desc=Makes the caster invisible for 30 seconds. -spell.ebwizardry:invoke_weather.desc=Changes the weather in the world. -spell.ebwizardry:ironflesh.desc=Greatly improves the caster's damage resistance for 30 seconds. -spell.ebwizardry:leap.desc=Causes the caster to jump upwards several blocks and slightly forward. -spell.ebwizardry:levitation.desc=Raises the caster upwards while the use item button is held. Will also negate fall damage if used before hitting the ground. -spell.ebwizardry:life_drain.desc=Creates a stream of withering energy in the direction you are pointing which drains the life of the target and uses it to gradually regenerate your health. -spell.ebwizardry:light.desc=Creates a magical point of light which illuminates the surrounding area. Lasts for 30 seconds. -spell.ebwizardry:lightning_arrow.desc=Shoots an arrow of lightning in the direction you are pointing. -spell.ebwizardry:lightning_bolt.desc=Causes lightning to strike where you are pointing. -spell.ebwizardry:lightning_disc.desc=Sends a disc of lightning flying off in the direction you are pointing, which seeks targets. -spell.ebwizardry:lightning_hammer.desc="I smite you by the wrath of the heavens!" -spell.ebwizardry:lightning_pulse.desc=Charges the ground around the caster with lightning, damaging and repelling nearby creatures. -spell.ebwizardry:lightning_ray.desc=Creates a stream of lightning in the direction you are pointing which continually damages targets. -spell.ebwizardry:lightning_sigil.desc=Places a magical lightning trap on the ground which damages the creature that triggers it and chains lightning to other nearby creatures. -spell.ebwizardry:lightning_web.desc="Focus. Channel the storm in your mind through your wand and unleash its fury." -spell.ebwizardry:magic_missile.desc=Fires a bolt of magical energy in the direction you are pointing. -spell.ebwizardry:metamorphosis.desc=Changes the target into another form. Only works on some creatures. -spell.ebwizardry:meteor.desc=Some wizards just want to see the world burn... -spell.ebwizardry:mind_control.desc=Takes control of the target's mind for 30 seconds, causing it switch sides and fight for the caster instead. Will not work on creatures that are too strong-willed. -spell.ebwizardry:mind_trick.desc=Confuses and disorients the target for 15 seconds, rendering it unable to attack effectively. The effect will be dispelled if the target takes damage. -spell.ebwizardry:none.desc=To get a spell book with the /give command, use metadata: /give [player] ebwizardry:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up). -spell.ebwizardry:oakflesh.desc=Improves the caster's damage resistance for 30 seconds. -spell.ebwizardry:petrify.desc=Turns the target to stone until broken out, with a chance for it to break out when it is dark. The target cannot move or do anything while petrified but is also impervious to all damage. -spell.ebwizardry:phase_step.desc=Teleports the caster through a 1 block thick wall in front of them. Range upgrades will increase the thickness you can teleport through. -spell.ebwizardry:plague_of_darkness.desc=The darkness will consume them all... -spell.ebwizardry:pocket_furnace.desc=Smelts up to 5 smeltable items in the caster's inventory. Items on the hotbar will be smelted first. -spell.ebwizardry:pocket_workbench.desc=Allows the caster to craft items as if they were at a crafting table. -spell.ebwizardry:poison.desc=Fires poison in the direction you are pointing. -spell.ebwizardry:poison_bomb.desc=Lanches a poison bomb in the direction you are pointing which explodes on impact, poisoning nearby creatures. -spell.ebwizardry:replenish_hunger.desc=Replenishes the caster's food level by 6 hunger points. -spell.ebwizardry:ring_of_fire.desc=Creates a ring of fire around the caster, damaging all nearby enemies and setting them on fire. -spell.ebwizardry:shadow_ward.desc=Creates a wall of darkness in front of the caster which causes half of all incoming damage to be inflicted upon the attacker instead. -spell.ebwizardry:shield.desc=Creates a protective barrier of force that blocks projectiles and magic. Also grants the caster a weak resistance effect. -spell.ebwizardry:shockwave.desc=Boom. -spell.ebwizardry:silverfish_swarm.desc="Ahhhh! They're MULTIPLYING!" -spell.ebwizardry:sixth_sense.desc=Allows the caster to sense the locations of nearby creatures, even through walls, for 20 seconds. -spell.ebwizardry:slime.desc=Engulfs the target in slime which slows and continually damages it. The slime bursts after 10 seconds. -spell.ebwizardry:smoke_bomb.desc=Launches a smoke bomb in the direction you are pointing which explodes on impact, releasing smoke and blinding nearby creatures for a short time. -spell.ebwizardry:snare.desc=Sets a trap on the ground which damages and briefly slows the creature that triggers it. -spell.ebwizardry:snowball.desc=Launches a snowball in the direction you are pointing. -spell.ebwizardry:spark_bomb.desc=Launches a shock charge in the direction you are pointing which releases sparks at nearby enemies on impact. -spell.ebwizardry:spectral_pathway.desc=Creates an indestructible magical bridge in front of you which extends for 15 blocks. The bridge vanishes after 60 seconds. -spell.ebwizardry:spider_swarm.desc=Summons a swarm of venomous spiders to fight for you. The spiders will disappear after 30 seconds or if they are killed. -spell.ebwizardry:static_aura.desc=Surrounds the caster with lightning for 30 seconds, firing a spark of lightning at anything that hits them. -spell.ebwizardry:summon_blaze.desc=Summons a blaze to fight for you. The blaze will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_ice_giant.desc="Smash them!" -spell.ebwizardry:summon_ice_wraith.desc=Summons an ice wraith to fight for you. The ice wraith will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_iron_golem.desc=Automatic automated autonomous automaton. -spell.ebwizardry:summon_lightning_wraith.desc=Summons a lightning wraith to fight for you. The lightning wraith will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_phoenix.desc=From the ashes... -spell.ebwizardry:summon_shadow_wraith.desc=Summons a shadow wraith to fight for you. -spell.ebwizardry:summon_skeleton.desc=Summons a skeleton to fight for you. The skeleton will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_skeleton_legion.desc="Rise, undead army!" -spell.ebwizardry:summon_snow_golem.desc=Creates a snow golem to fight for you. Lasts until the snow golem dies. -spell.ebwizardry:summon_spirit_horse.desc=Summons a spirit horse for you to ride. The spirit horse will vanish a short while after it is dismounted, or you can dismiss it by shift-right-clicking on it with any wand. -spell.ebwizardry:summon_spirit_wolf.desc=Summons a spirit wolf companion to fight for you. The spirit wolf will only disappear if it is killed, or you can dismiss it by shift-right-clicking on it with any wand. -spell.ebwizardry:summon_storm_elemental.desc="Storm Elemental: An ancient manifestation of the elements, it can hardly contain the raw power churning within it." - The Wizard's Guide to Arcane Beings, Volume I_i -spell.ebwizardry:summon_wither_skeleton.desc=Summons a wither skeleton to fight for you. The wither skeleton will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_zombie.desc=Summons a zombie to fight for you. The zombie will disappear after 30 seconds or if it is killed. -spell.ebwizardry:telekinesis.desc=Moves an item or other small object towards you, or right-clicks the block you are looking at. Can also be used to disarm players. -spell.ebwizardry:thunderbolt.desc=Shoots a bolt of thunder which knocks back targets. -spell.ebwizardry:thunderstorm.desc="Mwahahahahahaha!" -spell.ebwizardry:tornado.desc=Unleashes a tornado in the direction you are pointing which hurls anything in its path skywards. -spell.ebwizardry:transience.desc=Makes the caster transient for 20 seconds. The caster is immune to all damage while transient but cannot break or place blocks or cause any damage. -spell.ebwizardry:transportation.desc=Transports the caster to their remembered stone circle. To use this spell, make a circle of stones of transportation, then right click it with a wand. -spell.ebwizardry:vanishing_box.desc=Grants the caster access to their ender chest storage. -spell.ebwizardry:wall_of_frost.desc=Winter at your fingertips. -spell.ebwizardry:water_breathing.desc=Allows the caster to breathe underwater for 60 seconds. -spell.ebwizardry:whirlwind.desc=Causes the target to be blown upwards and away from you at speed. -spell.ebwizardry:wither.desc=Fires a ray of darkness which withers anything it touches. -spell.ebwizardry:wither_skull.desc=Launches a wither skull in the direction you are pointing. +spell.ebwizardry\:agility.desc=Grants the caster faster movement speed and greater jump height for 30 seconds. +spell.ebwizardry\:arc.desc=Fires a spark of lightning at the target. +spell.ebwizardry\:arcane_jammer.desc=Prevents the target from using magic for 15 seconds. +spell.ebwizardry\:arcane_lock.desc=Creates an impenetrable barrier of force around a container, protecting it from being opened or destroyed. The caster and their allies may still open it, however. +spell.ebwizardry\:arrow_rain.desc="Archers, fire!" +spell.ebwizardry\:banish.desc=Teleports the target against its will to a random locations within a certain range. +spell.ebwizardry\:black_hole.desc=Tear reality asunder. +spell.ebwizardry\:blink.desc=Teleports the caster over a short distance to where they are pointing. +spell.ebwizardry\:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed. +spell.ebwizardry\:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged. +spell.ebwizardry\:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice. +spell.ebwizardry\:charge.desc=Causes the caster to charge rapidly in the direction they are looking, damaging and knocking back anything in their path. +spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered locations. With this spell selected, sneak-right-click on a block to set the locations. Cast this spell normally to reveal the path. The path will fade after 90 seconds. +spell.ebwizardry\:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken. +spell.ebwizardry\:combustion_rune.desc=Places a magical landmine on the ground where you are pointing, which explodes when stepped upon. +spell.ebwizardry\:conjure_armour.desc=Creates spectral armour around the caster which offers protection equal to that of iron armour. The armour lasts for 60 seconds. The caster must have an empty armour slot. +spell.ebwizardry\:conjure_block.desc=Conjures a spectral block where you are pointing. The spectral block disappears after 45 seconds, or you can dispel it by casting this spell at it again. +spell.ebwizardry\:conjure_bow.desc=Creates a spectral bow with unlimited arrows that lasts for 30 seconds. +spell.ebwizardry\:conjure_pickaxe.desc=Creates a spectral pickaxe of equal strength to an iron pickaxe that lasts for 30 seconds. +spell.ebwizardry\:conjure_sword.desc=Creates a spectral sword of equal strength to an iron sword that lasts for 30 seconds. +spell.ebwizardry\:containment.desc=Contains the target to within a short distance of its current position for 20 seconds. +spell.ebwizardry\:cure_effects.desc=Removes all potion effects currently affecting the caster, good or bad. +spell.ebwizardry\:curse_of_enfeeblement.desc="He was suddenly weakened, as if the life had been wrenched from within him." - Testimony of the only person known to have encountered a member of the soulwalker cult and survived. +spell.ebwizardry\:curse_of_soulbinding.desc=Causes the target's soul to be inextricably bound to that of the caster, meaning all damage dealt to the caster is also dealt to the victim. Lasts until either the victim or the caster dies. +spell.ebwizardry\:curse_of_undeath.desc=Curses the target with undeath, causing it to burn in sunlight, like zombies and skeletons. Lasts until the victim dies. Has no effect on undead creatures. +spell.ebwizardry\:darkness_orb.desc=Fires a slow moving bolt of dark energy in the direction you are pointing, which withers whatever it hits. +spell.ebwizardry\:darkvision.desc=Grants the caster night vision for 45 seconds. +spell.ebwizardry\:dart.desc=Fires a dart in the direction you are pointing which damages and weakens its target. +spell.ebwizardry\:decay.desc=Creates a patch of decay on the ground which infects any creature that touches it, causing lingering damage over time and spreading more decay wherever it walks. +spell.ebwizardry\:decoy.desc=Creates an illusory clone of the caster which tricks mobs into attacking it instead. The decoy will vanish after 30 seconds. +spell.ebwizardry\:detonate.desc=Causes an explosion where you are pointing, damaging all nearby creatures - including the caster, if they are too close. +spell.ebwizardry\:diamondflesh.desc="Your arrows are no match for me!" +spell.ebwizardry\:disintegration.desc=Shoots a powerful bolt of flame a short distance in front of you which causes targets to explode into burning embers when killed. Creatures that step on the embers will be set on fire. +spell.ebwizardry\:divination.desc=Guides the caster to nearby ores and resources. Potency will increase the chance of finding more valuable ores. +spell.ebwizardry\:dragon_fireball.desc=Launches an enderdragon fireball in the direction you are pointing, which releases lingering poisonous clouds on impact. +spell.ebwizardry\:earthquake.desc=A true master of earth magic can move mountains. +spell.ebwizardry\:empowering_presence.desc=Grants the caster and nearby allies increased magic damage for 30 seconds. +spell.ebwizardry\:entrapment.desc=Traps the target in a sphere of darkness which pulls it helplessly upwards and continually damages it. +spell.ebwizardry\:evade.desc=Causes the caster to quickly jump sideways to dodge incoming attacks. +spell.ebwizardry\:fireball.desc=Launches a fireball in the direction you are pointing. +spell.ebwizardry\:firebolt.desc=Shoots a jet of fire a short distance in front of you. +spell.ebwizardry\:firebomb.desc=Lanches a firebomb in the direction you are pointing which explodes on impact, setting targets on fire. +spell.ebwizardry\:fire_resistance.desc=Grants the caster fire resistance for 30 seconds. +spell.ebwizardry\:fire_sigil.desc=Places a magical fire trap on the ground which damages and sets on fire the creature that triggers it. +spell.ebwizardry\:fireskin.desc=Cloaks the caster in flames for 30 seconds, causing anything that attacks them to catch fire. +spell.ebwizardry\:fire_breath.desc="I am the dragon." +spell.ebwizardry\:flame_ray.desc=Creates a stream of flames in the direction you are pointing which sets on fire and continually damages targets. +spell.ebwizardry\:flaming_axe.desc=Creates a flaming axe which sets enemies on fire when hit. Lasts for 30 seconds. +spell.ebwizardry\:flaming_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of flame, causing it to set fire to its victims. The magic wears off after 45 seconds. +spell.ebwizardry\:flight.desc=Soar like an eagle. +spell.ebwizardry\:font_of_mana.desc="We were filled with an intense magical energy appearing to emanate from the centre of the..." - Extract from the journal of a forgotten mage; the rest of the page has been burnt away. +spell.ebwizardry\:font_of_vitality.desc=It feels amazing. +spell.ebwizardry\:force_arrow.desc=Shoots an arrow of force in the direction you are pointing. +spell.ebwizardry\:forcefield.desc=Creates a forcefield around the caster which repels creatures and deflects projectiles. +spell.ebwizardry\:force_orb.desc=Launches a sphere of force which damages and repels nearby creatures on impact. +spell.ebwizardry\:forests_curse.desc="How dare you enter my forest!" +spell.ebwizardry\:forest_of_thorns.desc=Amidst the wood lies a hidden glade,\nIn the glade a wizard performs,\nMagical arts of an order untold,\nDeep within the forest of thorns. +spell.ebwizardry\:freeze.desc=Freezes the target for 10 seconds. Will also freeze water and create snow on the ground. +spell.ebwizardry\:freezing_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of frost, causing it to freeze its victims. The magic wears off after 45 seconds. +spell.ebwizardry\:frost_axe.desc=Creates a frozen axe which freezes enemies when hit. Lasts for 30 seconds. +spell.ebwizardry\:frost_ray.desc=Creates a stream of frost in the direction you are pointing which slows and continually damages targets. +spell.ebwizardry\:frost_sigil.desc=Places a magical ice trap on the ground which damages and freezes the creature that triggers it. +spell.ebwizardry\:frost_step.desc=Allows the caster to freeze water as they walk for 30 seconds. +spell.ebwizardry\:grapple.desc=Shoots a magical vine which allows the caster to grapple towards blocks or reel in entities. Release the use item button to let go of the block or entity. +spell.ebwizardry\:glide.desc=Allows the caster to glide downwards while in the air and holding the use item button. +spell.ebwizardry\:greater_fireball.desc=Launches a large fireball in the direction you are pointing which explodes on impact. +spell.ebwizardry\:greater_heal.desc=Heals the caster by 4 hearts. +spell.ebwizardry\:greater_telekinesis.desc=Allows the caster to pick up a block or creature and hold it in the air for as long as the use item button is pressed. Sneaking whilst holding a block or creature will throw it a short distance. +spell.ebwizardry\:greater_ward.desc=Grants the caster a strong shielding effect that greatly reduces incoming magic damage for 30 seconds. +spell.ebwizardry\:group_heal.desc=Heals the caster and all nearby allies and summoned creatures by 3 hearts. +spell.ebwizardry\:growth_aura.desc=Grows all crops near the caster. Also grows tall grass and flowers on grass. +spell.ebwizardry\:hailstorm.desc=It was during the great winter of the third age that the ice mages discovered their true power. +spell.ebwizardry\:heal.desc=Heals the caster by 2 hearts. +spell.ebwizardry\:heal_ally.desc=Heals the target by 2 and a half hearts. +spell.ebwizardry\:healing_aura.desc=Creates a zone of healing energy which regenerates the health of any ally inside it. Any undead inside the healing aura will slowly take damage. +spell.ebwizardry\:homing_spark.desc=Creates a floating spark which moves towards enemies. +spell.ebwizardry\:iceball.desc=Launches an iceball in the direction you are pointing. +spell.ebwizardry\:ice_age.desc="You shall be frozen for an eternity!" +spell.ebwizardry\:ice_charge.desc=Launches an ice charge which explodes on impact, freezing nearby creatures and releasing shards in all directions. +spell.ebwizardry\:ice_lance.desc=Fires a great spear of ice in the direction you are pointing which overpenetrates targets, damaging and freezing them in the process. +spell.ebwizardry\:ice_shard.desc=Fires a shard of ice in the direction you are pointing which damages and slows targets when hit. +spell.ebwizardry\:ice_shroud.desc=Creates a shroud of cold around the caster for 30 seconds, causing anything that attacks them to be frozen. +spell.ebwizardry\:ice_spikes.desc=Causes razor-sharp ice spikes to rise from the ground where you are pointing, skewering any creatures caught amongst them. +spell.ebwizardry\:ice_statue.desc=Freezes the target solid for 20 seconds or until broken out. The target cannot move or do anything while frozen but is also impervious to all damage. +spell.ebwizardry\:ignite.desc=Sets the target on fire for 10 seconds. Also works like a flint and steel. +spell.ebwizardry\:imbue_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with magic, rendering it more effective. The magic wears off after 45 seconds. +spell.ebwizardry\:intimidate.desc=Emits an intimidating growl which causes nearby creatures to run away in fear. Fear stricken creatures will recover after 30 seconds. +spell.ebwizardry\:invigorating_presence.desc=Grants the caster and all nearby allies increased strength for 45 seconds. +spell.ebwizardry\:invisibility.desc=Makes the caster invisible for 30 seconds. +spell.ebwizardry\:invoke_weather.desc=Changes the weather in the world. +spell.ebwizardry\:ironflesh.desc=Greatly improves the caster's damage resistance for 30 seconds. +spell.ebwizardry\:leap.desc=Causes the caster to jump upwards several blocks and slightly forward. +spell.ebwizardry\:levitation.desc=Raises the caster upwards while the use item button is held. Will also negate fall damage if used before hitting the ground. +spell.ebwizardry\:life_drain.desc=Creates a stream of withering energy in the direction you are pointing which drains the life of the target and uses it to gradually regenerate your health. +spell.ebwizardry\:light.desc=Creates a magical point of light which illuminates the surrounding area. Lasts for 30 seconds. +spell.ebwizardry\:lightning_arrow.desc=Shoots an arrow of lightning in the direction you are pointing. +spell.ebwizardry\:lightning_bolt.desc=Causes lightning to strike where you are pointing. +spell.ebwizardry\:lightning_disc.desc=Sends a disc of lightning flying off in the direction you are pointing, which seeks targets. +spell.ebwizardry\:lightning_hammer.desc="I smite you by the wrath of the heavens!" +spell.ebwizardry\:lightning_pulse.desc=Charges the ground around the caster with lightning, damaging and repelling nearby creatures. +spell.ebwizardry\:lightning_ray.desc=Creates a stream of lightning in the direction you are pointing which continually damages targets. +spell.ebwizardry\:lightning_sigil.desc=Places a magical lightning trap on the ground which damages the creature that triggers it and chains lightning to other nearby creatures. +spell.ebwizardry\:lightning_web.desc="Focus. Channel the storm in your mind through your wand and unleash its fury." +spell.ebwizardry\:magic_missile.desc=Fires a bolt of magical energy in the direction you are pointing. +spell.ebwizardry\:metamorphosis.desc=Changes the target into another form. Only works on some creatures. +spell.ebwizardry\:meteor.desc=Some wizards just want to see the world burn... +spell.ebwizardry\:mind_control.desc=Takes control of the target's mind for 30 seconds, causing it switch sides and fight for the caster instead. Will not work on creatures that are too strong-willed. +spell.ebwizardry\:mind_trick.desc=Confuses and disorients the target for 15 seconds, rendering it unable to attack effectively. The effect will be dispelled if the target takes damage. +spell.ebwizardry\:mine.desc=Breaks the block the caster is looking at. Potency will allow harder blocks to be broken. +spell.ebwizardry\:muffle.desc=Silences any sounds made by the caster for 30 seconds. When muffled, mobs can only detect you when looking towards you. +spell.ebwizardry\:none.desc=To get a spell book with the /give command, use id\: /give [player] ebwizardry\:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up). +spell.ebwizardry\:oakflesh.desc=Improves the caster's damage resistance for 30 seconds. +spell.ebwizardry\:paralysis.desc=Delivers a powerful lightning bolt that paralyses targets for 5 seconds. Paralysed creatures cannot move and will still take damage - but too much will snap the creature out of paralysis. +spell.ebwizardry\:petrify.desc=Turns the target to stone until broken out, with a chance for it to break out when it is dark. The target cannot move or do anything while petrified but is also impervious to all damage. +spell.ebwizardry\:phase_step.desc=Teleports the caster a short distance in front of them, including through walls. Range upgrades will increase the wall thickness you can teleport through. +spell.ebwizardry\:plague_of_darkness.desc=The darkness will consume them all... +spell.ebwizardry\:pocket_furnace.desc=Smelts up to 5 smeltable items in the caster's inventory. Items on the hotbar will be smelted first. +spell.ebwizardry\:pocket_workbench.desc=Allows the caster to craft items as if they were at a crafting table. +spell.ebwizardry\:poison.desc=Fires poison in the direction you are pointing. +spell.ebwizardry\:poison_bomb.desc=Lanches a poison bomb in the direction you are pointing which explodes on impact, poisoning nearby creatures. +spell.ebwizardry\:possession.desc="Become thy enemy." +spell.ebwizardry\:ray_of_purification.desc=Emits a ray of blinding light that damages and blinds its targets. Undead creatures take double damage and are set on fire. +spell.ebwizardry\:remove_curse.desc=Removes any curse currently affecting the caster. +spell.ebwizardry\:replenish_hunger.desc=Replenishes the caster's food level by 4 hunger points. +spell.ebwizardry\:resurrection.desc=With a master healer by your side, being dead is... optional. +spell.ebwizardry\:reversal.desc=Removes a random negative potion effect and inflicts it upon the target, which will suffer that effect for the remaining duration. Potency increases the number of effects that are reversed. +spell.ebwizardry\:ring_of_fire.desc=Creates a ring of fire around the caster, damaging all nearby enemies and setting them on fire. +spell.ebwizardry\:satiety.desc=Replenishes the caster's food level by 8 hunger points. +spell.ebwizardry\:shadow_ward.desc=Creates a wall of darkness in front of the caster which causes half of all incoming damage to be inflicted upon the attacker instead. +spell.ebwizardry\:shield.desc=Creates a protective barrier of force that blocks projectiles and magic. Also grants the caster a weak resistance effect. +spell.ebwizardry\:shockwave.desc=Boom. +spell.ebwizardry\:shulker_bullet.desc=Shoots a shulker bullet which seeks targets and causes them to levitate when hit. +spell.ebwizardry\:silverfish_swarm.desc="Ahhhh! They're MULTIPLYING!" +spell.ebwizardry\:sixth_sense.desc=Allows the caster to sense the locations of nearby creatures, even through walls, for 20 seconds. +spell.ebwizardry\:slime.desc=Engulfs the target in slime which slows and continually damages it. The slime bursts after 10 seconds. +spell.ebwizardry\:slow_time.desc=Chronomancy is the art of manipulating time itself to fit one's needs. It was widely believed to be lost in the past... until now. +spell.ebwizardry\:smoke_bomb.desc=Launches a smoke bomb in the direction you are pointing which explodes on impact, releasing smoke and blinding nearby creatures for a short time. +spell.ebwizardry\:snare.desc=Sets a trap on the ground which damages and briefly slows the creature that triggers it. +spell.ebwizardry\:snowball.desc=Launches a snowball in the direction you are pointing. +spell.ebwizardry\:spark_bomb.desc=Launches a shock charge in the direction you are pointing which releases sparks at nearby enemies on impact. +spell.ebwizardry\:spectral_pathway.desc=Creates an indestructible magical bridge in front of you which extends for 15 blocks. The bridge vanishes after 60 seconds. +spell.ebwizardry\:speed_time.desc=...day, night, dawn, dusk, sunrise and sunset\: thus is the passage of time, which traps us in an endless cycle of... +spell.ebwizardry\:spider_swarm.desc=Summons a swarm of venomous spiders to fight for you. The spiders will disappear after 30 seconds or if they are killed. +spell.ebwizardry\:static_aura.desc=Surrounds the caster with lightning for 30 seconds, firing a spark of lightning at anything that hits them. +spell.ebwizardry\:summon_blaze.desc=Summons a blaze to fight for you. The blaze will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_ice_giant.desc="Smash them!" +spell.ebwizardry\:summon_ice_wraith.desc=Summons an ice wraith to fight for you. The ice wraith will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_iron_golem.desc=Automatic automated autonomous automaton. +spell.ebwizardry\:summon_lightning_wraith.desc=Summons a lightning wraith to fight for you. The lightning wraith will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_phoenix.desc=From the ashes... +spell.ebwizardry\:summon_shadow_wraith.desc=Summons a shadow wraith to fight for you. +spell.ebwizardry\:summon_skeleton.desc=Summons a skeleton to fight for you. The skeleton will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_skeleton_legion.desc="Rise, undead army!" +spell.ebwizardry\:summon_snow_golem.desc=Creates a snow golem to fight for you. Lasts until the snow golem dies. +spell.ebwizardry\:summon_spirit_horse.desc=Summons a spirit horse for you to ride. The spirit horse will vanish a short while after it is dismounted, or you can dismiss it by shift-right-clicking on it with any wand. +spell.ebwizardry\:summon_spirit_wolf.desc=Summons a spirit wolf companion to fight for you. The spirit wolf will only disappear if it is killed, or you can dismiss it by shift-right-clicking on it with any wand. +spell.ebwizardry\:summon_storm_elemental.desc="Storm Elemental\: An ancient manifestation of the elements, it can hardly contain the raw power churning within it." - The Wizard's Guide to Arcane Beings, Volume II +spell.ebwizardry\:summon_wither_skeleton.desc=Summons a wither skeleton to fight for you. The wither skeleton will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_zombie.desc=Summons a zombie to fight for you. The zombie will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:telekinesis.desc=Moves an item or other small object towards you, or right-clicks the block you are looking at. Can also be used to disarm players. +spell.ebwizardry\:thunderbolt.desc=Shoots a bolt of thunder which knocks back targets. +spell.ebwizardry\:thunderstorm.desc="Mwahahahahahaha!" +spell.ebwizardry\:tornado.desc=Unleashes a tornado in the direction you are pointing which hurls anything in its path skywards. +spell.ebwizardry\:transience.desc=Makes the caster transient for 20 seconds. The caster is immune to all damage while transient but cannot break or place blocks or cause any damage. +spell.ebwizardry\:transportation.desc=Transports the caster to their remembered stone circle. To use this spell, make a circle of stones of transportation, then right click it with a wand. +spell.ebwizardry\:vanishing_box.desc=Grants the caster access to their ender chest storage. +spell.ebwizardry\:vex_swarm.desc=Summons a swarm of flying vexes to fight for you. The vexes will disappear after 30 seconds or if they are killed. +spell.ebwizardry\:wall_of_frost.desc=Winter at your fingertips. +spell.ebwizardry\:ward.desc=Grants the caster a shielding effect that reduces incoming magic damage for 30 seconds. +spell.ebwizardry\:water_breathing.desc=Allows the caster to breathe underwater for 60 seconds. +spell.ebwizardry\:whirlwind.desc=Causes the target to be blown upwards and away from you at speed. +spell.ebwizardry\:wither.desc=Fires a ray of darkness which withers anything it touches. +spell.ebwizardry\:wither_skull.desc=Launches a wither skull in the direction you are pointing. -spell.ebwizardry:invoke_weather.sun=The rain begins to stop... -spell.ebwizardry:invoke_weather.rain=The heavens open... -spell.ebwizardry:transportation.missing=Your remembered stone circle is missing or obstructed... -spell.ebwizardry:transportation.undefined=You must remember the location of a stone circle first! -spell.ebwizardry:transportation.wrongdimension=Your remembered stone circle is in another dimension... -spell.ebwizardry:clairvoyance.searching=Searching... -spell.ebwizardry:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point -spell.ebwizardry:clairvoyance.outofrange=Your remembered location is too far away or inaccessible... -spell.ebwizardry:clairvoyance.undefined=You must remember a location first! -spell.ebwizardry:clairvoyance.wrongdimension=Your remembered location is in another dimension... +spell.ebwizardry\:invoke_weather.sun=The rain begins to stop... +spell.ebwizardry\:invoke_weather.rain=The heavens open... +spell.ebwizardry\:transportation.missing=The stone circle is missing or obstructed... +spell.ebwizardry\:transportation.undefined=You must remember the location of a stone circle first! +spell.ebwizardry\:transportation.wrongdimension=No remembered stone circle in this dimension... +spell.ebwizardry\:clairvoyance.searching=Searching... +spell.ebwizardry\:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point +spell.ebwizardry\:clairvoyance.outofrange=Your remembered locations is too far away or inaccessible... +spell.ebwizardry\:clairvoyance.undefined=You must remember a locations first! +spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered locations is in another dimension... +spell.ebwizardry\:possession.insufficienthealth=You don't have enough health to possess %1$s! +spell.ebwizardry\:possession.success=Press %s to stop possessing +spell.ebwizardry\:divination.nothing=Nothing happened. +spell.ebwizardry\:divination.weak=You can just feel your wand twitching %s. +spell.ebwizardry\:divination.moderate=You feel your wand being tugged %s. +spell.ebwizardry\:divination.strong=Your wand pulls %s strongly. +spell.ebwizardry\:divination.very_strong=Your wand lurches %s sharply. +spell.ebwizardry\:divination.down=downwards +spell.ebwizardry\:divination.up=upwards +spell.ebwizardry\:divination.front=forwards +spell.ebwizardry\:divination.back=backwards +spell.ebwizardry\:divination.left=to the left +spell.ebwizardry\:divination.right=to the right +spell.ebwizardry\:resurrection.resurrect_ally=%s was resurrected by %s +spell.ebwizardry\:resurrection.resurrect_self=%s came back to life +spell.ebwizardry\:resurrection.button_wait=Resurrect (%ss) +spell.ebwizardry\:resurrection.button_ready=Resurrect -potion.ebwizardry:frost=Frostbite -potion.ebwizardry:fireskin=Fireskin -potion.ebwizardry:ice_shroud=Ice Shroud -potion.ebwizardry:static_aura=Static Aura -potion.ebwizardry:transience=Transience -potion.ebwizardry:decay=Decay -potion.ebwizardry:sixth_sense=Sixth Sense -potion.ebwizardry:arcane_jammer=Arcane Jammer -potion.ebwizardry:mind_trick=Mind Trick -potion.ebwizardry:mind_control=Mind Control -potion.ebwizardry:font_of_mana=Font of Mana -potion.ebwizardry:fear=Fear +forfeit.ebwizardry\:do_nothing=Nothing happened. -enchantment.ebwizardry:magic_sword=Imbuement -enchantment.ebwizardry:magic_bow=Imbuement -enchantment.ebwizardry:flaming_weapon=Fire Imbuement -enchantment.ebwizardry:freezing_weapon=Frost Imbuement +forfeit.ebwizardry\:burn_self=The %s bursts into flames in your hand! +forfeit.ebwizardry\:fireball=A fireball materialises in front of you! +forfeit.ebwizardry\:firebomb=A firebomb appears right above you! +forfeit.ebwizardry\:explode=A sudden explosion knocks you to the ground! +forfeit.ebwizardry\:blazes=Suddenly, hostile blazes materialise around you! +forfeit.ebwizardry\:burn_surroundings=The area around you is set ablaze! +forfeit.ebwizardry\:meteors=Fiery armageddon rains from the sky! + +forfeit.ebwizardry\:freeze_self=You feel an icy chill rush through you! +forfeit.ebwizardry\:freeze_self_2=From the %s emanates a cold so intense that it roots you to the spot! +forfeit.ebwizardry\:ice_spikes=Ice spikes rise from the ground beneath your feet! +forfeit.ebwizardry\:blizzard=You are suddenly surrounded by a raging blizzard! +forfeit.ebwizardry\:ice_wraiths=Suddenly, hostile ice wraiths materialise around you! +forfeit.ebwizardry\:hailstorm=Razor-sharp ice starts raining down upon you! +forfeit.ebwizardry\:ice_giant=A hostile ice giant materialises in front of you! + +forfeit.ebwizardry\:thunder=The scroll emits a deafening noise, knocking you to the ground! +forfeit.ebwizardry\:storm=Looks like a storm is brewing! +forfeit.ebwizardry\:lightning_sigils=Watch your step! +forfeit.ebwizardry\:lightning=You are struck by lightning! +forfeit.ebwizardry\:paralyse_self=You are paralysed! +forfeit.ebwizardry\:lightning_wraiths=Suddenly, hostile lightning wraiths materialise around you! +forfeit.ebwizardry\:storm_elementals=Hostile storm elementals materialise on all sides! + +forfeit.ebwizardry\:nausea=...huh? What just happened? Where am I? +forfeit.ebwizardry\:zombie_horde=A horde of zombies rises from the ground around you! +forfeit.ebwizardry\:wither_self=Darkness withers your soul! +forfeit.ebwizardry\:cripple_self=The %s emits a deathly howl, and you are crippled to within an inch of your life! +forfeit.ebwizardry\:shadow_wraiths=Hostile shadow wraiths materialise on all sides! + +forfeit.ebwizardry\:snares=It's a trap! +forfeit.ebwizardry\:squid=Squid! +forfeit.ebwizardry\:uproot_plants=All nearby plants are suddenly uprooted! +forfeit.ebwizardry\:poison_self=You are poisoned! +forfeit.ebwizardry\:flood=Water materialises around you! +forfeit.ebwizardry\:bury_self=The ground collapses beneath you! + +forfeit.ebwizardry\:spill_inventory=Your items spill themselves everywhere! +forfeit.ebwizardry\:teleport_self=You are instantly teleported somewhere! +forfeit.ebwizardry\:levitate_self=You begin to float upwards helplessly! +forfeit.ebwizardry\:vex_horde=A horde of vexes materialises around you! +forfeit.ebwizardry\:black_hole=A swirling vortex appears in front of you! +forfeit.ebwizardry\:arrow_rain=A barrage of arrows starts raining down upon you! + +forfeit.ebwizardry\:damage_self=Ouch! +forfeit.ebwizardry\:spill_armour=All your armour falls off! +forfeit.ebwizardry\:hunger=You suddenly feel very hungry! +forfeit.ebwizardry\:blind_self=You are blinded! +forfeit.ebwizardry\:weaken_self=You are severely weakened! +forfeit.ebwizardry\:jam_self=Your magic is rendered useless! +forfeit.ebwizardry\:curse_self=You are cursed with undeath! + +potion.ebwizardry\:frost=Frostbite +potion.ebwizardry\:fireskin=Fireskin +potion.ebwizardry\:ice_shroud=Ice Shroud +potion.ebwizardry\:static_aura=Static Aura +potion.ebwizardry\:transience=Transience +potion.ebwizardry\:decay=Decay +potion.ebwizardry\:sixth_sense=Sixth Sense +potion.ebwizardry\:arcane_jammer=Arcane Jammer +potion.ebwizardry\:mind_trick=Mind Trick +potion.ebwizardry\:mind_control=Mind Control +potion.ebwizardry\:font_of_mana=Font of Mana +potion.ebwizardry\:fear=Fear +potion.ebwizardry\:curse_of_soulbinding=Curse of Soulbinding +potion.ebwizardry\:paralysis=Paralysis +potion.ebwizardry\:muffle=Muffle +potion.ebwizardry\:ward=Ward +potion.ebwizardry\:slow_time=Slow Time +potion.ebwizardry\:empowerment=Empowerment +potion.ebwizardry\:curse_of_enfeeblement=Curse of Enfeeblement +potion.ebwizardry\:curse_of_undeath=Curse of Undeath +potion.ebwizardry\:containment=Containment +potion.ebwizardry\:frost_step=Frost Step + +enchantment.ebwizardry\:magic_sword=Imbuement +enchantment.ebwizardry\:magic_bow=Imbuement +enchantment.ebwizardry\:flaming_weapon=Fire Imbuement +enchantment.ebwizardry\:freezing_weapon=Frost Imbuement +enchantment.ebwizardry\:shocking_weapon=Lightning Imbuement + +enchantment.ebwizardry\:magic_protection=Magic Protection +enchantment.ebwizardry\:frost_protection=Frost Protection +enchantment.ebwizardry\:shock_protection=Shock Protection key.categories.ebwizardry=Wizardry @@ -627,140 +1011,268 @@ key.ebwizardry.previous_spell=Previous Spell death.attack.wizardry_magic=%1$s was killed by %2$s using magic death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic -commands.ebwizardry:cast.usage=/%1$s [player] [damage multiplier] [range multiplier] [duration multiplier] [blast multiplier] -commands.ebwizardry:cast.success=Successfully cast %1$s -commands.ebwizardry:cast.success_continuous=Successfully cast %1$s; repeat the command to stop -commands.ebwizardry:cast.success_remote=Successfully cast %1$s as %2$s -commands.ebwizardry:cast.success_remote_continuous=Successfully cast %1$s as %2$s; repeat the command to stop -commands.ebwizardry:cast.fail=Unable to cast %1$s -commands.ebwizardry:cast.not_found=There is no such spell with ID %1$s -commands.ebwizardry:cast.tag_error=Data tag parsing failed: %s +soundCategory.ebwizardry\:spells=Spells -commands.ebwizardry:ally.usage=/%1$s [player] -commands.ebwizardry:ally.addally=%1$s has been added to %2$s's list of allies -commands.ebwizardry:ally.removeally=%1$s has been removed from %2$s's list of allies -commands.ebwizardry:ally.self=Players cannot be an ally of themselves! -commands.ebwizardry:ally.permission=You do not have permission to change other players' allies +commands.ebwizardry\:cast.usage=/%1$s [player | x y z direction] [duration] [modifiers] +commands.ebwizardry\:cast.success=Successfully cast %s +commands.ebwizardry\:cast.success_continuous=Successfully cast %s for %s seconds +commands.ebwizardry\:cast.success_remote=Successfully cast %s as %s +commands.ebwizardry\:cast.success_remote_continuous=Successfully cast %s as %s for %s seconds +commands.ebwizardry\:cast.success_position=Successfully cast %s at %s, %s, %s +commands.ebwizardry\:cast.success_position_continuous=Successfully cast %s at %s, %s, %s for %s seconds +commands.ebwizardry\:cast.fail=Unable to cast %1$s +commands.ebwizardry\:cast.not_found=There is no such spell with ID %1$s +commands.ebwizardry\:cast.invalid_direction=Invalid direction: %1$s (valid directions are: up, down, north, south, east, west) +commands.ebwizardry\:cast.tag_error=Data tag parsing failed\: %s +commands.ebwizardry\:cast.origin_not_specified=You must specify a player or location to cast the spell from +commands.ebwizardry\:cast.duration_not_specified=You must specify a duration for this spell -commands.ebwizardry:allies.usage=/%1$s [player] -commands.ebwizardry:allies.list=Players allied to you: %1$s -commands.ebwizardry:allies.list_other=Players allied to %1$s: %2$s -commands.ebwizardry:allies.permission=You do not have permission to view other players' allies -commands.ebwizardry:allies.none=None +commands.ebwizardry\:ally.usage=/%1$s [player] +commands.ebwizardry\:ally.addally=%1$s has been added to %2$s's list of allies +commands.ebwizardry\:ally.removeally=%1$s has been removed from %2$s's list of allies +commands.ebwizardry\:ally.self=Players cannot be an ally of themselves! +commands.ebwizardry\:ally.permission=You do not have permission to change other players' allies -commands.ebwizardry:discoverspell.usage=/%1$s [player] -commands.ebwizardry:discoverspell.not_found=There is no such spell with ID %1$s -commands.ebwizardry:discoverspell.clear=Cleared all spell discovery data for %1$s -commands.ebwizardry:discoverspell.all=Added all spells to %1$s's spell discovery data -commands.ebwizardry:discoverspell.addspell=Added %1$s to %2$s's spell discovery data -commands.ebwizardry:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data +commands.ebwizardry\:allies.usage=/%1$s [player] +commands.ebwizardry\:allies.list=Players allied to you\: %1$s +commands.ebwizardry\:allies.list_other=Players allied to %1$s\: %2$s +commands.ebwizardry\:allies.permission=You do not have permission to view other players' allies +commands.ebwizardry\:allies.none=None + +commands.ebwizardry\:discoverspell.usage=/%1$s [player] +commands.ebwizardry\:discoverspell.not_found=There is no such spell with ID %1$s +commands.ebwizardry\:discoverspell.clear=Cleared all spell discovery data for %1$s +commands.ebwizardry\:discoverspell.all=Added all spells to %1$s's spell discovery data +commands.ebwizardry\:discoverspell.addspell=Added %1$s to %2$s's spell discovery data +commands.ebwizardry\:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data config.ebwizardry.title.general=Mod Options +config.ebwizardry.generic.true=Enabled +config.ebwizardry.generic.false=Disabled + +config.ebwizardry.category.spells=Spell Configuration +config.ebwizardry.category.spells.tooltip=Select which spells are enabled +config.ebwizardry.title.spells=Spell Configuration +config.ebwizardry.subtitle.spells=Disabling a spell globally here will override the finer controls in the spell JSON file. + config.ebwizardry.category.gameplay=Gameplay Settings config.ebwizardry.category.gameplay.tooltip=Configure wizardry's general gameplay config.ebwizardry.title.gameplay=Gameplay Settings config.ebwizardry.subtitle.gameplay=Global settings that affect game mechanics. +config.ebwizardry.discovery_mode=Discovery Mode +config.ebwizardry.discovery_mode.tooltip=For those who like a sense of mystery! When enabled, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is disabled. +config.ebwizardry.legacy_wand_levelling=Legacy Wand Levelling +config.ebwizardry.legacy_wand_levelling.tooltip=Controls whether wands are required to gain progression before they can be upgraded to the next tier. Enable this option to revert to the pre-4.2 system, which only requires tomes of arcana. Wands will still gain progression silently when this is enabled, so if you go back to the new system you won't lose any progress. +config.ebwizardry.legacy_wand_levelling.true=Yes - I liked it how it was! +config.ebwizardry.legacy_wand_levelling.false=No - Level me up! +config.ebwizardry.friendly_fire=Friendly Fire +config.ebwizardry.friendly_fire.tooltip=Controls which creatures may be damaged by your magic when allied to you. Your spells will not target your allies or creatures summoned/owned by them regardless of this setting, but this setting makes them completely immune if disabled. +config.ebwizardry.minion_revenge_targeting=Minion Revenge Targeting +config.ebwizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge-attack players or creatures that they would not otherwise be able to attack. +config.ebwizardry.minion_revenge_targeting.true=Yes - I'd never hurt them! +config.ebwizardry.minion_revenge_targeting.false=No - they must always obey me! +config.ebwizardry.players_move_each_other=Players Move Each Other +config.ebwizardry.players_move_each_other.tooltip=Whether to allow players to move other players around using magic. +config.ebwizardry.players_move_each_other.true=Yes - let the games begin! +config.ebwizardry.players_move_each_other.false=No - I won't be pushed around +config.ebwizardry.player_block_damage=Player Block Damage +config.ebwizardry.player_block_damage.tooltip=Whether spells cast by players can destroy blocks in the world. Disable this to prevent griefing. To prevent non-players from destroying blocks with magic, use the mobGriefing gamerule. +config.ebwizardry.player_block_damage.true=Yes - kaboom! +config.ebwizardry.player_block_damage.false=No - activate anti-grief (TM) +config.ebwizardry.telekinetic_disarmament=Telekinetic Disarmament +config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Disable to prevent stealing of items. +config.ebwizardry.telekinetic_disarmament.true=Yes - let people steal things +config.ebwizardry.telekinetic_disarmament.false=No - that's cheating! +config.ebwizardry.teleport_through_unbreakable_blocks=Teleport Through Unbreakable Blocks +config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. +config.ebwizardry.teleport_through_unbreakable_blocks.true=Yes - I wish to see the void! +config.ebwizardry.teleport_through_unbreakable_blocks.false=No - bedrock is impenetrable +config.ebwizardry.world_time_manipulation=World Time Manipulation +config.ebwizardry.world_time_manipulation.tooltip=Whether players are allowed to change the world time with the speed time spell. If disabled, the speed time spell will not change the world time but will still speed up nearby block, entity and tile entity ticks. +config.ebwizardry.world_time_manipulation.true=Yes - daytime, nighttime... +config.ebwizardry.world_time_manipulation.false=No - I need my sleep! +config.ebwizardry.replace_vanilla_fireballs=Replace Vanilla Fireballs +config.ebwizardry.replace_vanilla_fireballs.tooltip=Whether to replace Minecraft's own fireballs with wizardry fireballs. If this is disabled, only wizardry spells will use the custom fireballs. +config.ebwizardry.replace_vanilla_fireballs.true=Yes - give me FIRE! +config.ebwizardry.replace_vanilla_fireballs.false=No - blazes are mean enough +config.ebwizardry.replace_vanilla_fall_damage=Replace Vanilla Fall Damage +config.ebwizardry.replace_vanilla_fall_damage.tooltip=Whether to replace Minecraft's distance-based fall damage calculation with an equivalent, velocity-based one. This is done such that mobs in freefall will take exactly the same damage as normal, so it will not break falling-based mob farms. Disable this if you experience falling-related weirdness! If this is disabled, some spells revert to a more simplistic method of resetting the player's fall damage in certain cases. +config.ebwizardry.replace_vanilla_fall_damage.true=Yes - it's parkour time +config.ebwizardry.replace_vanilla_fall_damage.false=No - break my legs normally +config.ebwizardry.creative_bypasses_arcane_lock=Bypass Arcane Lock +config.ebwizardry.creative_bypasses_arcane_lock.tooltip=Determines which players can bypass arcane locks. +config.ebwizardry.creative_bypasses_arcane_lock.true=Anyone in creative mode +config.ebwizardry.creative_bypasses_arcane_lock.false=Only ops in creative mode +config.ebwizardry.slow_time_affects_players=Slow Time Affects Players +config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed. +config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist +config.ebwizardry.mob_loot_table_whitelist.tooltip=Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them. +config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist +config.ebwizardry.mob_loot_table_blacklist.tooltip=Blacklist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually exclude them. +config.ebwizardry.mob_spawn_dimensions=Mob Spawning Dimensions +config.ebwizardry.mob_spawn_dimensions.tooltip=List of ids of dimensions in which wizardry's hostile mobs can spawn. +config.ebwizardry.mob_spawn_biome_blacklist=Mob Spawning Biome Blacklist +config.ebwizardry.mob_spawn_biome_blaclist.tooltip=List of names of biomes in which wizardry's hostile mobs cannot spawn. Biome names are not case-sensitive. For mod biomes, prefix with the mod ID (e.g. biomesoplenty\:mystic_grove). +config.ebwizardry.evil_wizard_spawn_rate=Evil Wizard Spawn Rate +config.ebwizardry.evil_wizard_spawn_rate.tooltip=Spawn rate for naturally-spawned evil wizards; higher numbers mean more evil wizards will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable evil wizard spawning entirely. +config.ebwizardry.ice_wraith_spawn_rate=Ice Wraith Spawn Rate +config.ebwizardry.ice_wraith_spawn_rate.tooltip=Spawn rate for naturally-spawned ice wraiths; higher numbers mean more ice wraiths will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable ice wraith spawning entirely. +config.ebwizardry.lightning_wraith_spawn_rate=Lightning Wraith Spawn Rate +config.ebwizardry.lightning_wraith_spawn_rate.tooltip=Spawn rate for naturally-spawned lightning wraiths; higher numbers mean more lightning wraiths will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable lightning wraith spawning entirely. +config.ebwizardry.forfeit_chance=Forfeit Chance +config.ebwizardry.forfeit_chance.tooltip=The chance to 'misread' an undiscovered spell and trigger a forfeit instead. Setting this to 0 effectively disables the forfeit mechanic. Has no effect if discovery mode is disabled. +config.ebwizardry.player_damage_scaling=Player Damage Scaling Factor +config.ebwizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. +config.ebwizardry.npc_damage_scaling=NPC Damage Scaling Factor +config.ebwizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. +config.ebwizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist +config.ebwizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). +config.ebwizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist +config.ebwizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). +config.ebwizardry.mind_control_targets_blacklist=Mind Control Targets Blacklist +config.ebwizardry.mind_control_targets_blacklist.tooltip=List of names of entities which cannot be mind controlled, in addition to the defaults. Add creatures to this list if allowing them to be mind-controlled causes problems or could be exploited. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). +config.ebwizardry.pocket_furnace_item_blacklist=Pocket Furnace Item Blacklist +config.ebwizardry.pocket_furnace_item_blacklist.tooltip=List of registry names of blocks or items which cannot be smelted by the pocket furnace spell, in addition to armour, tools and weapons. Block/item names are not case sensitive. For mod items, prefix with the mod ID (e.g. ebwizardry\:crystal_ore). +config.ebwizardry.divination_ore_whitelist=Divination Ore Whitelist +config.ebwizardry.divination_ore_whitelist.tooltip=List of registry names of ore blocks which can be detected by the divination spell. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. ebwizardry\:crystal_ore). +config.ebwizardry.sword_item_whitelist=Sword Item Whitelist +config.ebwizardry.sword_item_whitelist.tooltip=List of registry names of items which should count as swords for imbuement spells. Most swords should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:broadsword). +config.ebwizardry.bow_item_whitelist=Bow Item Whitelist +config.ebwizardry.bow_item_whitelist.tooltip=List of registry names of items which should count as bows for imbuement spells. Most bows should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:shortbow). +config.ebwizardry.currency_items=Currency Items +config.ebwizardry.currency_items.tooltip=List of registry names of items which wizard trades can use as currency (in the first slot; the second slot is unaffected). Each entry in this list should consist of an item registry name, followed by a single space, then an integer which defines the 'value' of the item. Higher values mean fewer of that currency item are required for a given trade. + config.ebwizardry.category.worldgen=World Generation Settings config.ebwizardry.category.worldgen.tooltip=Configure wizardry's world generation features config.ebwizardry.title.worldgen=World Generation Settings config.ebwizardry.subtitle.worldgen=Settings that affect world generation. -config.ebwizardry.category.commands=Command Settings -config.ebwizardry.category.commands.tooltip=Configure wizardry's commands -config.ebwizardry.title.commands=Command Settings -config.ebwizardry.subtitle.commands=Settings for the commands added by Wizardry. +config.ebwizardry.fast_worldgen=Structure Generation +config.ebwizardry.fast_worldgen.tooltip=Controls which algorithm wizardry uses for structure generation. Fancy worldgen prevents structures on cliffs, in caves and intersecting other structures, and cleans up floating trees after generating. Fast worldgen sacrifices these improvements, potentially resulting in faster world generation. Performance improvement will vary depending on your setup. This option will affect randomisation; for any given seed, structures will not be the same as when it is turned off. +config.ebwizardry.fast_worldgen.true=Fast +config.ebwizardry.fast_worldgen.false=Fancy +config.ebwizardry.tower_dimensions=Tower Dimensions +config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate. +config.ebwizardry.tower_rarity=Tower Rarity +config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer. +config.ebwizardry.evil_wizard_chance=Evil Wizard Chance +config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard. +config.ebwizardry.tower_files=Tower Structure Files +config.ebwizardry.tower_files.tooltip=List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. +config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files +config.ebwizardry.tower_with_chest_files.tooltip=List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. +config.ebwizardry.obelisk_dimensions=Obelisk Dimensions +config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate. +config.ebwizardry.obelisk_rarity=Obelisk Rarity +config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer. +config.ebwizardry.obelisk_files=Obelisk Structure Files +config.ebwizardry.obelisk_files.tooltip=List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. +config.ebwizardry.shrine_dimensions=Shrine Dimensions +config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate. +config.ebwizardry.shrine_rarity=Shrine Rarity +config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer. +config.ebwizardry.shrine_files=Shrine Structure Files +config.ebwizardry.shrine_files.tooltip=List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. +config.ebwizardry.ore_dimensions=Ore Dimensions +config.ebwizardry.ore_dimensions.tooltip=List of ids of dimensions in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! +config.ebwizardry.flower_dimensions=Flower Dimensions +config.ebwizardry.flower_dimensions.tooltip=List of ids of dimensions in which crystal flowers will generate. +config.ebwizardry.loot_injection_locations=Loot Injection Locations +config.ebwizardry.loot_injection_locations.tooltip=List of loot tables to inject wizardry loot (as specified in loot_tables/chests/dungeon_additions.json) into. config.ebwizardry.category.client=Client Settings config.ebwizardry.category.client.tooltip=Configure wizardry's display and controls config.ebwizardry.title.client=Client Settings config.ebwizardry.subtitle.client=Client-side settings that only affect the local minecraft game. -config.ebwizardry.category.spells=Spell Configuration -config.ebwizardry.category.spells.tooltip=Select which spells are enabled -config.ebwizardry.title.spells=Spell Configuration -config.ebwizardry.subtitle.spells=Set a spell to false to disable it. +config.ebwizardry.shift_scrolling=Shift-scrolling +config.ebwizardry.shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. +config.ebwizardry.reverse_scroll_direction=Scroll Direction +config.ebwizardry.reverse_scroll_direction.tooltip=The scroll direction used to switch between spells on a wand while sneaking. +config.ebwizardry.reverse_scroll_direction.true=Reversed +config.ebwizardry.reverse_scroll_direction.false=Normal +config.ebwizardry.spell_hud_position=Spell HUD Position +config.ebwizardry.spell_hud_position.tooltip=The position of the spell HUD. +config.ebwizardry.spell_hud_skin=Spell HUD Skin +config.ebwizardry.spell_hud_skin.tooltip=Change the look of the spell HUD... +config.ebwizardry.spell_hud_skin.preview=Preview +config.ebwizardry.handbook_progression=Handbook Progression +config.ebwizardry.handbook_progression.tooltip=When enabled, to help guide players through the mod, sections of The Wizard's Handbook are unlocked when a player gains the advancement that triggers them, and are hidden otherwise. When disabled, the entire handbook is readable regardless of advancement progress. The entire handbook is always readable in creative mode. +config.ebwizardry.handbook_progression.true=Yes - teach me, Sensei! +config.ebwizardry.handbook_progression.false=No - I know what I'm doing +config.ebwizardry.books_pause_game=Books Pause Game +config.ebwizardry.books_pause_game.tooltip=Whether opening any of wizardry's books pauses the game in singleplayer. Has no effect on servers or LAN worlds. +config.ebwizardry.books_pause_game.true=Yes - I don't want any distractions! +config.ebwizardry.books_pause_game.false=No - I read to pass the time +config.ebwizardry.summoned_creature_names=Summoned Creature Names +config.ebwizardry.summoned_creature_names.tooltip=Controls whether summoned creatures' names and owners are displayed above their heads. +config.ebwizardry.summoned_creature_names.true=Shown +config.ebwizardry.summoned_creature_names.false=Hidden +config.ebwizardry.use_shaders=Use Custom Shaders +config.ebwizardry.use_shaders.tooltip=Whether to use custom shaders for certain spells. These use the vanilla shader system (like mob spectating shaders) and shouldn't have much of an effect on performance in most cases, but they may conflict with other shaders. +config.ebwizardry.use_shaders.true=Yes - gimme those sweet shaders! +config.ebwizardry.use_shaders.false=No - I'm running this on a potato + +config.ebwizardry.category.commands=Command Settings +config.ebwizardry.category.commands.tooltip=Configure wizardry's commands +config.ebwizardry.title.commands=Command Settings +config.ebwizardry.subtitle.commands=Settings for the commands added by Wizardry. + +config.ebwizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit +config.ebwizardry.cast_command_multiplier_limit.tooltip=Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned! +config.ebwizardry.cast_command_name=Cast Spell Command Name +config.ebwizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. +config.ebwizardry.discoverspell_command_name=Discover Spell Command Name +config.ebwizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. +config.ebwizardry.ally_command_name=Set Ally Command Name +config.ebwizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. +config.ebwizardry.allies_command_name=View Allies Command Name +config.ebwizardry.allies_command_name.tooltip=The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead. config.ebwizardry.category.resistances=Resistance Configuration config.ebwizardry.category.resistances.tooltip=Configure which mobs are immune to different types of magic config.ebwizardry.title.resistances=Resistance Configuration config.ebwizardry.subtitle.resistances=Settings which allow entities to be made immune to certain types of magic. -config.ebwizardry.tower_rarity=Tower Rarity -config.ebwizardry.ore_dimensions=Ore Dimensions -config.ebwizardry.flower_dimensions=Flower Dimensions -config.ebwizardry.tower_dimensions=Tower Dimensions -config.ebwizardry.spell_book_drop_chance=Spell Book Drop Chance -config.ebwizardry.generate_loot=Generate Loot -config.ebwizardry.firebomb_is_craftable=Firebomb Is Craftable -config.ebwizardry.poison_bomb_is_craftable=Poison Bomb Is Craftable -config.ebwizardry.smoke_bomb_is_craftable=Smoke Bomb Is Craftable -config.ebwizardry.use_alternate_scroll_recipe=Use Alternate Scroll Recipe -config.ebwizardry.teleport_through_unbreakable_blocks=Teleport Through Unbreakable Blocks -config.ebwizardry.show_summoned_creature_names=Show Summoned Creature Names -config.ebwizardry.friendly_fire=Friendly Fire -config.ebwizardry.telekinetic_disarmament=Telekinetic Disarmament -config.ebwizardry.discovery_mode=Discovery Mode -config.ebwizardry.enable_shift_scrolling=Enable Shift-scrolling -config.ebwizardry.reverse_scroll_direction=Reverse Scroll Direction -config.ebwizardry.minion_revenge_targeting=Minion Revenge Targeting -config.ebwizardry.player_damage_scaling=Player Damage Scaling Factor -config.ebwizardry.npc_damage_scaling=NPC Damage Scaling Factor -config.ebwizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit -config.ebwizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist -config.ebwizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist -config.ebwizardry.spell_hud_position=Spell HUD Position -config.ebwizardry.spell_hud_skin=Spell HUD Skin -config.ebwizardry.cast_command_name=Cast Spell Command Name -config.ebwizardry.discoverspell_command_name=Discover Spell Command Name -config.ebwizardry.ally_command_name=Set Ally Command Name -config.ebwizardry.allies_command_name=View Allies Command Name -config.ebwizardry.mind_control_targets_blacklist=Mind Control Targets Blacklist -config.ebwizardry.evil_wizard_dimensions=Evil Wizard Dimensions - config.ebwizardry.mobs_immune_to_fire=Mobs Immune To Fire +config.ebwizardry.mobs_immune_to_fire.tooltip=List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). config.ebwizardry.mobs_immune_to_ice=Mobs Immune To Ice +config.ebwizardry.mobs_immune_to_ice.tooltip=List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). config.ebwizardry.mobs_immune_to_lightning=Mobs Immune To Lightning +config.ebwizardry.mobs_immune_to_lightning.tooltip=List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). config.ebwizardry.mobs_immune_to_wither=Mobs Immune To Wither +config.ebwizardry.mobs_immune_to_wither.tooltip=List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). config.ebwizardry.mobs_immune_to_poison=Mobs Immune To Poison +config.ebwizardry.mobs_immune_to_poison.tooltip=List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). -config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely. -config.ebwizardry.ore_dimensions.tooltip=List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! -config.ebwizardry.flower_dimensions.tooltip=List of dimension ids in which crystal flowers will generate. -config.ebwizardry.tower_dimensions.tooltip=List of dimension ids in which wizard towers will generate. -config.ebwizardry.spell_book_drop_chance.tooltip=The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops. -config.ebwizardry.generate_loot.tooltip=Whether to generate wizardry loot in dungeon chests. -config.ebwizardry.firebomb_is_craftable.tooltip=Whether firebombs can be crafted or not. -config.ebwizardry.poison_bomb_is_craftable.tooltip=Whether poison bombs can be crafted or not. -config.ebwizardry.smoke_bomb_is_craftable.tooltip=Whether smoke bombs can be crafted or not. -config.ebwizardry.use_alternate_scroll_recipe.tooltip=Whether to require a magic crystal in the shapeless crafting recipe for blank scrolls. Set to true if another mod adds a conflicting recipe. -config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. -config.ebwizardry.show_summoned_creature_names.tooltip=Whether to show summoned creatures' names and owners above their heads. -config.ebwizardry.friendly_fire.tooltip=Whether to allow players to damage their designated allies using magic. -config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items. -config.ebwizardry.discovery_mode.tooltip=For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false. -config.ebwizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. -config.ebwizardry.reverse_scroll_direction.tooltip=Whether to reverse the scroll direction used to switch between spells on a wand while sneaking. -config.ebwizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge attack their owner if their owner attacks them. -config.ebwizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. -config.ebwizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. -config.ebwizardry.cast_command_multiplier_limit.tooltip=Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned! -config.ebwizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.spell_hud_position.tooltip=The position of the spell HUD. -config.ebwizardry.spell_hud_skin.tooltip=Change the look of the spell HUD... -config.ebwizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. -config.ebwizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. -config.ebwizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. -config.ebwizardry.allies_command_name.tooltip=The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead. -config.ebwizardry.mind_control_targets_blacklist.tooltip=List of names of entities which cannot be mind controlled, in addition to the defaults. Add creatures to this list if allowing them to be mind-controlled causes problems or could be exploited. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.evil_wizard_dimensions.tooltip=List of dimension ids in which evil wizards can spawn. +config.ebwizardry.category.compatibility=Mod Compatibility Settings +config.ebwizardry.category.compatibility.tooltip=Configure how wizardry interacts with other mods +config.ebwizardry.title.compatibility=Mod Compatibility Settings +config.ebwizardry.subtitle.compatibility=Settings that affect how wizardry interacts with other mods -config.ebwizardry.mobs_immune_to_fire.tooltip=List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.mobs_immune_to_ice.tooltip=List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.mobs_immune_to_lightning.tooltip=List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.mobs_immune_to_wither.tooltip=List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.mobs_immune_to_poison.tooltip=List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.damage_source_blacklist=Damage Source Blacklist +config.ebwizardry.damage_source_blacklist.tooltip=List of damage source string identifiers to be ignored when re-applying damage. Case-sensitive. A message will be logged if wizardry detects a damage source that should be added to this list. Otherwise, don't change unless instructed to do so. +config.ebwizardry.compatibility_warnings=Compatibility Warnings +config.ebwizardry.compatibility_warnings.tooltip=Whether to print compatibility warnings to the console. Set to false if excessive messages are being printed. +config.ebwizardry.baubles_integration=Baubles Integration +config.ebwizardry.baubles_integration.tooltip=If Baubles is installed, controls whether Baubles integration features are enabled. If this is disabled, wizardry will always behave as if Baubles is not installed. +config.ebwizardry.jei_integration=JEI Integration +config.ebwizardry.jei_integration.tooltip=If JEI (Just Enough Items) is installed, controls whether JEI integration features are enabled. If this is disabled, wizardry will always behave as if JEI is not installed. +config.ebwizardry.antique_atlas_integration=Antique Atlas Integration +config.ebwizardry.antique_atlas_integration.tooltip=If Antique Atlas is installed, controls whether Antique Atlas integration features are enabled. If this is disabled, wizardry will always behave as if Antique Atlas is not installed. +config.ebwizardry.auto_place_tower_markers=Auto-Place Tower Markers +config.ebwizardry.auto_place_tower_markers.tooltip=Controls whether wizardry automatically places antique atlas markers at the locations of wizard towers. +config.ebwizardry.auto_place_obelisk_markers=Auto-Place Obelisk Markers +config.ebwizardry.auto_place_obelisk_markers.tooltip=Controls whether wizardry automatically places antique atlas markers at the locations of obelisks. +config.ebwizardry.auto_place_shrine_markers=Auto-Place Shrine Markers +config.ebwizardry.auto_place_shrine_markers.tooltip=Controls whether wizardry automatically places antique atlas markers at the locations of shrines. + +integration.jei.category.ebwizardry\:arcane_workbench=Arcane Workbench + +integration.antiqueatlas.marker.ebwizardry\:wizard_tower=Wizard Tower +integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk +integration.antiqueatlas.marker.ebwizardry\:shrine=Shrine wizard.debug=%1$s, %2$s, %3$s diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang index a7acb7fb..bcc6666f 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_us.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang @@ -1,285 +1,515 @@ -tile.ebwizardry:arcane_workbench.name=Arcane Workbench -tile.ebwizardry:crystal_ore.name=Crystal Ore -tile.ebwizardry:petrified_stone.name=Petrified Stone -tile.ebwizardry:ice_statue.name=Ice Statue -tile.ebwizardry:crystal_flower.name=Crystal Flower -tile.ebwizardry:snare.name=Snare -tile.ebwizardry:transportation_stone.name=Stone of Transportation -tile.ebwizardry:spectral_block.name=Spectral Block -tile.ebwizardry:crystal_block.name=Block of Crystal +#PARSE_ESCAPES +tile.ebwizardry\:arcane_workbench.name=Arcane Workbench +tile.ebwizardry\:crystal_ore.name=Crystal Ore +tile.ebwizardry\:petrified_stone.name=Petrified Stone +tile.ebwizardry\:ice_statue.name=Ice Statue +tile.ebwizardry\:crystal_flower.name=Crystal Flower +tile.ebwizardry\:snare.name=Snare +tile.ebwizardry\:transportation_stone.name=Stone of Transportation +tile.ebwizardry\:transportation_stone.confirm=You will now be returned here upon casting %1$s +tile.ebwizardry\:transportation_stone.remember=Remembered the location %s, %s, %s in dimension %s +tile.ebwizardry\:transportation_stone.forget=Forgot the location %s, %s, %s in dimension %s +tile.ebwizardry\:transportation_stone.invalid=You must make a circle with 8 stones of transportation first! +tile.ebwizardry\:spectral_block.name=Spectral Block +tile.ebwizardry\:runestone.name=Runestone +tile.ebwizardry\:runestone_pedestal.name=Runestone Pedestal +tile.ebwizardry\:thorns.name=Thorns +tile.ebwizardry\:obsidian_crust.name=Obsidian Crust +tile.ebwizardry\:dry_frosted_ice.name=Dry Frosted Ice -item.ebwizardry:magic_crystal.name=Magic Crystal -item.ebwizardry:magic_wand.name=Magic Wand -item.ebwizardry:apprentice_wand.name=Apprentice Wand -item.ebwizardry:advanced_wand.name=Advanced Wand -item.ebwizardry:master_wand.name=Master Wand -item.ebwizardry:spell_book.name=Spell Book +tile.ebwizardry\:magic_crystal_block.name=Block of Crystal +tile.ebwizardry\:fire_crystal_block.name=Block of Fiery Crystal +tile.ebwizardry\:ice_crystal_block.name=Block of Icy Crystal +tile.ebwizardry\:lightning_crystal_block.name=Block of Stormy Crystal +tile.ebwizardry\:necromancy_crystal_block.name=Block of Dark Crystal +tile.ebwizardry\:earth_crystal_block.name=Block of Verdant Crystal +tile.ebwizardry\:sorcery_crystal_block.name=Block of Mystical Crystal +tile.ebwizardry\:healing_crystal_block.name=Block of Radiant Crystal -item.ebwizardry:spell_book.apply_to_wizard=Replaced %1$s's spell %2$s with %3$s +item.ebwizardry\:crystal_magic.name=Magic Crystal +item.ebwizardry\:crystal_fire.name=Fiery Crystal +item.ebwizardry\:crystal_ice.name=Icy Crystal +item.ebwizardry\:crystal_lightning.name=Stormy Crystal +item.ebwizardry\:crystal_necromancy.name=Dark Crystal +item.ebwizardry\:crystal_earth.name=Verdant Crystal +item.ebwizardry\:crystal_sorcery.name=Mystical Crystal +item.ebwizardry\:crystal_healing.name=Radiant Crystal -item.ebwizardry:arcane_tome.name=Tome of Arcana -item.ebwizardry:arcane_tome.desc1=Upgrades any %1$s -item.ebwizardry:arcane_tome.desc2=wand to %1$s tier +item.ebwizardry\:magic_wand.name=Magic Wand +item.ebwizardry\:apprentice_wand.name=Apprentice Wand +item.ebwizardry\:advanced_wand.name=Advanced Wand +item.ebwizardry\:master_wand.name=Master Wand +item.ebwizardry\:spell_book.name=Spell Book -item.ebwizardry:wizard_handbook.name=The Wizard's Handbook -item.ebwizardry:wizard_handbook.desc=by %1$s +item.ebwizardry\:spell_book.apply_to_wizard=Replaced %1$s's spell %2$s with %3$s -item.ebwizardry:wand.buff=+%1$s %2$s potency -item.ebwizardry:wand.spell=Current Spell: %1$s -item.ebwizardry:wand.mana=Mana: %1$s/%2$s +item.ebwizardry\:arcane_tome.name=Tome of Arcana +item.ebwizardry\:arcane_tome.desc1=Upgrades any %1$s +item.ebwizardry\:arcane_tome.desc2=wand to %1$s tier -item.ebwizardry:wand.addally=%1$s has been added to your list of allies -item.ebwizardry:wand.removeally=%1$s has been removed from your list of allies +item.ebwizardry\:wizard_handbook.name=The Wizard's Handbook +item.ebwizardry\:wizard_handbook.desc=by %1$s -item.ebwizardry:basic_fire_wand.name=Wand of Embers -item.ebwizardry:basic_ice_wand.name=Wand of Frost -item.ebwizardry:basic_lightning_wand.name=Wand of Sparks -item.ebwizardry:basic_necromancy_wand.name=Wand of Shadows -item.ebwizardry:basic_earth_wand.name=Wand of the Forest -item.ebwizardry:basic_sorcery_wand.name=Wand of Mystery -item.ebwizardry:basic_healing_wand.name=Wand of Healing +item.ebwizardry\:wand.generic=wand -item.ebwizardry:apprentice_fire_wand.name=Apprentice Pyromancer Wand -item.ebwizardry:apprentice_ice_wand.name=Apprentice Ice Mage Wand -item.ebwizardry:apprentice_lightning_wand.name=Apprentice Storm Mage Wand -item.ebwizardry:apprentice_necromancy_wand.name=Apprentice Necromancer Wand -item.ebwizardry:apprentice_earth_wand.name=Apprentice Earth Mage Wand -item.ebwizardry:apprentice_sorcery_wand.name=Apprentice Sorcerer Wand -item.ebwizardry:apprentice_healing_wand.name=Apprentice Healer Wand +item.ebwizardry\:wand.buff=+%1$s %2$s potency +item.ebwizardry\:wand.spell=Current Spell\: %1$s +item.ebwizardry\:wand.mana=Mana\: %1$s/%2$s +item.ebwizardry\:wand.progression=Progression\: %1$s/%2$s -item.ebwizardry:advanced_fire_wand.name=Wand of the Pyromancer -item.ebwizardry:advanced_ice_wand.name=Wand of the Ice Mage -item.ebwizardry:advanced_lightning_wand.name=Wand of the Storm Mage -item.ebwizardry:advanced_necromancy_wand.name=Wand of the Necromancer -item.ebwizardry:advanced_earth_wand.name=Wand of the Earth Mage -item.ebwizardry:advanced_sorcery_wand.name=Wand of the Sorcerer -item.ebwizardry:advanced_healing_wand.name=Wand of the Healer +item.ebwizardry\:wand.levelup=%1$s is ready to upgrade to %2$s tier -item.ebwizardry:master_fire_wand.name=Master Pyromancer Wand -item.ebwizardry:master_ice_wand.name=Master Ice Mage Wand -item.ebwizardry:master_lightning_wand.name=Master Storm Mage Wand -item.ebwizardry:master_necromancy_wand.name=Master Necromancer Wand -item.ebwizardry:master_earth_wand.name=Master Earth Mage Wand -item.ebwizardry:master_sorcery_wand.name=Master Sorcerer Wand -item.ebwizardry:master_healing_wand.name=Master Healer Wand +item.ebwizardry\:wand.addally=%1$s has been added to your list of allies +item.ebwizardry\:wand.removeally=%1$s has been removed from your list of allies -item.ebwizardry:spectral_sword.name=Spectral Sword -item.ebwizardry:spectral_pickaxe.name=Spectral Pickaxe -item.ebwizardry:spectral_bow.name=Spectral Bow +item.ebwizardry\:novice_fire_wand.name=Wand of Embers +item.ebwizardry\:novice_ice_wand.name=Wand of Frost +item.ebwizardry\:novice_lightning_wand.name=Wand of Sparks +item.ebwizardry\:novice_necromancy_wand.name=Wand of Shadows +item.ebwizardry\:novice_earth_wand.name=Wand of the Forest +item.ebwizardry\:novice_sorcery_wand.name=Wand of Mystery +item.ebwizardry\:novice_healing_wand.name=Wand of Healing -item.ebwizardry:mana_flask.name=Mana Flask -item.ebwizardry:storage_upgrade.name=Wand Storage Upgrade -item.ebwizardry:siphon_upgrade.name=Wand Siphon Upgrade -item.ebwizardry:condenser_upgrade.name=Wand Condenser Upgrade -item.ebwizardry:range_upgrade.name=Wand Range Upgrade -item.ebwizardry:duration_upgrade.name=Wand Duration Upgrade -item.ebwizardry:cooldown_upgrade.name=Wand Cooldown Upgrade -item.ebwizardry:blast_upgrade.name=Wand Blast Upgrade -item.ebwizardry:attunement_upgrade.name=Wand Attunement Upgrade +item.ebwizardry\:apprentice_fire_wand.name=Apprentice Pyromancer Wand +item.ebwizardry\:apprentice_ice_wand.name=Apprentice Ice Mage Wand +item.ebwizardry\:apprentice_lightning_wand.name=Apprentice Storm Mage Wand +item.ebwizardry\:apprentice_necromancy_wand.name=Apprentice Necromancer Wand +item.ebwizardry\:apprentice_earth_wand.name=Apprentice Earth Mage Wand +item.ebwizardry\:apprentice_sorcery_wand.name=Apprentice Sorcerer Wand +item.ebwizardry\:apprentice_healing_wand.name=Apprentice Healer Wand -item.ebwizardry:flaming_axe.name=Flaming Axe -item.ebwizardry:frost_axe.name=Frost Axe +item.ebwizardry\:advanced_fire_wand.name=Wand of the Pyromancer +item.ebwizardry\:advanced_ice_wand.name=Wand of the Ice Mage +item.ebwizardry\:advanced_lightning_wand.name=Wand of the Storm Mage +item.ebwizardry\:advanced_necromancy_wand.name=Wand of the Necromancer +item.ebwizardry\:advanced_earth_wand.name=Wand of the Earth Mage +item.ebwizardry\:advanced_sorcery_wand.name=Wand of the Sorcerer +item.ebwizardry\:advanced_healing_wand.name=Wand of the Healer -item.ebwizardry:firebomb.name=Firebomb -item.ebwizardry:poison_bomb.name=Poison Bomb -item.ebwizardry:smoke_bomb.name=Smoke Bomb +item.ebwizardry\:master_fire_wand.name=Master Pyromancer Wand +item.ebwizardry\:master_ice_wand.name=Master Ice Mage Wand +item.ebwizardry\:master_lightning_wand.name=Master Storm Mage Wand +item.ebwizardry\:master_necromancy_wand.name=Master Necromancer Wand +item.ebwizardry\:master_earth_wand.name=Master Earth Mage Wand +item.ebwizardry\:master_sorcery_wand.name=Master Sorcerer Wand +item.ebwizardry\:master_healing_wand.name=Master Healer Wand -item.ebwizardry:blank_scroll.name=Blank Scroll -item.ebwizardry:scroll.name=Scroll of %1$s -item.ebwizardry:scroll.undiscovered.name=Scroll "%1$s" -item.ebwizardry:identification_scroll.name=Scroll of Identification -item.ebwizardry:identification_scroll.desc1=%1$sIdentifies an unknown -item.ebwizardry:identification_scroll.desc2=%1$sspell book or scroll -item.ebwizardry:identification_scroll.nothing_to_identify=Nothing to identify! +item.ebwizardry\:spectral_sword.name=Spectral Sword +item.ebwizardry\:spectral_pickaxe.name=Spectral Pickaxe +item.ebwizardry\:spectral_bow.name=Spectral Bow -item.ebwizardry:armour_upgrade.name=Arcane Seal of Protection -item.ebwizardry:armour_upgrade.desc1=%1$sUpgrades any wizard armour -item.ebwizardry:armour_upgrade.desc2=%1$sto make it %2$slegendary +item.ebwizardry\:spectral_sword_upgraded.name=Spectral Sword +item.ebwizardry\:spectral_pickaxe_upgraded.name=Spectral Pickaxe -item.ebwizardry:magic_silk.name=Magical Silk +item.ebwizardry\:small_mana_flask.name=Small Mana Flask +item.ebwizardry\:medium_mana_flask.name=Medium Mana Flask +item.ebwizardry\:large_mana_flask.name=Large Mana Flask -item.ebwizardry:wizard_armour.legendary=Legendary -item.ebwizardry:wizard_armour.buff=-%1$s %2$s cost -item.ebwizardry:wizard_armour.mana=Mana: %1$s/%2$s +item.ebwizardry\:grand_crystal.name=Grand Magic Crystal +item.ebwizardry\:crystal_shard.name=Magic Crystal Shard -item.ebwizardry:wizard_hat.name=Wizard Hat -item.ebwizardry:wizard_robe.name=Wizard Robes -item.ebwizardry:wizard_leggings.name=Wizard Leggings -item.ebwizardry:wizard_boots.name=Wizard Boots +item.ebwizardry\:astral_diamond.name=Astral Diamond -item.ebwizardry:wizard_hat_fire.name=Pyromancer Hat -item.ebwizardry:wizard_robe_fire.name=Pyromancer Robes -item.ebwizardry:wizard_leggings_fire.name=Pyromancer Leggings -item.ebwizardry:wizard_boots_fire.name=Pyromancer Boots +item.ebwizardry\:purifying_elixir.name=Purifying Elixir +item.ebwizardry\:purifying_elixir.desc=Removes curses when consumed -item.ebwizardry:wizard_hat_ice.name=Ice Mage Hat -item.ebwizardry:wizard_robe_ice.name=Ice Mage Robes -item.ebwizardry:wizard_leggings_ice.name=Ice Mage Leggings -item.ebwizardry:wizard_boots_ice.name=Ice Mage Boots +item.ebwizardry\:storage_upgrade.name=Wand Storage Upgrade +item.ebwizardry\:siphon_upgrade.name=Wand Siphon Upgrade +item.ebwizardry\:condenser_upgrade.name=Wand Condenser Upgrade +item.ebwizardry\:range_upgrade.name=Wand Range Upgrade +item.ebwizardry\:duration_upgrade.name=Wand Duration Upgrade +item.ebwizardry\:cooldown_upgrade.name=Wand Cooldown Upgrade +item.ebwizardry\:blast_upgrade.name=Wand Blast Upgrade +item.ebwizardry\:attunement_upgrade.name=Wand Attunement Upgrade +item.ebwizardry\:melee_upgrade.name=Wand Melee Upgrade -item.ebwizardry:wizard_hat_lightning.name=Storm Mage Hat -item.ebwizardry:wizard_robe_lightning.name=Storm Mage Robes -item.ebwizardry:wizard_leggings_lightning.name=Storm Mage Leggings -item.ebwizardry:wizard_boots_lightning.name=Storm Mage Boots +item.ebwizardry\:storage_upgrade.desc=Upgrades the mana capacity of a wand +item.ebwizardry\:siphon_upgrade.desc=Upgrades a wand to extract mana from mobs when killed +item.ebwizardry\:condenser_upgrade.desc=Upgrades a wand to slowly regenerate mana over time +item.ebwizardry\:range_upgrade.desc=Upgrades the effective range of spells cast by a wand +item.ebwizardry\:duration_upgrade.desc=Upgrades the duration of effects cast by a wand +item.ebwizardry\:cooldown_upgrade.desc=Upgrades the spell cooldown speed of a wand +item.ebwizardry\:blast_upgrade.desc=Upgrades the area of effect of spells cast by a wand +item.ebwizardry\:attunement_upgrade.desc=Upgrades the number of spells that can be bound to a wand +item.ebwizardry\:melee_upgrade.desc=Upgrades a wand to use mana to deal more damage to mobs when hit -item.ebwizardry:wizard_hat_necromancy.name=Necromancer Hat -item.ebwizardry:wizard_robe_necromancy.name=Necromancer Robes -item.ebwizardry:wizard_leggings_necromancy.name=Necromancer Leggings -item.ebwizardry:wizard_boots_necromancy.name=Necromancer Boots +item.ebwizardry\:flaming_axe.name=Flaming Axe +item.ebwizardry\:frost_axe.name=Frost Axe -item.ebwizardry:wizard_hat_earth.name=Earth Mage Hat -item.ebwizardry:wizard_robe_earth.name=Earth Mage Robes -item.ebwizardry:wizard_leggings_earth.name=Earth Mage Leggings -item.ebwizardry:wizard_boots_earth.name=Earth Mage Boots +item.ebwizardry\:flaming_axe_upgraded.name=Flaming Axe +item.ebwizardry\:frost_axe_upgraded.name=Frost Axe -item.ebwizardry:wizard_hat_sorcery.name=Sorcerer Hat -item.ebwizardry:wizard_robe_sorcery.name=Sorcerer Robes -item.ebwizardry:wizard_leggings_sorcery.name=Sorcerer Leggings -item.ebwizardry:wizard_boots_sorcery.name=Sorcerer Boots +item.ebwizardry\:firebomb.name=Firebomb +item.ebwizardry\:poison_bomb.name=Poison Bomb +item.ebwizardry\:smoke_bomb.name=Smoke Bomb +item.ebwizardry\:spark_bomb.name=Spark Bomb -item.ebwizardry:wizard_hat_healing.name=Healer Hat -item.ebwizardry:wizard_robe_healing.name=Healer Robes -item.ebwizardry:wizard_leggings_healing.name=Healer Leggings -item.ebwizardry:wizard_boots_healing.name=Healer Boots +item.ebwizardry\:blank_scroll.name=Blank Scroll +item.ebwizardry\:scroll.generic=scroll +item.ebwizardry\:scroll.name=Scroll of %1$s +item.ebwizardry\:scroll.undiscovered.name=Scroll "%1$s" +item.ebwizardry\:identification_scroll.name=Scroll of Identification +item.ebwizardry\:identification_scroll.desc=Identifies an unknown spell book or scroll +item.ebwizardry\:identification_scroll.nothing_to_identify=Nothing to identify! -item.ebwizardry:spawn_wizard.name=Spawn Wizard -item.ebwizardry:spawn_evil_wizard.name=Spawn Evil Wizard +item.ebwizardry\:armour_upgrade.name=Arcane Seal of Protection +item.ebwizardry\:armour_upgrade.desc1=%1$sUpgrades any wizard armour +item.ebwizardry\:armour_upgrade.desc2=%1$sto make it %2$slegendary -item.ebwizardry:spectral_helmet.name=Spectral Helmet -item.ebwizardry:spectral_chestplate.name=Spectral Chestplate -item.ebwizardry:spectral_leggings.name=Spectral Leggings -item.ebwizardry:spectral_boots.name=Spectral Boots +item.ebwizardry\:magic_silk.name=Magical Silk -entity.ebwizardry:summonedcreature.nameplate=%1$s's %2$s -entity.ebwizardry:summonedcreature.nameplate_fallback=Someone's %1$s +item.ebwizardry\:wizard_armour.legendary=Legendary +item.ebwizardry\:wizard_armour.buff=-%1$s %2$s cost +item.ebwizardry\:wizard_armour.mana=Mana\: %1$s/%2$s -entity.ebwizardry:zombie_minion.name=Zombie -entity.ebwizardry:skeleton_minion.name=Skeleton -entity.ebwizardry:spider_minion.name=Spider -entity.ebwizardry:blaze_minion.name=Blaze -entity.ebwizardry:wither_skeleton_minion.name=Wither Skeleton -entity.ebwizardry:ice_wraith.name=Ice Wraith -entity.ebwizardry:lightning_wraith.name=Lightning Wraith -entity.ebwizardry:shadow_wraith.name=Shadow Wraith -entity.ebwizardry:spirit_wolf.name=Spirit Wolf -entity.ebwizardry:spirit_horse.name=Spirit Horse -entity.ebwizardry:ice_giant.name=Ice Giant -entity.ebwizardry:phoenix.name=Phoenix -entity.ebwizardry:wizard.name=Wizard -entity.ebwizardry:magic_slime.name=Magical Slime -entity.ebwizardry:silverfish_minion.name=Silverfish -entity.ebwizardry:storm_elemental.name=Storm Elemental -entity.ebwizardry:evil_wizard.name=Wizard -entity.ebwizardry:decoy.name=Decoy +item.ebwizardry\:wizard_hat.name=Wizard Hat +item.ebwizardry\:wizard_robe.name=Wizard Robes +item.ebwizardry\:wizard_leggings.name=Wizard Leggings +item.ebwizardry\:wizard_boots.name=Wizard Boots -entity.ebwizardry:magic_missile.name=Magic -entity.ebwizardry:arc.name=Magic -entity.ebwizardry:spark_bomb.name=Magic -entity.ebwizardry:ice_shard.name=Magic -entity.ebwizardry:firebomb.name=Magic -entity.ebwizardry:poison_bomb.name=Magic -entity.ebwizardry:force_orb.name=Magic -entity.ebwizardry:spark.name=Magic -entity.ebwizardry:darkness_orb.name=Magic -entity.ebwizardry:fire_sigil.name=Magic -entity.ebwizardry:frost_sigil.name=Magic -entity.ebwizardry:lightning_sigil.name=Magic -entity.ebwizardry:lightning_arrow.name=Magic -entity.ebwizardry:firebolt.name=Magic -entity.ebwizardry:ice_charge.name=Magic -entity.ebwizardry:force_arrow.name=Magic -entity.ebwizardry:dart.name=Magic -entity.ebwizardry:lightning_disc.name=Magic -entity.ebwizardry:thunderbolt.name=Magic -entity.ebwizardry:decay.name=Magic -entity.ebwizardry:ice_lance.name=Magic -entity.ebwizardry:smoke_bomb.name=Magic -entity.ebwizardry:ice_spike.name=Magic +item.ebwizardry\:wizard_hat_fire.name=Pyromancer Hat +item.ebwizardry\:wizard_robe_fire.name=Pyromancer Robes +item.ebwizardry\:wizard_leggings_fire.name=Pyromancer Leggings +item.ebwizardry\:wizard_boots_fire.name=Pyromancer Boots -entity.ebwizardry:black_hole.name=Black Hole -entity.ebwizardry:shield.name=Shield -entity.ebwizardry:meteor.name=Meteor -entity.ebwizardry:blizzard.name=Blizzard -entity.ebwizardry:bubble.name=Bubble -entity.ebwizardry:tornado.name=Tornado -entity.ebwizardry:lightning_hammer.name=Lightning Hammer -entity.ebwizardry:arrow_rain.name=Arrow Rain -entity.ebwizardry:healing_aura.name=Healing Aura -entity.ebwizardry:forcefield.name=Forcefield -entity.ebwizardry:ring_of_fire.name=Ring of Fire -entity.ebwizardry:earthquake.name=Earthquake -entity.ebwizardry:falling_grass.name=Falling Grass -entity.ebwizardry:hailstorm.name=Hailstorm -entity.ebwizardry:lightning_pulse.name=Lightning Pulse +item.ebwizardry\:wizard_hat_ice.name=Ice Mage Hat +item.ebwizardry\:wizard_robe_ice.name=Ice Mage Robes +item.ebwizardry\:wizard_leggings_ice.name=Ice Mage Leggings +item.ebwizardry\:wizard_boots_ice.name=Ice Mage Boots + +item.ebwizardry\:wizard_hat_lightning.name=Storm Mage Hat +item.ebwizardry\:wizard_robe_lightning.name=Storm Mage Robes +item.ebwizardry\:wizard_leggings_lightning.name=Storm Mage Leggings +item.ebwizardry\:wizard_boots_lightning.name=Storm Mage Boots + +item.ebwizardry\:wizard_hat_necromancy.name=Necromancer Hat +item.ebwizardry\:wizard_robe_necromancy.name=Necromancer Robes +item.ebwizardry\:wizard_leggings_necromancy.name=Necromancer Leggings +item.ebwizardry\:wizard_boots_necromancy.name=Necromancer Boots + +item.ebwizardry\:wizard_hat_earth.name=Earth Mage Hat +item.ebwizardry\:wizard_robe_earth.name=Earth Mage Robes +item.ebwizardry\:wizard_leggings_earth.name=Earth Mage Leggings +item.ebwizardry\:wizard_boots_earth.name=Earth Mage Boots + +item.ebwizardry\:wizard_hat_sorcery.name=Sorcerer Hat +item.ebwizardry\:wizard_robe_sorcery.name=Sorcerer Robes +item.ebwizardry\:wizard_leggings_sorcery.name=Sorcerer Leggings +item.ebwizardry\:wizard_boots_sorcery.name=Sorcerer Boots + +item.ebwizardry\:wizard_hat_healing.name=Healer Hat +item.ebwizardry\:wizard_robe_healing.name=Healer Robes +item.ebwizardry\:wizard_leggings_healing.name=Healer Leggings +item.ebwizardry\:wizard_boots_healing.name=Healer Boots + +item.ebwizardry\:spawn_wizard.name=Spawn Wizard +item.ebwizardry\:spawn_evil_wizard.name=Spawn Evil Wizard + +item.ebwizardry\:spectral_helmet.name=Spectral Helmet +item.ebwizardry\:spectral_chestplate.name=Spectral Chestplate +item.ebwizardry\:spectral_leggings.name=Spectral Leggings +item.ebwizardry\:spectral_boots.name=Spectral Boots + +item.ebwizardry\:lightning_hammer.name=Lightning Hammer + +item.ebwizardry\:ring_condensing.name=Ring of Condensing +item.ebwizardry\:ring_condensing.desc=Slowly regenerates mana for all wands on your hotbar +item.ebwizardry\:ring_siphoning.name=Ring of Siphoning +item.ebwizardry\:ring_siphoning.desc=Increases siphoned mana by 30%% +item.ebwizardry\:ring_battlemage.name=Ring of the Battlemage +item.ebwizardry\:ring_battlemage.desc=Holding a wand in your offhand and a sword in your main hand grants 10%% extra magic damage +item.ebwizardry\:ring_combustion.name=Ring of Combustion +item.ebwizardry\:ring_combustion.desc=Creatures killed by fire spells explode +item.ebwizardry\:ring_fire_melee.name=Ring of Fiery Touch +item.ebwizardry\:ring_fire_melee.desc=Hitting a creature with a fire wand sets it on fire +item.ebwizardry\:ring_fire_biome.name=Ring of the Desert Sun +item.ebwizardry\:ring_fire_biome.desc=Fire spells are 30%% more potent in hot biomes +item.ebwizardry\:ring_disintegration.name=Ring of Searing Embers +item.ebwizardry\:ring_disintegration.desc=All fire attack spells cause their victims to disintegrate +item.ebwizardry\:ring_ice_melee.name=Ring of Icy Touch +item.ebwizardry\:ring_ice_melee.desc=Hitting a creature with an ice wand gives it the frostbite effect +item.ebwizardry\:ring_ice_biome.name=Ring of Glaciation +item.ebwizardry\:ring_ice_biome.desc=Ice spells are 30%% more potent in snowy biomes +item.ebwizardry\:ring_arcane_frost.name=Ring of Arcane Frost +item.ebwizardry\:ring_arcane_frost.desc=Creatures killed by ice spells release ice shards in all directions +item.ebwizardry\:ring_shattering.name=Ring of Shattering +item.ebwizardry\:ring_shattering.desc=Melee attacks on mobs with the frostbite effect have a chance to shatter them into ice shards +item.ebwizardry\:ring_lightning_melee.name=Ring of Chaining +item.ebwizardry\:ring_lightning_melee.desc=Hitting a creature with a lightning wand shoots lightning at another nearby creature +item.ebwizardry\:ring_storm.name=Ring of the Gathering Storm +item.ebwizardry\:ring_storm.desc=During thunderstorms, lightning spells have dramatically reduced cooldowns +item.ebwizardry\:ring_seeking.name=Ring of Attraction +item.ebwizardry\:ring_seeking.desc=All projectile spells seek their targets +item.ebwizardry\:ring_hammer.name=Ring of Thalek the Almighty +item.ebwizardry\:ring_hammer.desc=Lightning hammers can be picked up and thrown +item.ebwizardry\:ring_soulbinding.name=Soulwalker's Ring +item.ebwizardry\:ring_soulbinding.desc=Creatures damaged by necromancy spells become soulbound to you +item.ebwizardry\:ring_leeching.name=Ring of Leeching +item.ebwizardry\:ring_leeching.desc=All necromancy attacks have a 30%% chance to trigger a life drain effect +item.ebwizardry\:ring_necromancy_melee.name=Ring of Necrotic Touch +item.ebwizardry\:ring_necromancy_melee.desc=Hitting a creature with a necromancy wand gives it the wither effect +item.ebwizardry\:ring_mind_control.name=Ring of the Psychic +item.ebwizardry\:ring_mind_control.desc=Mind-controlled creatures have a chance to mind control other nearby creatures +item.ebwizardry\:ring_poison.name=Serpentine Ring +item.ebwizardry\:ring_poison.desc=All earth spells poison their target +item.ebwizardry\:ring_earth_melee.name=Ring of Venomous Touch +item.ebwizardry\:ring_earth_melee.desc=Hitting a creature with an earth wand poisons it +item.ebwizardry\:ring_earth_biome.name=Dryad's Ring +item.ebwizardry\:ring_earth_biome.desc=Earth spells are 30%% more potent in forests and roofed forests +item.ebwizardry\:ring_full_moon.name=Ring of the Howling Wolf +item.ebwizardry\:ring_full_moon.desc=Earth spells have dramatically reduced cooldowns under a full moon +item.ebwizardry\:ring_extraction.name=Ring of Extraction +item.ebwizardry\:ring_extraction.desc=Kills with sorcery spells grant bonus mana +item.ebwizardry\:ring_mana_return.name=Ring of the Perfectionist +item.ebwizardry\:ring_mana_return.desc=Force arrows that miss their target return the mana they used to your wand +item.ebwizardry\:ring_blockwrangler.name=Blockwrangler's Ring +item.ebwizardry\:ring_blockwrangler.desc=Thrown blocks deal twice their normal damage +item.ebwizardry\:ring_conjurer.name=Conjurer's Ring +item.ebwizardry\:ring_conjurer.desc=Conjured items last twice as long +item.ebwizardry\:ring_defender.name=Ring of the Defender +item.ebwizardry\:ring_defender.desc=Your projectiles pass through forcefields belonging to you or an ally +item.ebwizardry\:ring_paladin.name=Paladin's Ring +item.ebwizardry\:ring_paladin.desc=When you heal yourself or an ally, nearby allies will also gain some health +item.ebwizardry\:ring_interdiction.name=Ring of Interdiction +item.ebwizardry\:ring_interdiction.desc=Your forcefield damages creatures that touch it + +item.ebwizardry\:amulet_arcane_defence.name=Amulet of Arcane Defense +item.ebwizardry\:amulet_arcane_defence.desc=Slowly regenerates mana for all worn wizard armor +item.ebwizardry\:amulet_warding.name=Amulet of Warding +item.ebwizardry\:amulet_warding.desc=Reduces all incoming magic damage by 10%% +item.ebwizardry\:amulet_wisdom.name=Amulet of Wisdom +item.ebwizardry\:amulet_wisdom.desc=Greatly reduces the chance of negative effects when using undiscovered spells +item.ebwizardry\:amulet_fire_protection.name=Flamefast Amulet +item.ebwizardry\:amulet_fire_protection.desc=Reduces fire damage by 30%% +item.ebwizardry\:amulet_fire_cloaking.name=Amulet of Cloaking Flame +item.ebwizardry\:amulet_fire_cloaking.desc=Reduces incoming damage by 75%% whilst standing within a ring of fire belonging to you or an ally +item.ebwizardry\:amulet_ice_immunity.name=Permafrost Amulet +item.ebwizardry\:amulet_ice_immunity.desc=Grants total immunity to frostbite effects +item.ebwizardry\:amulet_ice_protection.name=Frostbound Amulet +item.ebwizardry\:amulet_ice_protection.desc=Reduces frost damage by 30%% +item.ebwizardry\:amulet_potential.name=Amulet of Potential +item.ebwizardry\:amulet_potential.desc=Grants a 15%% chance to shoot lightning at creatures that melee attack you +item.ebwizardry\:amulet_channeling.name=Amulet of Channeling +item.ebwizardry\:amulet_channeling.desc=Grants a 30%% chance to negate incoming shock damage +item.ebwizardry\:amulet_lich.name=Amulet of the Lich +item.ebwizardry\:amulet_lich.desc=Grants a 15%% chance for incoming damage to be dealt to a nearby minion instead +item.ebwizardry\:amulet_wither_immunity.name=Wither Pearl Amulet +item.ebwizardry\:amulet_wither_immunity.desc=Grants total immunity to wither effects +item.ebwizardry\:amulet_glide.name=Windfeather Amulet +item.ebwizardry\:amulet_glide.desc=Falling more than 3 blocks has a 50%% chance to activate the glide effect +item.ebwizardry\:amulet_banishing.name=Enderbound Amulet +item.ebwizardry\:amulet_banishing.desc=Creatures that melee attack you have a 15%% chance to be teleported to a random nearby location +item.ebwizardry\:amulet_anchoring.name=Amulet of Anchoring +item.ebwizardry\:amulet_anchoring.desc=Grants immunity to being moved by magic +item.ebwizardry\:amulet_recovery.name=Amulet of Recovery +item.ebwizardry\:amulet_recovery.desc=When on less than 50%% health, mana from your armor will be used to heal you over time +item.ebwizardry\:amulet_transience.name=Amulet of Transience +item.ebwizardry\:amulet_transience.desc=Grants a 25%% chance to activate a transience effect when critically wounded +item.ebwizardry\:amulet_resurrection.name=Amulet of the Immortal +item.ebwizardry\:amulet_resurrection.desc=The resurrection spell can be used on yourself from beyond the grave +item.ebwizardry\:amulet_auto_shield.name=Hyeleth's Amulet +item.ebwizardry\:amulet_auto_shield.desc=Grants a 25%% chance to trigger the shield spell for a few seconds when bound to a wand on your hotbar + +item.ebwizardry\:charm_haggler.name=Haggler's Sign +item.ebwizardry\:charm_haggler.desc=Wizards are guaranteed to offer a new trade every time you trade with them +item.ebwizardry\:charm_experience_tome.name=Tome of the Diligent +item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 40%% +item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark +item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar +item.ebwizardry\:charm_lava_walking.name=Nether Ice Core +item.ebwizardry\:charm_lava_walking.desc=Frost step freezes lava to form an obsidian crust +item.ebwizardry\:charm_storm.name=Bottled Thundercloud +item.ebwizardry\:charm_storm.desc=Invoke weather is guaranteed to summon storms +item.ebwizardry\:charm_minion_health.name=Obsidian Zombie Head +item.ebwizardry\:charm_minion_health.desc=Summoned creatures are 25%% stronger +item.ebwizardry\:charm_minion_variants.name=Talisman of Transformation +item.ebwizardry\:charm_minion_variants.desc=Summoned zombies are husks; summoned skeletons are strays +item.ebwizardry\:charm_flight.name=Emerald Beetle Wing +item.ebwizardry\:charm_flight.desc=Flight and Glide are 50%% faster +item.ebwizardry\:charm_growth.name=Crystal Flower Charm +item.ebwizardry\:charm_growth.desc=Growth aura has a 35%% chance to instantly grow crops to fully-grown +item.ebwizardry\:charm_abseiling.name=Enchanted Twine +item.ebwizardry\:charm_abseiling.desc=Holding sneak whilst grappling slowly pays out the line +item.ebwizardry\:charm_silk_touch.name=Moonstone Orb +item.ebwizardry\:charm_silk_touch.desc=Blocks broken with the mine spell always drop themselves +item.ebwizardry\:charm_stop_time.name=Peculiar Pocketwatch +item.ebwizardry\:charm_stop_time.desc=The slow time spell makes time stand still +item.ebwizardry\:charm_light.name=Elevinia's Everburning Lantern +item.ebwizardry\:charm_light.desc=Conjured light sources last forever and may be dispelled by right-clicking with a wand +item.ebwizardry\:charm_transportation.name=Ancient Compass +item.ebwizardry\:charm_transportation.desc=Up to four stone circles may be remembered and selected from when using transportation +item.ebwizardry\:charm_feeding.name=Bottomless Provisions +item.ebwizardry\:charm_feeding.desc=Replenish hunger triggers automatically when bound to a wand on your hotbar + +item.charge_status.full=Full +item.charge_status.almost_full=Almost full +item.charge_status.mostly_full=Mostly full +item.charge_status.half_full=Half full +item.charge_status.mostly_empty=Mostly empty +item.charge_status.almost_empty=Almost empty +item.charge_status.empty=Empty + +entity.ebwizardry\:summonedcreature.nameplate=%1$s's %2$s +entity.ebwizardry\:summonedcreature.nameplate_fallback=Someone's %1$s + +entity.ebwizardry\:wizard.greeting_0=Good day, fellow wanderer. +entity.ebwizardry\:wizard.greeting_1=Greetings, traveller. What brings you here? +entity.ebwizardry\:wizard.greeting_2=Ah, nice to see another person around here. +entity.ebwizardry\:wizard.speech_0=Might I interest you in any spells, perhaps? +entity.ebwizardry\:wizard.speech_1=Magic is everywhere, if you know where to look. +entity.ebwizardry\:wizard.speech_2=There is still much to be learned about the arcane arts, adventurer. +entity.ebwizardry\:wizard.speech_3=Perhaps you have learned something yourself that you wish to share? +entity.ebwizardry\:wizard.speech_4=Studying the arcane is most fascinating, don't you think? +entity.ebwizardry\:wizard.farewell_0=Good luck in your quest, adventurer. +entity.ebwizardry\:wizard.farewell_1=I trust that we will meet again soon, friend. +entity.ebwizardry\:wizard.farewell_2=Goodbye then, traveller. +entity.ebwizardry\:wizard.combat_0=Be gone, foul creatures! +entity.ebwizardry\:wizard.combat_1=Leave me alone, pests! +entity.ebwizardry\:wizard.combat_2=Undead beings are not welcome here, shoo! +entity.ebwizardry\:wizard.combat_3=Away with you, creatures of darkness! +entity.ebwizardry\:wizard.combat_4=This is all I need! Get out of here, monsters! +entity.ebwizardry\:wizard.combat_5=Return to the caves from whence you came, evil creatures! +entity.ebwizardry\:wizard.player_combat_0=You will regret that decision, traveller! +entity.ebwizardry\:wizard.player_combat_1=What do you think you are doing?! +entity.ebwizardry\:wizard.player_combat_2=Only a fool dares to anger a wizard! +entity.ebwizardry\:wizard.player_combat_3=You will pay for your carelessness, adventurer! +entity.ebwizardry\:wizard.player_combat_4=Be ready to defend yourself, villain! +entity.ebwizardry\:wizard.player_combat_5=Prepare to feel my wrath! + +entity.ebwizardry\:zombie_minion.name=Zombie +entity.ebwizardry\:husk_minion.name=Husk +entity.ebwizardry\:skeleton_minion.name=Skeleton +entity.ebwizardry\:stray_minion.name=Stray +entity.ebwizardry\:spider_minion.name=Spider +entity.ebwizardry\:blaze_minion.name=Blaze +entity.ebwizardry\:wither_skeleton_minion.name=Wither Skeleton +entity.ebwizardry\:ice_wraith.name=Ice Wraith +entity.ebwizardry\:lightning_wraith.name=Lightning Wraith +entity.ebwizardry\:shadow_wraith.name=Shadow Wraith +entity.ebwizardry\:spirit_wolf.name=Spirit Wolf +entity.ebwizardry\:spirit_horse.name=Spirit Horse +entity.ebwizardry\:ice_giant.name=Ice Giant +entity.ebwizardry\:phoenix.name=Phoenix +entity.ebwizardry\:wizard.name=Wizard +entity.ebwizardry\:magic_slime.name=Magical Slime +entity.ebwizardry\:silverfish_minion.name=Silverfish +entity.ebwizardry\:storm_elemental.name=Storm Elemental +entity.ebwizardry\:evil_wizard.name=Wizard +entity.ebwizardry\:decoy.name=Decoy +entity.ebwizardry\:vex_minion.name=Vex + +entity.ebwizardry\:magic_missile.name=Magic +entity.ebwizardry\:arc.name=Magic +entity.ebwizardry\:spark_bomb.name=Magic +entity.ebwizardry\:ice_shard.name=Magic +entity.ebwizardry\:firebomb.name=Magic +entity.ebwizardry\:poison_bomb.name=Magic +entity.ebwizardry\:force_orb.name=Magic +entity.ebwizardry\:spark.name=Magic +entity.ebwizardry\:darkness_orb.name=Magic +entity.ebwizardry\:fire_sigil.name=Magic +entity.ebwizardry\:frost_sigil.name=Magic +entity.ebwizardry\:lightning_sigil.name=Magic +entity.ebwizardry\:lightning_arrow.name=Magic +entity.ebwizardry\:firebolt.name=Magic +entity.ebwizardry\:ice_charge.name=Magic +entity.ebwizardry\:force_arrow.name=Magic +entity.ebwizardry\:dart.name=Magic +entity.ebwizardry\:lightning_disc.name=Magic +entity.ebwizardry\:thunderbolt.name=Magic +entity.ebwizardry\:decay.name=Magic +entity.ebwizardry\:ice_lance.name=Magic +entity.ebwizardry\:smoke_bomb.name=Magic +entity.ebwizardry\:ice_spike.name=Magic +entity.ebwizardry\:combustion_rune.name=Magic + +entity.ebwizardry\:black_hole.name=Black Hole +entity.ebwizardry\:shield.name=Shield +entity.ebwizardry\:meteor.name=Meteor +entity.ebwizardry\:blizzard.name=Blizzard +entity.ebwizardry\:bubble.name=Bubble +entity.ebwizardry\:tornado.name=Tornado +entity.ebwizardry\:lightning_hammer.name=Lightning Hammer +entity.ebwizardry\:arrow_rain.name=Arrow Rain +entity.ebwizardry\:healing_aura.name=Healing Aura +entity.ebwizardry\:forcefield.name=Forcefield +entity.ebwizardry\:ring_of_fire.name=Ring of Fire +entity.ebwizardry\:earthquake.name=Earthquake +entity.ebwizardry\:hailstorm.name=Hailstorm +entity.ebwizardry\:lightning_pulse.name=Lightning Pulse itemGroup.ebwizardry=Wizardry itemGroup.ebwizardryspells=Spells +itemGroup.ebwizardrygear=Wizard Gear -advancement.wizardry:root=Wizardry -advancement.wizardry:root.desc=A wizard's journey to mastering the arcane -advancement.wizardry:crystal=A Curious Crystal... -advancement.wizardry:crystal.desc=Mine a magic crystal -advancement.wizardry:arcane_initiate=Arcane Initiate -advancement.wizardry:arcane_initiate.desc=Craft a magic wand with a gold nugget, a stick and a magic crystal -advancement.wizardry:apprentice=Wizard's Apprentice -advancement.wizardry:apprentice.desc=Use a tome of arcana to upgrade your wand -advancement.wizardry:master=Arcane Master -advancement.wizardry:master.desc=Obtain a master wand -advancement.wizardry:all_spells=Mage of All Trades -advancement.wizardry:all_spells.desc=Cast every single spell in the game -advancement.wizardry:wizard_trade=Magic Dealing -advancement.wizardry:wizard_trade.desc=Purchase an item from a wizard -advancement.wizardry:buy_master_spell=Knowledge is Power -advancement.wizardry:buy_master_spell.desc=Purchase a master spell from a wizard -advancement.wizardry:freeze_blaze=Not So Hot Now -advancement.wizardry:freeze_blaze.desc=Freeze a blaze solid -advancement.wizardry:charge_creeper=It's Gonna Blow -advancement.wizardry:charge_creeper.desc='Accidentally' charge a creeper -advancement.wizardry:frankenstein=Frankenstein -advancement.wizardry:frankenstein.desc=Turn a pig into a zombie pigman using the lightning bolt spell -advancement.wizardry:special_upgrade=Arcane Tinkering -advancement.wizardry:special_upgrade.desc=Apply a special upgrade to a wand -advancement.wizardry:craft_flask=It's Magic, Bottled! -advancement.wizardry:craft_flask.desc=Craft a mana flask -advancement.wizardry:elemental=Elemental -advancement.wizardry:elemental.desc=Obtain an elemental wand -advancement.wizardry:armour_set=Now You're a Proper Wizard -advancement.wizardry:armour_set.desc=Craft and equip a full set of wizard armor -advancement.wizardry:legendary=Legendary -advancement.wizardry:legendary.desc=Obtain a piece of legendary wizard armor -advancement.wizardry:self_destruct=That Backfired -advancement.wizardry:self_destruct.desc=Get killed by your own magic -advancement.wizardry:pig_tornado=Not Again... -advancement.wizardry:pig_tornado.desc=Ride a pig into a tornado -advancement.wizardry:jam_wizard=Jamming Session -advancement.wizardry:jam_wizard.desc=Use the arcane jammer spell on a wizard -advancement.wizardry:slime_skeleton=Sticky Situation -advancement.wizardry:slime_skeleton.desc=Engulf a skeleton in slime -advancement.wizardry:anger_wizard=You'll Regret That -advancement.wizardry:anger_wizard.desc=Make a wizard angry -advancement.wizardry:defeat_evil_wizard=Righteousness -advancement.wizardry:defeat_evil_wizard.desc=Defeat an evil wizard -advancement.wizardry:max_out_wand=Fully Equipped -advancement.wizardry:max_out_wand.desc=Apply the maximum number of upgrades to a master wand -advancement.wizardry:element_master=Element Mastery -advancement.wizardry:element_master.desc=Cast all the spells of any element -advancement.wizardry:identify_spell=Arcane Appraisal -advancement.wizardry:identify_spell.desc=Use a scroll of identification to identify a spell book or scroll +advancement.ebwizardry\:root=Wizardry +advancement.ebwizardry\:root.desc=A wizard's journey to mastering the arcane +advancement.ebwizardry\:crystal=A Curious Crystal... +advancement.ebwizardry\:crystal.desc=Mine a magic crystal +advancement.ebwizardry\:arcane_initiate=Arcane Initiate +advancement.ebwizardry\:arcane_initiate.desc=Craft a magic wand with a gold nugget, a stick and a magic crystal -tile.ebwizardry:transportation_stone.confirm=You will now be returned here upon casting %1$s -tile.ebwizardry:transportation_stone.invalid=You must make a circle with 8 stones of transportation first! +advancement.ebwizardry\:apprentice=Wizard's Apprentice +advancement.ebwizardry\:apprentice.desc=Use a tome of arcana to upgrade your wand +advancement.ebwizardry\:special_upgrade=Arcane Tinkering +advancement.ebwizardry\:special_upgrade.desc=Apply a special upgrade to a wand +advancement.ebwizardry\:advanced=Advancing Rapidly +advancement.ebwizardry\:advanced.desc=Upgrade your wand to advanced tier +advancement.ebwizardry\:master=Arcane Master +advancement.ebwizardry\:master.desc=Obtain a master wand +advancement.ebwizardry\:max_out_wand=Fully Equipped +advancement.ebwizardry\:max_out_wand.desc=Apply the maximum number of upgrades to a master wand +advancement.ebwizardry\:all_spells=Mage of All Trades +advancement.ebwizardry\:all_spells.desc=Cast every single spell in the game -container.ebwizardry:arcane_workbench=Arcane Workbench -container.ebwizardry:arcane_workbench.apply=Apply -container.ebwizardry:arcane_workbench.mana=Mana: -container.ebwizardry:arcane_workbench.upgrades=Applied Upgrades: +advancement.ebwizardry\:wizard_tower=Who Lives Here? +advancement.ebwizardry\:wizard_tower.desc=Visit a wizard's tower +advancement.ebwizardry\:wizard_trade=Magic Dealing +advancement.ebwizardry\:wizard_trade.desc=Purchase an item from a wizard +advancement.ebwizardry\:anger_wizard=You'll Regret That +advancement.ebwizardry\:anger_wizard.desc=Make a wizard angry +advancement.ebwizardry\:defeat_evil_wizard=Righteousness +advancement.ebwizardry\:defeat_evil_wizard.desc=Defeat an evil wizard +advancement.ebwizardry\:buy_master_spell=Knowledge is Power +advancement.ebwizardry\:buy_master_spell.desc=Purchase a master spell from a wizard -tier.basic=Novice +advancement.ebwizardry\:discover_spell=Trial And Error +advancement.ebwizardry\:discover_spell.desc=Identify an unknown spell by casting it and seeing what happens +advancement.ebwizardry\:identify_spell=Arcane Appraisal +advancement.ebwizardry\:identify_spell.desc=Find a more reliable way of identifying spells +advancement.ebwizardry\:spell_failure=That Backfired +advancement.ebwizardry\:spell_failure.desc=Find out the hard way how spells can go wrong +advancement.ebwizardry\:discover_master_spell=Dicing With Danger +advancement.ebwizardry\:discover_master_spell.desc=Successfully identify a master spell by trial and error + +advancement.ebwizardry\:visit_shrine=Enshrined +advancement.ebwizardry\:visit_shrine.desc=Enter a shrine and awaken its ancient magic +advancement.ebwizardry\:artefact=A Forgotten Relic +advancement.ebwizardry\:artefact.desc=Lift the protective enchantments from a shrine and claim the treasures within +advancement.ebwizardry\:all_artefacts=A Veritable Museum +advancement.ebwizardry\:all_artefacts.desc=Collect all of the rings, amulets and charms + +advancement.ebwizardry\:armour_set=Now You're a Proper Wizard +advancement.ebwizardry\:armour_set.desc=Craft and equip a full set of wizard armor +advancement.ebwizardry\:legendary=Legendary +advancement.ebwizardry\:legendary.desc=Obtain a piece of legendary wizard armor + +advancement.ebwizardry\:enchant_scroll=Scroll Up! +advancement.ebwizardry\:enchant_scroll.desc=Craft a blank scroll and enchant it with a spell at an arcane workbench + +handbook.toast.title=New Handbook Section Unlocked! + +container.ebwizardry\:arcane_workbench=Arcane Workbench +container.ebwizardry\:arcane_workbench.apply=Apply +container.ebwizardry\:arcane_workbench.mana=Mana\: +container.ebwizardry\:arcane_workbench.upgrades=Applied Upgrades\: + +tier.novice=Novice tier.apprentice=Apprentice tier.advanced=Advanced tier.master=Master -element.simple=None +element.magic=None element.fire=Fire element.ice=Ice element.lightning=Lightning @@ -288,7 +518,7 @@ element.earth=Earth element.sorcery=Sorcery element.healing=Healing -element.simple.wizard=Wizard +element.magic.wizard=Wizard element.fire.wizard=Pyromancer element.ice.wizard=Ice Mage element.lightning.wizard=Storm Mage @@ -301,323 +531,477 @@ spelltype.attack=Attack spelltype.defence=Defense spelltype.utility=Utility spelltype.minion=Minion +spelltype.buff=Buff +spelltype.construct=Construct +spelltype.projectile=Projectile +spelltype.alteration=Alteration spell.disabled=%1$s has been disabled in the config spell.resist=%1$s resisted %2$s spell.discover=Discovered the spell %1$s! -spell.ebwizardry:agility=Agility -spell.ebwizardry:arc=Arc -spell.ebwizardry:arcane_jammer=Arcane Jammer -spell.ebwizardry:arrow_rain=Arrow Rain -spell.ebwizardry:banish=Banish -spell.ebwizardry:black_hole=Black Hole -spell.ebwizardry:blink=Blink -spell.ebwizardry:blizzard=Blizzard -spell.ebwizardry:bubble=Bubble -spell.ebwizardry:chain_lightning=Chain Lightning -spell.ebwizardry:clairvoyance=Clairvoyance -spell.ebwizardry:cobwebs=Cobwebs -spell.ebwizardry:conjure_armour=Conjure Armor -spell.ebwizardry:conjure_bow=Conjure Bow -spell.ebwizardry:conjure_pickaxe=Conjure Pickaxe -spell.ebwizardry:conjure_sword=Conjure Sword -spell.ebwizardry:cure_effects=Cure Effects -spell.ebwizardry:curse_of_soulbinding=Curse of Soulbinding -spell.ebwizardry:darkness_orb=Darkness Orb -spell.ebwizardry:darkvision=Darkvision -spell.ebwizardry:dart=Dart -spell.ebwizardry:decay=Decay -spell.ebwizardry:decoy=Decoy -spell.ebwizardry:detonate=Detonate -spell.ebwizardry:diamondflesh=Diamondflesh -spell.ebwizardry:earthquake=Earthquake -spell.ebwizardry:entrapment=Entrapment -spell.ebwizardry:fireball=Fireball -spell.ebwizardry:firebolt=Firebolt -spell.ebwizardry:firebomb=Firebomb -spell.ebwizardry:fire_resistance=Fire Resistance -spell.ebwizardry:fire_sigil=Fire Sigil -spell.ebwizardry:fireskin=Fireskin -spell.ebwizardry:firestorm=Firestorm -spell.ebwizardry:flame_ray=Flame Ray -spell.ebwizardry:flaming_axe=Flaming Axe -spell.ebwizardry:flaming_weapon=Flaming Weapon -spell.ebwizardry:flight=Flight -spell.ebwizardry:font_of_mana=Font of Mana -spell.ebwizardry:font_of_vitality=Font of Vitality -spell.ebwizardry:force_arrow=Force Arrow -spell.ebwizardry:forcefield=Forcefield -spell.ebwizardry:force_orb=Force Orb -spell.ebwizardry:forests_curse=Forest's Curse -spell.ebwizardry:freeze=Freeze -spell.ebwizardry:freezing_weapon=Freezing Weapon -spell.ebwizardry:frost_axe=Frost Axe -spell.ebwizardry:frost_ray=Frost Ray -spell.ebwizardry:frost_sigil=Frost Sigil -spell.ebwizardry:glide=Glide -spell.ebwizardry:greater_fireball=Greater Fireball -spell.ebwizardry:greater_heal=Greater Heal -spell.ebwizardry:group_heal=Group Heal -spell.ebwizardry:growth_aura=Growth Aura -spell.ebwizardry:hailstorm=Hailstorm -spell.ebwizardry:heal=Heal -spell.ebwizardry:heal_ally=Heal Ally -spell.ebwizardry:healing_aura=Healing Aura -spell.ebwizardry:homing_spark=Homing Spark -spell.ebwizardry:ice_age=Ice Age -spell.ebwizardry:ice_charge=Ice Charge -spell.ebwizardry:ice_lance=Ice Lance -spell.ebwizardry:ice_shard=Ice Shard -spell.ebwizardry:ice_shroud=Ice Shroud -spell.ebwizardry:ice_spikes=Ice Spikes -spell.ebwizardry:ice_statue=Ice Statue -spell.ebwizardry:ignite=Ignite -spell.ebwizardry:imbue_weapon=Imbue Weapon -spell.ebwizardry:intimidate=Intimidate -spell.ebwizardry:invigorating_presence=Invigorating Presence -spell.ebwizardry:invisibility=Invisibility -spell.ebwizardry:invoke_weather=Invoke Weather -spell.ebwizardry:ironflesh=Ironflesh -spell.ebwizardry:leap=Leap -spell.ebwizardry:levitation=Levitation -spell.ebwizardry:life_drain=Life Drain -spell.ebwizardry:light=Light -spell.ebwizardry:lightning_arrow=Lightning Arrow -spell.ebwizardry:lightning_bolt=Lightning Bolt -spell.ebwizardry:lightning_disc=Lightning Disk -spell.ebwizardry:lightning_hammer=Lightning Hammer -spell.ebwizardry:lightning_pulse=Lightning Pulse -spell.ebwizardry:lightning_ray=Lightning Ray -spell.ebwizardry:lightning_sigil=Lightning Sigil -spell.ebwizardry:lightning_web=Lightning Web -spell.ebwizardry:magic_missile=Magic Missile -spell.ebwizardry:metamorphosis=Metamorphosis -spell.ebwizardry:meteor=Meteor -spell.ebwizardry:mind_control=Mind Control -spell.ebwizardry:mind_trick=Mind Trick -spell.ebwizardry:none=[Empty Slot] -spell.ebwizardry:oakflesh=Oakflesh -spell.ebwizardry:petrify=Petrify -spell.ebwizardry:phase_step=Phase Step -spell.ebwizardry:plague_of_darkness=Plague of Darkness -spell.ebwizardry:pocket_furnace=Pocket Furnace -spell.ebwizardry:pocket_workbench=Pocket Workbench -spell.ebwizardry:poison=Poison -spell.ebwizardry:poison_bomb=Poison Bomb -spell.ebwizardry:replenish_hunger=Replenish Hunger -spell.ebwizardry:ring_of_fire=Ring of Fire -spell.ebwizardry:shadow_ward=Shadow Ward -spell.ebwizardry:shield=Shield -spell.ebwizardry:shockwave=Shockwave -spell.ebwizardry:silverfish_swarm=Silverfish Swarm -spell.ebwizardry:sixth_sense=Sixth Sense -spell.ebwizardry:slime=Slime -spell.ebwizardry:smoke_bomb=Smoke Bomb -spell.ebwizardry:snare=Snare -spell.ebwizardry:snowball=Snowball -spell.ebwizardry:spark_bomb=Spark Bomb -spell.ebwizardry:spectral_pathway=Spectral Pathway -spell.ebwizardry:spider_swarm=Spider Swarm -spell.ebwizardry:static_aura=Static Aura -spell.ebwizardry:summon_blaze=Summon Blaze -spell.ebwizardry:summon_ice_giant=Summon Ice Giant -spell.ebwizardry:summon_ice_wraith=Summon Ice Wraith -spell.ebwizardry:summon_iron_golem=Summon Iron Golem -spell.ebwizardry:summon_lightning_wraith=Summon Lightning Wraith -spell.ebwizardry:summon_phoenix=Summon Phoenix -spell.ebwizardry:summon_shadow_wraith=Summon Shadow Wraith -spell.ebwizardry:summon_skeleton=Summon Skeleton -spell.ebwizardry:summon_skeleton_legion=Summon Skeleton Legion -spell.ebwizardry:summon_snow_golem=Summon Snow Golem -spell.ebwizardry:summon_spirit_horse=Summon Spirit Horse -spell.ebwizardry:summon_spirit_wolf=Summon Spirit Wolf -spell.ebwizardry:summon_storm_elemental=Summon Storm Elemental -spell.ebwizardry:summon_wither_skeleton=Summon Wither Skeleton -spell.ebwizardry:summon_zombie=Summon Zombie -spell.ebwizardry:telekinesis=Telekinesis -spell.ebwizardry:thunderbolt=Thunderbolt -spell.ebwizardry:thunderstorm=Thunderstorm -spell.ebwizardry:tornado=Tornado -spell.ebwizardry:transience=Transience -spell.ebwizardry:transportation=Transportation -spell.ebwizardry:vanishing_box=Vanishing Box -spell.ebwizardry:wall_of_frost=Wall of Frost -spell.ebwizardry:water_breathing=Water Breathing -spell.ebwizardry:whirlwind=Whirlwind -spell.ebwizardry:wither=Wither -spell.ebwizardry:wither_skull=Wither Skull +spell.ebwizardry\:agility=Agility +spell.ebwizardry\:arc=Arc +spell.ebwizardry\:arcane_jammer=Arcane Jammer +spell.ebwizardry\:arcane_lock=Arcane Lock +spell.ebwizardry\:arrow_rain=Arrow Rain +spell.ebwizardry\:banish=Banish +spell.ebwizardry\:black_hole=Black Hole +spell.ebwizardry\:blink=Blink +spell.ebwizardry\:blizzard=Blizzard +spell.ebwizardry\:bubble=Bubble +spell.ebwizardry\:chain_lightning=Chain Lightning +spell.ebwizardry\:charge=Charge +spell.ebwizardry\:clairvoyance=Clairvoyance +spell.ebwizardry\:cobwebs=Cobwebs +spell.ebwizardry\:combustion_rune=Combustion Rune +spell.ebwizardry\:conjure_armour=Conjure Armor +spell.ebwizardry\:conjure_block=Conjure Block +spell.ebwizardry\:conjure_bow=Conjure Bow +spell.ebwizardry\:conjure_pickaxe=Conjure Pickaxe +spell.ebwizardry\:conjure_sword=Conjure Sword +spell.ebwizardry\:containment=Containment +spell.ebwizardry\:cure_effects=Cure Effects +spell.ebwizardry\:curse_of_enfeeblement=Curse of Enfeeblement +spell.ebwizardry\:curse_of_soulbinding=Curse of Soulbinding +spell.ebwizardry\:curse_of_undeath=Curse of Undeath +spell.ebwizardry\:darkness_orb=Darkness Orb +spell.ebwizardry\:darkvision=Darkvision +spell.ebwizardry\:dart=Dart +spell.ebwizardry\:decay=Decay +spell.ebwizardry\:decoy=Decoy +spell.ebwizardry\:detonate=Detonate +spell.ebwizardry\:diamondflesh=Diamondflesh +spell.ebwizardry\:disintegration=Disintegration +spell.ebwizardry\:divination=Divination +spell.ebwizardry\:dragon_fireball=Dragon Fireball +spell.ebwizardry\:earthquake=Earthquake +spell.ebwizardry\:empowering_presence=Empowering Presence +spell.ebwizardry\:entrapment=Entrapment +spell.ebwizardry\:evade=Evade +spell.ebwizardry\:fireball=Fireball +spell.ebwizardry\:firebolt=Firebolt +spell.ebwizardry\:firebomb=Firebomb +spell.ebwizardry\:fire_resistance=Fire Resistance +spell.ebwizardry\:fire_sigil=Fire Sigil +spell.ebwizardry\:fireskin=Fireskin +spell.ebwizardry\:fire_breath=Fire Breath +spell.ebwizardry\:flame_ray=Flame Ray +spell.ebwizardry\:flaming_axe=Flaming Axe +spell.ebwizardry\:flaming_weapon=Flaming Weapon +spell.ebwizardry\:flight=Flight +spell.ebwizardry\:font_of_mana=Font of Mana +spell.ebwizardry\:font_of_vitality=Font of Vitality +spell.ebwizardry\:force_arrow=Force Arrow +spell.ebwizardry\:forcefield=Forcefield +spell.ebwizardry\:force_orb=Force Orb +spell.ebwizardry\:forests_curse=Forest's Curse +spell.ebwizardry\:forest_of_thorns=Forest of Thorns +spell.ebwizardry\:freeze=Freeze +spell.ebwizardry\:freezing_weapon=Freezing Weapon +spell.ebwizardry\:frost_axe=Frost Axe +spell.ebwizardry\:frost_ray=Frost Ray +spell.ebwizardry\:frost_sigil=Frost Sigil +spell.ebwizardry\:frost_step=Frost Step +spell.ebwizardry\:glide=Glide +spell.ebwizardry\:grapple=Grapple +spell.ebwizardry\:greater_fireball=Greater Fireball +spell.ebwizardry\:greater_heal=Greater Heal +spell.ebwizardry\:greater_telekinesis=Greater Telekinesis +spell.ebwizardry\:greater_ward=Greater Ward +spell.ebwizardry\:group_heal=Group Heal +spell.ebwizardry\:growth_aura=Growth Aura +spell.ebwizardry\:hailstorm=Hailstorm +spell.ebwizardry\:heal=Heal +spell.ebwizardry\:heal_ally=Heal Ally +spell.ebwizardry\:healing_aura=Healing Aura +spell.ebwizardry\:homing_spark=Homing Spark +spell.ebwizardry\:iceball=Iceball +spell.ebwizardry\:ice_age=Ice Age +spell.ebwizardry\:ice_charge=Ice Charge +spell.ebwizardry\:ice_lance=Ice Lance +spell.ebwizardry\:ice_shard=Ice Shard +spell.ebwizardry\:ice_shroud=Ice Shroud +spell.ebwizardry\:ice_spikes=Ice Spikes +spell.ebwizardry\:ice_statue=Ice Statue +spell.ebwizardry\:ignite=Ignite +spell.ebwizardry\:imbue_weapon=Imbue Weapon +spell.ebwizardry\:intimidate=Intimidate +spell.ebwizardry\:invigorating_presence=Invigorating Presence +spell.ebwizardry\:invisibility=Invisibility +spell.ebwizardry\:invoke_weather=Invoke Weather +spell.ebwizardry\:ironflesh=Ironflesh +spell.ebwizardry\:leap=Leap +spell.ebwizardry\:levitation=Levitation +spell.ebwizardry\:life_drain=Life Drain +spell.ebwizardry\:light=Light +spell.ebwizardry\:lightning_arrow=Lightning Arrow +spell.ebwizardry\:lightning_bolt=Lightning Bolt +spell.ebwizardry\:lightning_disc=Lightning Disk +spell.ebwizardry\:lightning_hammer=Lightning Hammer +spell.ebwizardry\:lightning_pulse=Lightning Pulse +spell.ebwizardry\:lightning_ray=Lightning Ray +spell.ebwizardry\:lightning_sigil=Lightning Sigil +spell.ebwizardry\:lightning_web=Lightning Web +spell.ebwizardry\:magic_missile=Magic Missile +spell.ebwizardry\:metamorphosis=Metamorphosis +spell.ebwizardry\:meteor=Meteor +spell.ebwizardry\:mind_control=Mind Control +spell.ebwizardry\:mind_trick=Mind Trick +spell.ebwizardry\:mine=Mine +spell.ebwizardry\:muffle=Muffle +spell.ebwizardry\:none=[Empty Slot] +spell.ebwizardry\:oakflesh=Oakflesh +spell.ebwizardry\:paralysis=Paralysis +spell.ebwizardry\:petrify=Petrify +spell.ebwizardry\:phase_step=Phase Step +spell.ebwizardry\:plague_of_darkness=Plague of Darkness +spell.ebwizardry\:pocket_furnace=Pocket Furnace +spell.ebwizardry\:pocket_workbench=Pocket Workbench +spell.ebwizardry\:poison=Poison +spell.ebwizardry\:poison_bomb=Poison Bomb +spell.ebwizardry\:possession=Possession +spell.ebwizardry\:ray_of_purification=Ray of Purification +spell.ebwizardry\:remove_curse=Remove Curse +spell.ebwizardry\:replenish_hunger=Replenish Hunger +spell.ebwizardry\:resurrection=Resurrection +spell.ebwizardry\:reversal=Reversal +spell.ebwizardry\:ring_of_fire=Ring of Fire +spell.ebwizardry\:satiety=Satiety +spell.ebwizardry\:shadow_ward=Shadow Ward +spell.ebwizardry\:shield=Shield +spell.ebwizardry\:shockwave=Shockwave +spell.ebwizardry\:shulker_bullet=Shulker Bullet +spell.ebwizardry\:silverfish_swarm=Silverfish Swarm +spell.ebwizardry\:sixth_sense=Sixth Sense +spell.ebwizardry\:slime=Slime +spell.ebwizardry\:slow_time=Slow Time +spell.ebwizardry\:smoke_bomb=Smoke Bomb +spell.ebwizardry\:snare=Snare +spell.ebwizardry\:snowball=Snowball +spell.ebwizardry\:spark_bomb=Spark Bomb +spell.ebwizardry\:spectral_pathway=Spectral Pathway +spell.ebwizardry\:speed_time=Speed Time +spell.ebwizardry\:spider_swarm=Spider Swarm +spell.ebwizardry\:static_aura=Static Aura +spell.ebwizardry\:summon_blaze=Summon Blaze +spell.ebwizardry\:summon_ice_giant=Summon Ice Giant +spell.ebwizardry\:summon_ice_wraith=Summon Ice Wraith +spell.ebwizardry\:summon_iron_golem=Summon Iron Golem +spell.ebwizardry\:summon_lightning_wraith=Summon Lightning Wraith +spell.ebwizardry\:summon_phoenix=Summon Phoenix +spell.ebwizardry\:summon_shadow_wraith=Summon Shadow Wraith +spell.ebwizardry\:summon_skeleton=Summon Skeleton +spell.ebwizardry\:summon_skeleton_legion=Summon Skeleton Legion +spell.ebwizardry\:summon_snow_golem=Summon Snow Golem +spell.ebwizardry\:summon_spirit_horse=Summon Spirit Horse +spell.ebwizardry\:summon_spirit_wolf=Summon Spirit Wolf +spell.ebwizardry\:summon_storm_elemental=Summon Storm Elemental +spell.ebwizardry\:summon_wither_skeleton=Summon Wither Skeleton +spell.ebwizardry\:summon_zombie=Summon Zombie +spell.ebwizardry\:telekinesis=Telekinesis +spell.ebwizardry\:thunderbolt=Thunderbolt +spell.ebwizardry\:thunderstorm=Thunderstorm +spell.ebwizardry\:tornado=Tornado +spell.ebwizardry\:transience=Transience +spell.ebwizardry\:transportation=Transportation +spell.ebwizardry\:vanishing_box=Vanishing Box +spell.ebwizardry\:vex_swarm=Vex Swarm +spell.ebwizardry\:wall_of_frost=Wall of Frost +spell.ebwizardry\:ward=Ward +spell.ebwizardry\:water_breathing=Water Breathing +spell.ebwizardry\:whirlwind=Whirlwind +spell.ebwizardry\:wither=Wither +spell.ebwizardry\:wither_skull=Wither Skull -spell.ebwizardry:agility.desc=Grants the caster faster movement speed and greater jump height for 30 seconds. -spell.ebwizardry:arc.desc=Fires a spark of lightning at the target. -spell.ebwizardry:arcane_jammer.desc=Prevents the target from using magic for 15 seconds. -spell.ebwizardry:arrow_rain.desc="Archers, fire!" -spell.ebwizardry:banish.desc=Teleports the target against its will to a random location within a certain range. -spell.ebwizardry:black_hole.desc=Tear reality asunder. -spell.ebwizardry:blink.desc=Teleports the caster over a short distance to where they are pointing. -spell.ebwizardry:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed. -spell.ebwizardry:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged. -spell.ebwizardry:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice. -spell.ebwizardry:clairvoyance.desc=Reveals the path to a remembered location. With this spell selected, sneak-right-click on a block to set the location. Cast this spell normally to reveal the path. The path will fade after 90 seconds. -spell.ebwizardry:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken. -spell.ebwizardry:conjure_armour.desc=Creates spectral armor around the caster which offers protection equal to that of iron armor. The armor lasts for 60 seconds. The caster must have an empty armor slot. -spell.ebwizardry:conjure_bow.desc=Creates a spectral bow with unlimited arrows that lasts for 30 seconds. -spell.ebwizardry:conjure_pickaxe.desc=Creates a spectral pickaxe of equal strength to an iron pickaxe that lasts for 30 seconds. -spell.ebwizardry:conjure_sword.desc=Creates a spectral sword of equal strength to an iron sword that lasts for 30 seconds. -spell.ebwizardry:cure_effects.desc=Removes all potion effects currently affecting the caster, good or bad. -spell.ebwizardry:curse_of_soulbinding.desc=Causes the target's soul to be inextricably bound to that of the caster, meaning all damage dealt to the caster is also dealt to the victim. Lasts until either the victim or the caster dies. -spell.ebwizardry:darkness_orb.desc=Fires a slow moving bolt of dark energy in the direction you are pointing, which withers whatever it hits. -spell.ebwizardry:darkvision.desc=Grants the caster night vision for 45 seconds. -spell.ebwizardry:dart.desc=Fires a dart in the direction you are pointing which damages and weakens its target. -spell.ebwizardry:decay.desc=Creates a patch of decay on the ground which infects any creature that touches it, causing lingering damage over time and spreading more decay wherever it walks. -spell.ebwizardry:decoy.desc=Creates an illusory clone of the caster which tricks mobs into attacking it instead. The decoy will vanish after 30 seconds. -spell.ebwizardry:detonate.desc=Causes an explosion where you are pointing, damaging all nearby creatures - including the caster, if they are too close. -spell.ebwizardry:diamondflesh.desc="Your arrows are no match for me!" -spell.ebwizardry:earthquake.desc=A true master of earth magic can move mountains. -spell.ebwizardry:entrapment.desc=Traps the target in a sphere of darkness which pulls it helplessly upwards and continually damages it. -spell.ebwizardry:fireball.desc=Launches a fireball in the direction you are pointing. -spell.ebwizardry:firebolt.desc=Shoots a jet of fire a short distance in front of you. -spell.ebwizardry:firebomb.desc=Lanches a firebomb in the direction you are pointing which explodes on impact, setting targets on fire. -spell.ebwizardry:fire_resistance.desc=Grants the caster fire resistance for 30 seconds. -spell.ebwizardry:fire_sigil.desc=Places a magical fire trap on the ground which damages and sets on fire the creature that triggers it. -spell.ebwizardry:fireskin.desc=Cloaks the caster in flames for 30 seconds, causing anything that attacks them to catch fire. -spell.ebwizardry:firestorm.desc="I am the dragon." -spell.ebwizardry:flame_ray.desc=Creates a stream of flames in the direction you are pointing which sets on fire and continually damages targets. -spell.ebwizardry:flaming_axe.desc=Creates a flaming axe which sets enemies on fire when hit. Lasts for 30 seconds. -spell.ebwizardry:flaming_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of flame, causing it to set fire to its victims. The magic wears off after 45 seconds. -spell.ebwizardry:flight.desc=Soar like an eagle. -spell.ebwizardry:font_of_mana.desc="We were filled with an intense magical energy appearing to emanate from the centre of the..." - Extract from the journal of a forgotten mage; the rest of the page has been burnt away. -spell.ebwizardry:font_of_vitality.desc=It feels amazing. -spell.ebwizardry:force_arrow.desc=Shoots an arrow of force in the direction you are pointing. -spell.ebwizardry:forcefield.desc=Creates a forcefield around the caster which repels creatures and deflects projectiles. -spell.ebwizardry:force_orb.desc=Launches a sphere of force which damages and repels nearby creatures on impact. -spell.ebwizardry:forests_curse.desc="How dare you enter my forest!" -spell.ebwizardry:freeze.desc=Freezes the target for 10 seconds. Will also freeze water and create snow on the ground. -spell.ebwizardry:freezing_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of frost, causing it to freeze its victims. The magic wears off after 45 seconds. -spell.ebwizardry:frost_axe.desc=Creates a frozen axe which freezes enemies when hit. Lasts for 30 seconds. -spell.ebwizardry:frost_ray.desc=Creates a stream of frost in the direction you are pointing which slows and continually damages targets. -spell.ebwizardry:frost_sigil.desc=Places a magical ice trap on the ground which damages and freezes the creature that triggers it. -spell.ebwizardry:glide.desc=Allows the caster to glide downwards while in the air and holding the use item button. -spell.ebwizardry:greater_fireball.desc=Launches a large fireball in the direction you are pointing which explodes on impact. -spell.ebwizardry:greater_heal.desc=Heals the caster by 4 hearts. -spell.ebwizardry:group_heal.desc=Heals the caster and all nearby allies and summoned creatures by 3 hearts. -spell.ebwizardry:growth_aura.desc=Grows all crops near the caster. Also grows tall grass and flowers on grass. -spell.ebwizardry:hailstorm.desc=It was during the great winter of the third age that the ice mages discovered their true power. -spell.ebwizardry:heal.desc=Heals the caster by 2 hearts. -spell.ebwizardry:heal_ally.desc=Heals the target by 2 and a half hearts. -spell.ebwizardry:healing_aura.desc=Creates a zone of healing energy which regenerates the health of any ally inside it. Any undead inside the healing aura will slowly take damage. -spell.ebwizardry:homing_spark.desc=Creates a floating spark which moves towards enemies. -spell.ebwizardry:ice_age.desc="You shall be frozen for an eternity!" -spell.ebwizardry:ice_charge.desc=Launches an ice charge which explodes on impact, freezing nearby creatures and releasing shards in all directions. -spell.ebwizardry:ice_lance.desc=Fires a great spear of ice in the direction you are pointing which overpenetrates targets, damaging and freezing them in the process. -spell.ebwizardry:ice_shard.desc=Fires a shard of ice in the direction you are pointing which damages and slows targets when hit. -spell.ebwizardry:ice_shroud.desc=Creates a shroud of cold around the caster for 30 seconds, causing anything that attacks them to be frozen. -spell.ebwizardry:ice_spikes.desc=Causes razor-sharp ice spikes to rise from the ground where you are pointing, skewering any creatures caught amongst them. -spell.ebwizardry:ice_statue.desc=Freezes the target solid for 20 seconds or until broken out. The target cannot move or do anything while frozen but is also impervious to all damage. -spell.ebwizardry:ignite.desc=Sets the target on fire for 10 seconds. Also works like a flint and steel. -spell.ebwizardry:imbue_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with magic, rendering it more effective. The magic wears off after 45 seconds. -spell.ebwizardry:intimidate.desc=Emits an intimidating growl which causes nearby creatures to run away in fear. Fear stricken creatures will recover after 30 seconds. -spell.ebwizardry:invigorating_presence.desc=Grants the caster and all nearby allies increased strength for 45 seconds. -spell.ebwizardry:invisibility.desc=Makes the caster invisible for 30 seconds. -spell.ebwizardry:invoke_weather.desc=Changes the weather in the world. -spell.ebwizardry:ironflesh.desc=Greatly improves the caster's damage resistance for 30 seconds. -spell.ebwizardry:leap.desc=Causes the caster to jump upwards several blocks and slightly forward. -spell.ebwizardry:levitation.desc=Raises the caster upwards while the use item button is held. Will also negate fall damage if used before hitting the ground. -spell.ebwizardry:life_drain.desc=Creates a stream of withering energy in the direction you are pointing which drains the life of the target and uses it to gradually regenerate your health. -spell.ebwizardry:light.desc=Creates a magical point of light which illuminates the surrounding area. Lasts for 30 seconds. -spell.ebwizardry:lightning_arrow.desc=Shoots an arrow of lightning in the direction you are pointing. -spell.ebwizardry:lightning_bolt.desc=Causes lightning to strike where you are pointing. -spell.ebwizardry:lightning_disc.desc=Sends a disk of lightning flying off in the direction you are pointing, which seeks targets. -spell.ebwizardry:lightning_hammer.desc="I smite you by the wrath of the heavens!" -spell.ebwizardry:lightning_pulse.desc=Charges the ground around the caster with lightning, damaging and repelling nearby creatures. -spell.ebwizardry:lightning_ray.desc=Creates a stream of lightning in the direction you are pointing which continually damages targets. -spell.ebwizardry:lightning_sigil.desc=Places a magical lightning trap on the ground which damages the creature that triggers it and chains lightning to other nearby creatures. -spell.ebwizardry:lightning_web.desc="Focus. Channel the storm in your mind through your wand and unleash its fury." -spell.ebwizardry:magic_missile.desc=Fires a bolt of magical energy in the direction you are pointing. -spell.ebwizardry:metamorphosis.desc=Changes the target into another form. Only works on some creatures. -spell.ebwizardry:meteor.desc=Some wizards just want to see the world burn... -spell.ebwizardry:mind_control.desc=Takes control of the target's mind for 30 seconds, causing it switch sides and fight for the caster instead. Will not work on creatures that are too strong-willed. -spell.ebwizardry:mind_trick.desc=Confuses and disorients the target for 15 seconds, rendering it unable to attack effectively. The effect will be dispelled if the target takes damage. -spell.ebwizardry:none.desc=To get a spell book with the /give command, use metadata: /give [player] ebwizardry:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up). -spell.ebwizardry:oakflesh.desc=Improves the caster's damage resistance for 30 seconds. -spell.ebwizardry:petrify.desc=Turns the target to stone until broken out, with a chance for it to break out when it is dark. The target cannot move or do anything while petrified but is also impervious to all damage. -spell.ebwizardry:phase_step.desc=Teleports the caster through a 1 block thick wall in front of them. Range upgrades will increase the thickness you can teleport through. -spell.ebwizardry:plague_of_darkness.desc=The darkness will consume them all... -spell.ebwizardry:pocket_furnace.desc=Smelts up to 5 smeltable items in the caster's inventory. Items on the hotbar will be smelted first. -spell.ebwizardry:pocket_workbench.desc=Allows the caster to craft items as if they were at a crafting table. -spell.ebwizardry:poison.desc=Fires poison in the direction you are pointing. -spell.ebwizardry:poison_bomb.desc=Lanches a poison bomb in the direction you are pointing which explodes on impact, poisoning nearby creatures. -spell.ebwizardry:replenish_hunger.desc=Replenishes the caster's food level by 6 hunger points. -spell.ebwizardry:ring_of_fire.desc=Creates a ring of fire around the caster, damaging all nearby enemies and setting them on fire. -spell.ebwizardry:shadow_ward.desc=Creates a wall of darkness in front of the caster which causes half of all incoming damage to be inflicted upon the attacker instead. -spell.ebwizardry:shield.desc=Creates a protective barrier of force that blocks projectiles and magic. Also grants the caster a weak resistance effect. -spell.ebwizardry:shockwave.desc=Boom. -spell.ebwizardry:silverfish_swarm.desc="Ahhhh! They're MULTIPLYING!" -spell.ebwizardry:sixth_sense.desc=Allows the caster to sense the locations of nearby creatures, even through walls, for 20 seconds. -spell.ebwizardry:slime.desc=Engulfs the target in slime which slows and continually damages it. The slime bursts after 10 seconds. -spell.ebwizardry:smoke_bomb.desc=Launches a smoke bomb in the direction you are pointing which explodes on impact, releasing smoke and blinding nearby creatures for a short time. -spell.ebwizardry:snare.desc=Sets a trap on the ground which damages and briefly slows the creature that triggers it. -spell.ebwizardry:snowball.desc=Launches a snowball in the direction you are pointing. -spell.ebwizardry:spark_bomb.desc=Launches a shock charge in the direction you are pointing which releases sparks at nearby enemies on impact. -spell.ebwizardry:spectral_pathway.desc=Creates an indestructible magical bridge in front of you which extends for 15 blocks. The bridge vanishes after 60 seconds. -spell.ebwizardry:spider_swarm.desc=Summons a swarm of venomous spiders to fight for you. The spiders will disappear after 30 seconds or if they are killed. -spell.ebwizardry:static_aura.desc=Surrounds the caster with lightning for 30 seconds, firing a spark of lightning at anything that hits them. -spell.ebwizardry:summon_blaze.desc=Summons a blaze to fight for you. The blaze will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_ice_giant.desc="Smash them!" -spell.ebwizardry:summon_ice_wraith.desc=Summons an ice wraith to fight for you. The ice wraith will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_iron_golem.desc=Automatic automated autonomous automaton. -spell.ebwizardry:summon_lightning_wraith.desc=Summons a lightning wraith to fight for you. The lightning wraith will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_phoenix.desc=From the ashes... -spell.ebwizardry:summon_shadow_wraith.desc=Summons a shadow wraith to fight for you. -spell.ebwizardry:summon_skeleton.desc=Summons a skeleton to fight for you. The skeleton will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_skeleton_legion.desc="Rise, undead army!" -spell.ebwizardry:summon_snow_golem.desc=Creates a snow golem to fight for you. Lasts until the snow golem dies. -spell.ebwizardry:summon_spirit_horse.desc=Summons a spirit horse for you to ride. The spirit horse will vanish a short while after it is dismounted, or you can dismiss it by shift-right-clicking on it with any wand. -spell.ebwizardry:summon_spirit_wolf.desc=Summons a spirit wolf companion to fight for you. The spirit wolf will only disappear if it is killed, or you can dismiss it by shift-right-clicking on it with any wand. -spell.ebwizardry:summon_storm_elemental.desc="Storm Elemental: An ancient manifestation of the elements, it can hardly contain the raw power churning within it." - The Wizard's Guide to Arcane Beings, Volume I_i -spell.ebwizardry:summon_wither_skeleton.desc=Summons a wither skeleton to fight for you. The wither skeleton will disappear after 30 seconds or if it is killed. -spell.ebwizardry:summon_zombie.desc=Summons a zombie to fight for you. The zombie will disappear after 30 seconds or if it is killed. -spell.ebwizardry:telekinesis.desc=Moves an item or other small object towards you, or right-clicks the block you are looking at. Can also be used to disarm players. -spell.ebwizardry:thunderbolt.desc=Shoots a bolt of thunder which knocks back targets. -spell.ebwizardry:thunderstorm.desc="Mwahahahahahaha!" -spell.ebwizardry:tornado.desc=Unleashes a tornado in the direction you are pointing which hurls anything in its path skywards. -spell.ebwizardry:transience.desc=Makes the caster transient for 20 seconds. The caster is immune to all damage while transient but cannot break or place blocks or cause any damage. -spell.ebwizardry:transportation.desc=Transports the caster to their remembered stone circle. To use this spell, make a circle of stones of transportation, then right click it with a wand. -spell.ebwizardry:vanishing_box.desc=Grants the caster access to their ender chest storage. -spell.ebwizardry:wall_of_frost.desc=Winter at your fingertips. -spell.ebwizardry:water_breathing.desc=Allows the caster to breathe underwater for 60 seconds. -spell.ebwizardry:whirlwind.desc=Causes the target to be blown upwards and away from you at speed. -spell.ebwizardry:wither.desc=Fires a ray of darkness which withers anything it touches. -spell.ebwizardry:wither_skull.desc=Launches a wither skull in the direction you are pointing. +spell.ebwizardry\:agility.desc=Grants the caster faster movement speed and greater jump height for 30 seconds. +spell.ebwizardry\:arc.desc=Fires a spark of lightning at the target. +spell.ebwizardry\:arcane_jammer.desc=Prevents the target from using magic for 15 seconds. +spell.ebwizardry\:arcane_lock.desc=Creates an impenetrable barrier of force around a container, protecting it from being opened or destroyed. The caster and their allies may still open it, however. +spell.ebwizardry\:arrow_rain.desc="Archers, fire!" +spell.ebwizardry\:banish.desc=Teleports the target against its will to a random locations within a certain range. +spell.ebwizardry\:black_hole.desc=Tear reality asunder. +spell.ebwizardry\:blink.desc=Teleports the caster over a short distance to where they are pointing. +spell.ebwizardry\:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed. +spell.ebwizardry\:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged. +spell.ebwizardry\:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice. +spell.ebwizardry\:charge.desc=Causes the caster to charge rapidly in the direction they are looking, damaging and knocking back anything in their path. +spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered locations. With this spell selected, sneak-right-click on a block to set the locations. Cast this spell normally to reveal the path. The path will fade after 90 seconds. +spell.ebwizardry\:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken. +spell.ebwizardry\:combustion_rune.desc=Places a magical landmine on the ground where you are pointing, which explodes when stepped upon. +spell.ebwizardry\:conjure_armour.desc=Creates spectral armor around the caster which offers protection equal to that of iron armor. The armor lasts for 60 seconds. The caster must have an empty armor slot. +spell.ebwizardry\:conjure_block.desc=Conjures a spectral block where you are pointing. The spectral block disappears after 45 seconds, or you can dispel it by casting this spell at it again. +spell.ebwizardry\:conjure_bow.desc=Creates a spectral bow with unlimited arrows that lasts for 30 seconds. +spell.ebwizardry\:conjure_pickaxe.desc=Creates a spectral pickaxe of equal strength to an iron pickaxe that lasts for 30 seconds. +spell.ebwizardry\:conjure_sword.desc=Creates a spectral sword of equal strength to an iron sword that lasts for 30 seconds. +spell.ebwizardry\:containment.desc=Contains the target to within a short distance of its current position for 20 seconds. +spell.ebwizardry\:cure_effects.desc=Removes all potion effects currently affecting the caster, good or bad. +spell.ebwizardry\:curse_of_enfeeblement.desc="He was suddenly weakened, as if the life had been wrenched from within him." - Testimony of the only person known to have encountered a member of the soulwalker cult and survived. +spell.ebwizardry\:curse_of_soulbinding.desc=Causes the target's soul to be inextricably bound to that of the caster, meaning all damage dealt to the caster is also dealt to the victim. Lasts until either the victim or the caster dies. +spell.ebwizardry\:curse_of_undeath.desc=Curses the target with undeath, causing it to burn in sunlight, like zombies and skeletons. Lasts until the victim dies. Has no effect on undead creatures. +spell.ebwizardry\:darkness_orb.desc=Fires a slow moving bolt of dark energy in the direction you are pointing, which withers whatever it hits. +spell.ebwizardry\:darkvision.desc=Grants the caster night vision for 45 seconds. +spell.ebwizardry\:dart.desc=Fires a dart in the direction you are pointing which damages and weakens its target. +spell.ebwizardry\:decay.desc=Creates a patch of decay on the ground which infects any creature that touches it, causing lingering damage over time and spreading more decay wherever it walks. +spell.ebwizardry\:decoy.desc=Creates an illusory clone of the caster which tricks mobs into attacking it instead. The decoy will vanish after 30 seconds. +spell.ebwizardry\:detonate.desc=Causes an explosion where you are pointing, damaging all nearby creatures - including the caster, if they are too close. +spell.ebwizardry\:diamondflesh.desc="Your arrows are no match for me!" +spell.ebwizardry\:disintegration.desc=Shoots a powerful bolt of flame a short distance in front of you which causes targets to explode into burning embers when killed. Creatures that step on the embers will be set on fire. +spell.ebwizardry\:divination.desc=Guides the caster to nearby ores and resources. Potency will increase the chance of finding more valuable ores. +spell.ebwizardry\:dragon_fireball.desc=Launches an enderdragon fireball in the direction you are pointing, which releases lingering poisonous clouds on impact. +spell.ebwizardry\:earthquake.desc=A true master of earth magic can move mountains. +spell.ebwizardry\:empowering_presence.desc=Grants the caster and nearby allies increased magic damage for 30 seconds. +spell.ebwizardry\:entrapment.desc=Traps the target in a sphere of darkness which pulls it helplessly upwards and continually damages it. +spell.ebwizardry\:evade.desc=Causes the caster to quickly jump sideways to dodge incoming attacks. +spell.ebwizardry\:fireball.desc=Launches a fireball in the direction you are pointing. +spell.ebwizardry\:firebolt.desc=Shoots a jet of fire a short distance in front of you. +spell.ebwizardry\:firebomb.desc=Lanches a firebomb in the direction you are pointing which explodes on impact, setting targets on fire. +spell.ebwizardry\:fire_resistance.desc=Grants the caster fire resistance for 30 seconds. +spell.ebwizardry\:fire_sigil.desc=Places a magical fire trap on the ground which damages and sets on fire the creature that triggers it. +spell.ebwizardry\:fireskin.desc=Cloaks the caster in flames for 30 seconds, causing anything that attacks them to catch fire. +spell.ebwizardry\:fire_breath.desc="I am the dragon." +spell.ebwizardry\:flame_ray.desc=Creates a stream of flames in the direction you are pointing which sets on fire and continually damages targets. +spell.ebwizardry\:flaming_axe.desc=Creates a flaming axe which sets enemies on fire when hit. Lasts for 30 seconds. +spell.ebwizardry\:flaming_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of flame, causing it to set fire to its victims. The magic wears off after 45 seconds. +spell.ebwizardry\:flight.desc=Soar like an eagle. +spell.ebwizardry\:font_of_mana.desc="We were filled with an intense magical energy appearing to emanate from the centre of the..." - Extract from the journal of a forgotten mage; the rest of the page has been burnt away. +spell.ebwizardry\:font_of_vitality.desc=It feels amazing. +spell.ebwizardry\:force_arrow.desc=Shoots an arrow of force in the direction you are pointing. +spell.ebwizardry\:forcefield.desc=Creates a forcefield around the caster which repels creatures and deflects projectiles. +spell.ebwizardry\:force_orb.desc=Launches a sphere of force which damages and repels nearby creatures on impact. +spell.ebwizardry\:forests_curse.desc="How dare you enter my forest!" +spell.ebwizardry\:forest_of_thorns.desc=Amidst the wood lies a hidden glade,\nIn the glade a wizard performs,\nMagical arts of an order untold,\nDeep within the forest of thorns. +spell.ebwizardry\:freeze.desc=Freezes the target for 10 seconds. Will also freeze water and create snow on the ground. +spell.ebwizardry\:freezing_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with the power of frost, causing it to freeze its victims. The magic wears off after 45 seconds. +spell.ebwizardry\:frost_axe.desc=Creates a frozen axe which freezes enemies when hit. Lasts for 30 seconds. +spell.ebwizardry\:frost_ray.desc=Creates a stream of frost in the direction you are pointing which slows and continually damages targets. +spell.ebwizardry\:frost_sigil.desc=Places a magical ice trap on the ground which damages and freezes the creature that triggers it. +spell.ebwizardry\:frost_step.desc=Allows the caster to freeze water as they walk for 30 seconds. +spell.ebwizardry\:grapple.desc=Shoots a magical vine which allows the caster to grapple towards blocks or reel in entities. Release the use item button to let go of the block or entity. +spell.ebwizardry\:glide.desc=Allows the caster to glide downwards while in the air and holding the use item button. +spell.ebwizardry\:greater_fireball.desc=Launches a large fireball in the direction you are pointing which explodes on impact. +spell.ebwizardry\:greater_heal.desc=Heals the caster by 4 hearts. +spell.ebwizardry\:greater_telekinesis.desc=Allows the caster to pick up a block or creature and hold it in the air for as long as the use item button is pressed. Sneaking whilst holding a block or creature will throw it a short distance. +spell.ebwizardry\:greater_ward.desc=Grants the caster a strong shielding effect that greatly reduces incoming magic damage for 30 seconds. +spell.ebwizardry\:group_heal.desc=Heals the caster and all nearby allies and summoned creatures by 3 hearts. +spell.ebwizardry\:growth_aura.desc=Grows all crops near the caster. Also grows tall grass and flowers on grass. +spell.ebwizardry\:hailstorm.desc=It was during the great winter of the third age that the ice mages discovered their true power. +spell.ebwizardry\:heal.desc=Heals the caster by 2 hearts. +spell.ebwizardry\:heal_ally.desc=Heals the target by 2 and a half hearts. +spell.ebwizardry\:healing_aura.desc=Creates a zone of healing energy which regenerates the health of any ally inside it. Any undead inside the healing aura will slowly take damage. +spell.ebwizardry\:homing_spark.desc=Creates a floating spark which moves towards enemies. +spell.ebwizardry\:iceball.desc=Launches an iceball in the direction you are pointing. +spell.ebwizardry\:ice_age.desc="You shall be frozen for an eternity!" +spell.ebwizardry\:ice_charge.desc=Launches an ice charge which explodes on impact, freezing nearby creatures and releasing shards in all directions. +spell.ebwizardry\:ice_lance.desc=Fires a great spear of ice in the direction you are pointing which overpenetrates targets, damaging and freezing them in the process. +spell.ebwizardry\:ice_shard.desc=Fires a shard of ice in the direction you are pointing which damages and slows targets when hit. +spell.ebwizardry\:ice_shroud.desc=Creates a shroud of cold around the caster for 30 seconds, causing anything that attacks them to be frozen. +spell.ebwizardry\:ice_spikes.desc=Causes razor-sharp ice spikes to rise from the ground where you are pointing, skewering any creatures caught amongst them. +spell.ebwizardry\:ice_statue.desc=Freezes the target solid for 20 seconds or until broken out. The target cannot move or do anything while frozen but is also impervious to all damage. +spell.ebwizardry\:ignite.desc=Sets the target on fire for 10 seconds. Also works like a flint and steel. +spell.ebwizardry\:imbue_weapon.desc=Temporarily imbues the first weapon on the caster's hotbar with magic, rendering it more effective. The magic wears off after 45 seconds. +spell.ebwizardry\:intimidate.desc=Emits an intimidating growl which causes nearby creatures to run away in fear. Fear stricken creatures will recover after 30 seconds. +spell.ebwizardry\:invigorating_presence.desc=Grants the caster and all nearby allies increased strength for 45 seconds. +spell.ebwizardry\:invisibility.desc=Makes the caster invisible for 30 seconds. +spell.ebwizardry\:invoke_weather.desc=Changes the weather in the world. +spell.ebwizardry\:ironflesh.desc=Greatly improves the caster's damage resistance for 30 seconds. +spell.ebwizardry\:leap.desc=Causes the caster to jump upwards several blocks and slightly forward. +spell.ebwizardry\:levitation.desc=Raises the caster upwards while the use item button is held. Will also negate fall damage if used before hitting the ground. +spell.ebwizardry\:life_drain.desc=Creates a stream of withering energy in the direction you are pointing which drains the life of the target and uses it to gradually regenerate your health. +spell.ebwizardry\:light.desc=Creates a magical point of light which illuminates the surrounding area. Lasts for 30 seconds. +spell.ebwizardry\:lightning_arrow.desc=Shoots an arrow of lightning in the direction you are pointing. +spell.ebwizardry\:lightning_bolt.desc=Causes lightning to strike where you are pointing. +spell.ebwizardry\:lightning_disc.desc=Sends a disk of lightning flying off in the direction you are pointing, which seeks targets. +spell.ebwizardry\:lightning_hammer.desc="I smite you by the wrath of the heavens!" +spell.ebwizardry\:lightning_pulse.desc=Charges the ground around the caster with lightning, damaging and repelling nearby creatures. +spell.ebwizardry\:lightning_ray.desc=Creates a stream of lightning in the direction you are pointing which continually damages targets. +spell.ebwizardry\:lightning_sigil.desc=Places a magical lightning trap on the ground which damages the creature that triggers it and chains lightning to other nearby creatures. +spell.ebwizardry\:lightning_web.desc="Focus. Channel the storm in your mind through your wand and unleash its fury." +spell.ebwizardry\:magic_missile.desc=Fires a bolt of magical energy in the direction you are pointing. +spell.ebwizardry\:metamorphosis.desc=Changes the target into another form. Only works on some creatures. +spell.ebwizardry\:meteor.desc=Some wizards just want to see the world burn... +spell.ebwizardry\:mind_control.desc=Takes control of the target's mind for 30 seconds, causing it switch sides and fight for the caster instead. Will not work on creatures that are too strong-willed. +spell.ebwizardry\:mind_trick.desc=Confuses and disorients the target for 15 seconds, rendering it unable to attack effectively. The effect will be dispelled if the target takes damage. +spell.ebwizardry\:mine.desc=Breaks the block the caster is looking at. Potency will allow harder blocks to be broken. +spell.ebwizardry\:muffle.desc=Silences any sounds made by the caster for 30 seconds. When muffled, mobs can only detect you when looking towards you. +spell.ebwizardry\:none.desc=To get a spell book with the /give command, use id\: /give [player] ebwizardry\:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up). +spell.ebwizardry\:oakflesh.desc=Improves the caster's damage resistance for 30 seconds. +spell.ebwizardry\:paralysis.desc=Delivers a powerful lightning bolt that paralyses targets for 5 seconds. Paralysed creatures cannot move and will still take damage - but too much will snap the creature out of paralysis. +spell.ebwizardry\:petrify.desc=Turns the target to stone until broken out, with a chance for it to break out when it is dark. The target cannot move or do anything while petrified but is also impervious to all damage. +spell.ebwizardry\:phase_step.desc=Teleports the caster a short distance in front of them, including through walls. Range upgrades will increase the wall thickness you can teleport through. +spell.ebwizardry\:plague_of_darkness.desc=The darkness will consume them all... +spell.ebwizardry\:pocket_furnace.desc=Smelts up to 5 smeltable items in the caster's inventory. Items on the hotbar will be smelted first. +spell.ebwizardry\:pocket_workbench.desc=Allows the caster to craft items as if they were at a crafting table. +spell.ebwizardry\:poison.desc=Fires poison in the direction you are pointing. +spell.ebwizardry\:poison_bomb.desc=Lanches a poison bomb in the direction you are pointing which explodes on impact, poisoning nearby creatures. +spell.ebwizardry\:possession.desc="Become thy enemy." +spell.ebwizardry\:ray_of_purification.desc=Emits a ray of blinding light that damages and blinds its targets. Undead creatures take double damage and are set on fire. +spell.ebwizardry\:remove_curse.desc=Removes any curse currently affecting the caster. +spell.ebwizardry\:replenish_hunger.desc=Replenishes the caster's food level by 4 hunger points. +spell.ebwizardry\:resurrection.desc=With a master healer by your side, being dead is... optional. +spell.ebwizardry\:reversal.desc=Removes a random negative potion effect and inflicts it upon the target, which will suffer that effect for the remaining duration. Potency increases the number of effects that are reversed. +spell.ebwizardry\:ring_of_fire.desc=Creates a ring of fire around the caster, damaging all nearby enemies and setting them on fire. +spell.ebwizardry\:satiety.desc=Replenishes the caster's food level by 8 hunger points. +spell.ebwizardry\:shadow_ward.desc=Creates a wall of darkness in front of the caster which causes half of all incoming damage to be inflicted upon the attacker instead. +spell.ebwizardry\:shield.desc=Creates a protective barrier of force that blocks projectiles and magic. Also grants the caster a weak resistance effect. +spell.ebwizardry\:shockwave.desc=Boom. +spell.ebwizardry\:shulker_bullet.desc=Shoots a shulker bullet which seeks targets and causes them to levitate when hit. +spell.ebwizardry\:silverfish_swarm.desc="Ahhhh! They're MULTIPLYING!" +spell.ebwizardry\:sixth_sense.desc=Allows the caster to sense the locations of nearby creatures, even through walls, for 20 seconds. +spell.ebwizardry\:slime.desc=Engulfs the target in slime which slows and continually damages it. The slime bursts after 10 seconds. +spell.ebwizardry\:slow_time.desc=Chronomancy is the art of manipulating time itself to fit one's needs. It was widely believed to be lost in the past... until now. +spell.ebwizardry\:smoke_bomb.desc=Launches a smoke bomb in the direction you are pointing which explodes on impact, releasing smoke and blinding nearby creatures for a short time. +spell.ebwizardry\:snare.desc=Sets a trap on the ground which damages and briefly slows the creature that triggers it. +spell.ebwizardry\:snowball.desc=Launches a snowball in the direction you are pointing. +spell.ebwizardry\:spark_bomb.desc=Launches a shock charge in the direction you are pointing which releases sparks at nearby enemies on impact. +spell.ebwizardry\:spectral_pathway.desc=Creates an indestructible magical bridge in front of you which extends for 15 blocks. The bridge vanishes after 60 seconds. +spell.ebwizardry\:speed_time.desc=...day, night, dawn, dusk, sunrise and sunset\: thus is the passage of time, which traps us in an endless cycle of... +spell.ebwizardry\:spider_swarm.desc=Summons a swarm of venomous spiders to fight for you. The spiders will disappear after 30 seconds or if they are killed. +spell.ebwizardry\:static_aura.desc=Surrounds the caster with lightning for 30 seconds, firing a spark of lightning at anything that hits them. +spell.ebwizardry\:summon_blaze.desc=Summons a blaze to fight for you. The blaze will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_ice_giant.desc="Smash them!" +spell.ebwizardry\:summon_ice_wraith.desc=Summons an ice wraith to fight for you. The ice wraith will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_iron_golem.desc=Automatic automated autonomous automaton. +spell.ebwizardry\:summon_lightning_wraith.desc=Summons a lightning wraith to fight for you. The lightning wraith will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_phoenix.desc=From the ashes... +spell.ebwizardry\:summon_shadow_wraith.desc=Summons a shadow wraith to fight for you. +spell.ebwizardry\:summon_skeleton.desc=Summons a skeleton to fight for you. The skeleton will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_skeleton_legion.desc="Rise, undead army!" +spell.ebwizardry\:summon_snow_golem.desc=Creates a snow golem to fight for you. Lasts until the snow golem dies. +spell.ebwizardry\:summon_spirit_horse.desc=Summons a spirit horse for you to ride. The spirit horse will vanish a short while after it is dismounted, or you can dismiss it by shift-right-clicking on it with any wand. +spell.ebwizardry\:summon_spirit_wolf.desc=Summons a spirit wolf companion to fight for you. The spirit wolf will only disappear if it is killed, or you can dismiss it by shift-right-clicking on it with any wand. +spell.ebwizardry\:summon_storm_elemental.desc="Storm Elemental\: An ancient manifestation of the elements, it can hardly contain the raw power churning within it." - The Wizard's Guide to Arcane Beings, Volume II +spell.ebwizardry\:summon_wither_skeleton.desc=Summons a wither skeleton to fight for you. The wither skeleton will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:summon_zombie.desc=Summons a zombie to fight for you. The zombie will disappear after 30 seconds or if it is killed. +spell.ebwizardry\:telekinesis.desc=Moves an item or other small object towards you, or right-clicks the block you are looking at. Can also be used to disarm players. +spell.ebwizardry\:thunderbolt.desc=Shoots a bolt of thunder which knocks back targets. +spell.ebwizardry\:thunderstorm.desc="Mwahahahahahaha!" +spell.ebwizardry\:tornado.desc=Unleashes a tornado in the direction you are pointing which hurls anything in its path skywards. +spell.ebwizardry\:transience.desc=Makes the caster transient for 20 seconds. The caster is immune to all damage while transient but cannot break or place blocks or cause any damage. +spell.ebwizardry\:transportation.desc=Transports the caster to their remembered stone circle. To use this spell, make a circle of stones of transportation, then right click it with a wand. +spell.ebwizardry\:vanishing_box.desc=Grants the caster access to their ender chest storage. +spell.ebwizardry\:vex_swarm.desc=Summons a swarm of flying vexes to fight for you. The vexes will disappear after 30 seconds or if they are killed. +spell.ebwizardry\:wall_of_frost.desc=Winter at your fingertips. +spell.ebwizardry\:ward.desc=Grants the caster a shielding effect that reduces incoming magic damage for 30 seconds. +spell.ebwizardry\:water_breathing.desc=Allows the caster to breathe underwater for 60 seconds. +spell.ebwizardry\:whirlwind.desc=Causes the target to be blown upwards and away from you at speed. +spell.ebwizardry\:wither.desc=Fires a ray of darkness which withers anything it touches. +spell.ebwizardry\:wither_skull.desc=Launches a wither skull in the direction you are pointing. -spell.ebwizardry:invoke_weather.sun=The rain begins to stop... -spell.ebwizardry:invoke_weather.rain=The heavens open... -spell.ebwizardry:transportation.missing=Your remembered stone circle is missing or obstructed... -spell.ebwizardry:transportation.undefined=You must remember the location of a stone circle first! -spell.ebwizardry:transportation.wrongdimension=Your remembered stone circle is in another dimension... -spell.ebwizardry:clairvoyance.searching=Searching... -spell.ebwizardry:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point -spell.ebwizardry:clairvoyance.outofrange=Your remembered location is too far away or inaccessible... -spell.ebwizardry:clairvoyance.undefined=You must remember a location first! -spell.ebwizardry:clairvoyance.wrongdimension=Your remembered location is in another dimension... +spell.ebwizardry\:invoke_weather.sun=The rain begins to stop... +spell.ebwizardry\:invoke_weather.rain=The heavens open... +spell.ebwizardry\:transportation.missing=The stone circle is missing or obstructed... +spell.ebwizardry\:transportation.undefined=You must remember the location of a stone circle first! +spell.ebwizardry\:transportation.wrongdimension=No remembered stone circle in this dimension... +spell.ebwizardry\:clairvoyance.searching=Searching... +spell.ebwizardry\:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point +spell.ebwizardry\:clairvoyance.outofrange=Your remembered locations is too far away or inaccessible... +spell.ebwizardry\:clairvoyance.undefined=You must remember a locations first! +spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered locations is in another dimension... +spell.ebwizardry\:possession.insufficienthealth=You don't have enough health to possess %1$s! +spell.ebwizardry\:possession.success=Press %s to stop possessing +spell.ebwizardry\:divination.nothing=Nothing happened. +spell.ebwizardry\:divination.weak=You can just feel your wand twitching %s. +spell.ebwizardry\:divination.moderate=You feel your wand being tugged %s. +spell.ebwizardry\:divination.strong=Your wand pulls %s strongly. +spell.ebwizardry\:divination.very_strong=Your wand lurches %s sharply. +spell.ebwizardry\:divination.down=downwards +spell.ebwizardry\:divination.up=upwards +spell.ebwizardry\:divination.front=forwards +spell.ebwizardry\:divination.back=backwards +spell.ebwizardry\:divination.left=to the left +spell.ebwizardry\:divination.right=to the right +spell.ebwizardry\:resurrection.resurrect_ally=%s was resurrected by %s +spell.ebwizardry\:resurrection.resurrect_self=%s came back to life +spell.ebwizardry\:resurrection.button_wait=Resurrect (%ss) +spell.ebwizardry\:resurrection.button_ready=Resurrect -potion.ebwizardry:frost=Frostbite -potion.ebwizardry:fireskin=Fireskin -potion.ebwizardry:ice_shroud=Ice Shroud -potion.ebwizardry:static_aura=Static Aura -potion.ebwizardry:transience=Transience -potion.ebwizardry:decay=Decay -potion.ebwizardry:sixth_sense=Sixth Sense -potion.ebwizardry:arcane_jammer=Arcane Jammer -potion.ebwizardry:mind_trick=Mind Trick -potion.ebwizardry:mind_control=Mind Control -potion.ebwizardry:font_of_mana=Font of Mana -potion.ebwizardry:fear=Fear +forfeit.ebwizardry\:do_nothing=Nothing happened. -enchantment.ebwizardry:magic_sword=Imbuement -enchantment.ebwizardry:magic_bow=Imbuement -enchantment.ebwizardry:flaming_weapon=Fire Imbuement -enchantment.ebwizardry:freezing_weapon=Frost Imbuement +forfeit.ebwizardry\:burn_self=The %s bursts into flames in your hand! +forfeit.ebwizardry\:fireball=A fireball materializes in front of you! +forfeit.ebwizardry\:firebomb=A firebomb appears right above you! +forfeit.ebwizardry\:explode=A sudden explosion knocks you to the ground! +forfeit.ebwizardry\:blazes=Suddenly, hostile blazes materialize around you! +forfeit.ebwizardry\:burn_surroundings=The area around you is set ablaze! +forfeit.ebwizardry\:meteors=Fiery armageddon rains from the sky! + +forfeit.ebwizardry\:freeze_self=You feel an icy chill rush through you! +forfeit.ebwizardry\:freeze_self_2=From the %s emanates a cold so intense that it roots you to the spot! +forfeit.ebwizardry\:ice_spikes=Ice spikes rise from the ground beneath your feet! +forfeit.ebwizardry\:blizzard=You are suddenly surrounded by a raging blizzard! +forfeit.ebwizardry\:ice_wraiths=Suddenly, hostile ice wraiths materialize around you! +forfeit.ebwizardry\:hailstorm=Razor-sharp ice starts raining down upon you! +forfeit.ebwizardry\:ice_giant=A hostile ice giant materializes in front of you! + +forfeit.ebwizardry\:thunder=The scroll emits a deafening noise, knocking you to the ground! +forfeit.ebwizardry\:storm=Looks like a storm is brewing! +forfeit.ebwizardry\:lightning_sigils=Watch your step! +forfeit.ebwizardry\:lightning=You are struck by lightning! +forfeit.ebwizardry\:paralyse_self=You are paralysed! +forfeit.ebwizardry\:lightning_wraiths=Suddenly, hostile lightning wraiths materialise around you! +forfeit.ebwizardry\:storm_elementals=Hostile storm elementals materialize on all sides! + +forfeit.ebwizardry\:nausea=...huh? What just happened? Where am I? +forfeit.ebwizardry\:zombie_horde=A horde of zombies rises from the ground around you! +forfeit.ebwizardry\:wither_self=Darkness withers your soul! +forfeit.ebwizardry\:cripple_self=The %s emits a deathly howl, and you are crippled to within an inch of your life! +forfeit.ebwizardry\:shadow_wraiths=Hostile shadow wraiths materialise on all sides! + +forfeit.ebwizardry\:snares=It's a trap! +forfeit.ebwizardry\:squid=Squid! +forfeit.ebwizardry\:uproot_plants=All nearby plants are suddenly uprooted! +forfeit.ebwizardry\:poison_self=You are poisoned! +forfeit.ebwizardry\:flood=Water materialises around you! +forfeit.ebwizardry\:bury_self=The ground collapses beneath you! + +forfeit.ebwizardry\:spill_inventory=Your items spill themselves everywhere! +forfeit.ebwizardry\:teleport_self=You are instantly teleported somewhere! +forfeit.ebwizardry\:levitate_self=You begin to float upwards helplessly! +forfeit.ebwizardry\:vex_horde=A horde of vexes materializes around you! +forfeit.ebwizardry\:black_hole=A swirling vortex appears in front of you! +forfeit.ebwizardry\:arrow_rain=A barrage of arrows starts raining down upon you! + +forfeit.ebwizardry\:damage_self=Ouch! +forfeit.ebwizardry\:spill_armour=All your armour falls off! +forfeit.ebwizardry\:hunger=You suddenly feel very hungry! +forfeit.ebwizardry\:blind_self=You are blinded! +forfeit.ebwizardry\:weaken_self=You are severely weakened! +forfeit.ebwizardry\:jam_self=Your magic is rendered useless! +forfeit.ebwizardry\:curse_self=You are cursed with undeath! + +potion.ebwizardry\:frost=Frostbite +potion.ebwizardry\:fireskin=Fireskin +potion.ebwizardry\:ice_shroud=Ice Shroud +potion.ebwizardry\:static_aura=Static Aura +potion.ebwizardry\:transience=Transience +potion.ebwizardry\:decay=Decay +potion.ebwizardry\:sixth_sense=Sixth Sense +potion.ebwizardry\:arcane_jammer=Arcane Jammer +potion.ebwizardry\:mind_trick=Mind Trick +potion.ebwizardry\:mind_control=Mind Control +potion.ebwizardry\:font_of_mana=Font of Mana +potion.ebwizardry\:fear=Fear +potion.ebwizardry\:curse_of_soulbinding=Curse of Soulbinding +potion.ebwizardry\:paralysis=Paralysis +potion.ebwizardry\:muffle=Muffle +potion.ebwizardry\:ward=Ward +potion.ebwizardry\:slow_time=Slow Time +potion.ebwizardry\:empowerment=Empowerment +potion.ebwizardry\:curse_of_enfeeblement=Curse of Enfeeblement +potion.ebwizardry\:curse_of_undeath=Curse of Undeath +potion.ebwizardry\:containment=Containment +potion.ebwizardry\:frost_step=Frost Step + +enchantment.ebwizardry\:magic_sword=Imbuement +enchantment.ebwizardry\:magic_bow=Imbuement +enchantment.ebwizardry\:flaming_weapon=Fire Imbuement +enchantment.ebwizardry\:freezing_weapon=Frost Imbuement +enchantment.ebwizardry\:shocking_weapon=Lightning Imbuement + +enchantment.ebwizardry\:magic_protection=Magic Protection +enchantment.ebwizardry\:frost_protection=Frost Protection +enchantment.ebwizardry\:shock_protection=Shock Protection key.categories.ebwizardry=Wizardry @@ -627,140 +1011,268 @@ key.ebwizardry.previous_spell=Previous Spell death.attack.wizardry_magic=%1$s was killed by %2$s using magic death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic -commands.ebwizardry:cast.usage=/%1$s [player] [damage multiplier] [range multiplier] [duration multiplier] [blast multiplier] -commands.ebwizardry:cast.success=Successfully cast %1$s -commands.ebwizardry:cast.success_continuous=Successfully cast %1$s; repeat the command to stop -commands.ebwizardry:cast.success_remote=Successfully cast %1$s as %2$s -commands.ebwizardry:cast.success_remote_continuous=Successfully cast %1$s as %2$s; repeat the command to stop -commands.ebwizardry:cast.fail=Unable to cast %1$s -commands.ebwizardry:cast.not_found=There is no such spell with ID %1$s -commands.ebwizardry:cast.tag_error=Data tag parsing failed: %s +soundCategory.ebwizardry\:spells=Spells -commands.ebwizardry:ally.usage=/%1$s [player] -commands.ebwizardry:ally.addally=%1$s has been added to %2$s's list of allies -commands.ebwizardry:ally.removeally=%1$s has been removed from %2$s's list of allies -commands.ebwizardry:ally.self=Players cannot be an ally of themselves! -commands.ebwizardry:ally.permission=You do not have permission to change other players' allies +commands.ebwizardry\:cast.usage=/%1$s [player | x y z direction] [duration] [modifiers] +commands.ebwizardry\:cast.success=Successfully cast %s +commands.ebwizardry\:cast.success_continuous=Successfully cast %s for %s seconds +commands.ebwizardry\:cast.success_remote=Successfully cast %s as %s +commands.ebwizardry\:cast.success_remote_continuous=Successfully cast %s as %s for %s seconds +commands.ebwizardry\:cast.success_position=Successfully cast %s at %s, %s, %s +commands.ebwizardry\:cast.success_position_continuous=Successfully cast %s at %s, %s, %s for %s seconds +commands.ebwizardry\:cast.fail=Unable to cast %1$s +commands.ebwizardry\:cast.not_found=There is no such spell with ID %1$s +commands.ebwizardry\:cast.invalid_direction=Invalid direction: %1$s (valid directions are: up, down, north, south, east, west) +commands.ebwizardry\:cast.tag_error=Data tag parsing failed\: %s +commands.ebwizardry\:cast.origin_not_specified=You must specify a player or location to cast the spell from +commands.ebwizardry\:cast.duration_not_specified=You must specify a duration for this spell -commands.ebwizardry:allies.usage=/%1$s [player] -commands.ebwizardry:allies.list=Players allied to you: %1$s -commands.ebwizardry:allies.list_other=Players allied to %1$s: %2$s -commands.ebwizardry:allies.permission=You do not have permission to view other players' allies -commands.ebwizardry:allies.none=None +commands.ebwizardry\:ally.usage=/%1$s [player] +commands.ebwizardry\:ally.addally=%1$s has been added to %2$s's list of allies +commands.ebwizardry\:ally.removeally=%1$s has been removed from %2$s's list of allies +commands.ebwizardry\:ally.self=Players cannot be an ally of themselves! +commands.ebwizardry\:ally.permission=You do not have permission to change other players' allies -commands.ebwizardry:discoverspell.usage=/%1$s [player] -commands.ebwizardry:discoverspell.not_found=There is no such spell with ID %1$s -commands.ebwizardry:discoverspell.clear=Cleared all spell discovery data for %1$s -commands.ebwizardry:discoverspell.all=Added all spells to %1$s's spell discovery data -commands.ebwizardry:discoverspell.addspell=Added %1$s to %2$s's spell discovery data -commands.ebwizardry:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data +commands.ebwizardry\:allies.usage=/%1$s [player] +commands.ebwizardry\:allies.list=Players allied to you\: %1$s +commands.ebwizardry\:allies.list_other=Players allied to %1$s\: %2$s +commands.ebwizardry\:allies.permission=You do not have permission to view other players' allies +commands.ebwizardry\:allies.none=None + +commands.ebwizardry\:discoverspell.usage=/%1$s [player] +commands.ebwizardry\:discoverspell.not_found=There is no such spell with ID %1$s +commands.ebwizardry\:discoverspell.clear=Cleared all spell discovery data for %1$s +commands.ebwizardry\:discoverspell.all=Added all spells to %1$s's spell discovery data +commands.ebwizardry\:discoverspell.addspell=Added %1$s to %2$s's spell discovery data +commands.ebwizardry\:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data config.ebwizardry.title.general=Mod Options +config.ebwizardry.generic.true=Enabled +config.ebwizardry.generic.false=Disabled + +config.ebwizardry.category.spells=Spell Configuration +config.ebwizardry.category.spells.tooltip=Select which spells are enabled +config.ebwizardry.title.spells=Spell Configuration +config.ebwizardry.subtitle.spells=Disabling a spell globally here will override the finer controls in the spell JSON file. + config.ebwizardry.category.gameplay=Gameplay Settings config.ebwizardry.category.gameplay.tooltip=Configure wizardry's general gameplay config.ebwizardry.title.gameplay=Gameplay Settings config.ebwizardry.subtitle.gameplay=Global settings that affect game mechanics. +config.ebwizardry.discovery_mode=Discovery Mode +config.ebwizardry.discovery_mode.tooltip=For those who like a sense of mystery! When enabled, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is disabled. +config.ebwizardry.legacy_wand_levelling=Legacy Wand Levelling +config.ebwizardry.legacy_wand_levelling.tooltip=Controls whether wands are required to gain progression before they can be upgraded to the next tier. Enable this option to revert to the pre-4.2 system, which only requires tomes of arcana. Wands will still gain progression silently when this is enabled, so if you go back to the new system you won't lose any progress. +config.ebwizardry.legacy_wand_levelling.true=Yes - I liked it how it was! +config.ebwizardry.legacy_wand_levelling.false=No - Level me up! +config.ebwizardry.friendly_fire=Friendly Fire +config.ebwizardry.friendly_fire.tooltip=Controls which creatures may be damaged by your magic when allied to you. Your spells will not target your allies or creatures summoned/owned by them regardless of this setting, but this setting makes them completely immune if disabled. +config.ebwizardry.minion_revenge_targeting=Minion Revenge Targeting +config.ebwizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge-attack players or creatures that they would not otherwise be able to attack. +config.ebwizardry.minion_revenge_targeting.true=Yes - I'd never hurt them! +config.ebwizardry.minion_revenge_targeting.false=No - they must always obey me! +config.ebwizardry.players_move_each_other=Players Move Each Other +config.ebwizardry.players_move_each_other.tooltip=Whether to allow players to move other players around using magic. +config.ebwizardry.players_move_each_other.true=Yes - let the games begin! +config.ebwizardry.players_move_each_other.false=No - I won't be pushed around +config.ebwizardry.player_block_damage=Player Block Damage +config.ebwizardry.player_block_damage.tooltip=Whether spells cast by players can destroy blocks in the world. Disable this to prevent griefing. To prevent non-players from destroying blocks with magic, use the mobGriefing gamerule. +config.ebwizardry.player_block_damage.true=Yes - kaboom! +config.ebwizardry.player_block_damage.false=No - activate anti-grief (TM) +config.ebwizardry.telekinetic_disarmament=Telekinetic Disarmament +config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Disable to prevent stealing of items. +config.ebwizardry.telekinetic_disarmament.true=Yes - let people steal things +config.ebwizardry.telekinetic_disarmament.false=No - that's cheating! +config.ebwizardry.teleport_through_unbreakable_blocks=Teleport Through Unbreakable Blocks +config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. +config.ebwizardry.teleport_through_unbreakable_blocks.true=Yes - I wish to see the void! +config.ebwizardry.teleport_through_unbreakable_blocks.false=No - bedrock is impenetrable +config.ebwizardry.world_time_manipulation=World Time Manipulation +config.ebwizardry.world_time_manipulation.tooltip=Whether players are allowed to change the world time with the speed time spell. If disabled, the speed time spell will not change the world time but will still speed up nearby block, entity and tile entity ticks. +config.ebwizardry.world_time_manipulation.true=Yes - daytime, nighttime... +config.ebwizardry.world_time_manipulation.false=No - I need my sleep! +config.ebwizardry.replace_vanilla_fireballs=Replace Vanilla Fireballs +config.ebwizardry.replace_vanilla_fireballs.tooltip=Whether to replace Minecraft's own fireballs with wizardry fireballs. If this is disabled, only wizardry spells will use the custom fireballs. +config.ebwizardry.replace_vanilla_fireballs.true=Yes - give me FIRE! +config.ebwizardry.replace_vanilla_fireballs.false=No - blazes are mean enough +config.ebwizardry.replace_vanilla_fall_damage=Replace Vanilla Fall Damage +config.ebwizardry.replace_vanilla_fall_damage.tooltip=Whether to replace Minecraft's distance-based fall damage calculation with an equivalent, velocity-based one. This is done such that mobs in freefall will take exactly the same damage as normal, so it will not break falling-based mob farms. Disable this if you experience falling-related weirdness! If this is disabled, some spells revert to a more simplistic method of resetting the player's fall damage in certain cases. +config.ebwizardry.replace_vanilla_fall_damage.true=Yes - it's parkour time +config.ebwizardry.replace_vanilla_fall_damage.false=No - break my legs normally +config.ebwizardry.creative_bypasses_arcane_lock=Bypass Arcane Lock +config.ebwizardry.creative_bypasses_arcane_lock.tooltip=Determines which players can bypass arcane locks. +config.ebwizardry.creative_bypasses_arcane_lock.true=Anyone in creative mode +config.ebwizardry.creative_bypasses_arcane_lock.false=Only ops in creative mode +config.ebwizardry.slow_time_affects_players=Slow Time Affects Players +config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed. +config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist +config.ebwizardry.mob_loot_table_whitelist.tooltip=Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them. +config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist +config.ebwizardry.mob_loot_table_blacklist.tooltip=Blacklist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually exclude them. +config.ebwizardry.mob_spawn_dimensions=Mob Spawning Dimensions +config.ebwizardry.mob_spawn_dimensions.tooltip=List of ids of dimensions in which wizardry's hostile mobs can spawn. +config.ebwizardry.mob_spawn_biome_blacklist=Mob Spawning Biome Blacklist +config.ebwizardry.mob_spawn_biome_blaclist.tooltip=List of names of biomes in which wizardry's hostile mobs cannot spawn. Biome names are not case-sensitive. For mod biomes, prefix with the mod ID (e.g. biomesoplenty\:mystic_grove). +config.ebwizardry.evil_wizard_spawn_rate=Evil Wizard Spawn Rate +config.ebwizardry.evil_wizard_spawn_rate.tooltip=Spawn rate for naturally-spawned evil wizards; higher numbers mean more evil wizards will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable evil wizard spawning entirely. +config.ebwizardry.ice_wraith_spawn_rate=Ice Wraith Spawn Rate +config.ebwizardry.ice_wraith_spawn_rate.tooltip=Spawn rate for naturally-spawned ice wraiths; higher numbers mean more ice wraiths will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable ice wraith spawning entirely. +config.ebwizardry.lightning_wraith_spawn_rate=Lightning Wraith Spawn Rate +config.ebwizardry.lightning_wraith_spawn_rate.tooltip=Spawn rate for naturally-spawned lightning wraiths; higher numbers mean more lightning wraiths will spawn. 5 is equivalent to witches, 100 is equivalent to zombies, skeletons and creepers. Set to 0 to disable lightning wraith spawning entirely. +config.ebwizardry.forfeit_chance=Forfeit Chance +config.ebwizardry.forfeit_chance.tooltip=The chance to 'misread' an undiscovered spell and trigger a forfeit instead. Setting this to 0 effectively disables the forfeit mechanic. Has no effect if discovery mode is disabled. +config.ebwizardry.player_damage_scaling=Player Damage Scaling Factor +config.ebwizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. +config.ebwizardry.npc_damage_scaling=NPC Damage Scaling Factor +config.ebwizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. +config.ebwizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist +config.ebwizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). +config.ebwizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist +config.ebwizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). +config.ebwizardry.mind_control_targets_blacklist=Mind Control Targets Blacklist +config.ebwizardry.mind_control_targets_blacklist.tooltip=List of names of entities which cannot be mind controlled, in addition to the defaults. Add creatures to this list if allowing them to be mind-controlled causes problems or could be exploited. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). +config.ebwizardry.pocket_furnace_item_blacklist=Pocket Furnace Item Blacklist +config.ebwizardry.pocket_furnace_item_blacklist.tooltip=List of registry names of blocks or items which cannot be smelted by the pocket furnace spell, in addition to armour, tools and weapons. Block/item names are not case sensitive. For mod items, prefix with the mod ID (e.g. ebwizardry\:crystal_ore). +config.ebwizardry.divination_ore_whitelist=Divination Ore Whitelist +config.ebwizardry.divination_ore_whitelist.tooltip=List of registry names of ore blocks which can be detected by the divination spell. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. ebwizardry\:crystal_ore). +config.ebwizardry.sword_item_whitelist=Sword Item Whitelist +config.ebwizardry.sword_item_whitelist.tooltip=List of registry names of items which should count as swords for imbuement spells. Most swords should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:broadsword). +config.ebwizardry.bow_item_whitelist=Bow Item Whitelist +config.ebwizardry.bow_item_whitelist.tooltip=List of registry names of items which should count as bows for imbuement spells. Most bows should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:shortbow). +config.ebwizardry.currency_items=Currency Items +config.ebwizardry.currency_items.tooltip=List of registry names of items which wizard trades can use as currency (in the first slot; the second slot is unaffected). Each entry in this list should consist of an item registry name, followed by a single space, then an integer which defines the 'value' of the item. Higher values mean fewer of that currency item are required for a given trade. + config.ebwizardry.category.worldgen=World Generation Settings config.ebwizardry.category.worldgen.tooltip=Configure wizardry's world generation features config.ebwizardry.title.worldgen=World Generation Settings config.ebwizardry.subtitle.worldgen=Settings that affect world generation. -config.ebwizardry.category.commands=Command Settings -config.ebwizardry.category.commands.tooltip=Configure wizardry's commands -config.ebwizardry.title.commands=Command Settings -config.ebwizardry.subtitle.commands=Settings for the commands added by Wizardry. +config.ebwizardry.fast_worldgen=Structure Generation +config.ebwizardry.fast_worldgen.tooltip=Controls which algorithm wizardry uses for structure generation. Fancy worldgen prevents structures on cliffs, in caves and intersecting other structures, and cleans up floating trees after generating. Fast worldgen sacrifices these improvements, potentially resulting in faster world generation. Performance improvement will vary depending on your setup. This option will affect randomisation; for any given seed, structures will not be the same as when it is turned off. +config.ebwizardry.fast_worldgen.true=Fast +config.ebwizardry.fast_worldgen.false=Fancy +config.ebwizardry.tower_dimensions=Tower Dimensions +config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate. +config.ebwizardry.tower_rarity=Tower Rarity +config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer. +config.ebwizardry.evil_wizard_chance=Evil Wizard Chance +config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard. +config.ebwizardry.tower_files=Tower Structure Files +config.ebwizardry.tower_files.tooltip=List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. +config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files +config.ebwizardry.tower_with_chest_files.tooltip=List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. +config.ebwizardry.obelisk_dimensions=Obelisk Dimensions +config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate. +config.ebwizardry.obelisk_rarity=Obelisk Rarity +config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer. +config.ebwizardry.obelisk_files=Obelisk Structure Files +config.ebwizardry.obelisk_files.tooltip=List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. +config.ebwizardry.shrine_dimensions=Shrine Dimensions +config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate. +config.ebwizardry.shrine_rarity=Shrine Rarity +config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer. +config.ebwizardry.shrine_files=Shrine Structure Files +config.ebwizardry.shrine_files.tooltip=List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]\:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. +config.ebwizardry.ore_dimensions=Ore Dimensions +config.ebwizardry.ore_dimensions.tooltip=List of ids of dimensions in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! +config.ebwizardry.flower_dimensions=Flower Dimensions +config.ebwizardry.flower_dimensions.tooltip=List of ids of dimensions in which crystal flowers will generate. +config.ebwizardry.loot_injection_locations=Loot Injection Locations +config.ebwizardry.loot_injection_locations.tooltip=List of loot tables to inject wizardry loot (as specified in loot_tables/chests/dungeon_additions.json) into. config.ebwizardry.category.client=Client Settings config.ebwizardry.category.client.tooltip=Configure wizardry's display and controls config.ebwizardry.title.client=Client Settings config.ebwizardry.subtitle.client=Client-side settings that only affect the local minecraft game. -config.ebwizardry.category.spells=Spell Configuration -config.ebwizardry.category.spells.tooltip=Select which spells are enabled -config.ebwizardry.title.spells=Spell Configuration -config.ebwizardry.subtitle.spells=Set a spell to false to disable it. +config.ebwizardry.shift_scrolling=Shift-scrolling +config.ebwizardry.shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. +config.ebwizardry.reverse_scroll_direction=Scroll Direction +config.ebwizardry.reverse_scroll_direction.tooltip=The scroll direction used to switch between spells on a wand while sneaking. +config.ebwizardry.reverse_scroll_direction.true=Reversed +config.ebwizardry.reverse_scroll_direction.false=Normal +config.ebwizardry.spell_hud_position=Spell HUD Position +config.ebwizardry.spell_hud_position.tooltip=The position of the spell HUD. +config.ebwizardry.spell_hud_skin=Spell HUD Skin +config.ebwizardry.spell_hud_skin.tooltip=Change the look of the spell HUD... +config.ebwizardry.spell_hud_skin.preview=Preview +config.ebwizardry.handbook_progression=Handbook Progression +config.ebwizardry.handbook_progression.tooltip=When enabled, to help guide players through the mod, sections of The Wizard's Handbook are unlocked when a player gains the advancement that triggers them, and are hidden otherwise. When disabled, the entire handbook is readable regardless of advancement progress. The entire handbook is always readable in creative mode. +config.ebwizardry.handbook_progression.true=Yes - teach me, Sensei! +config.ebwizardry.handbook_progression.false=No - I know what I'm doing +config.ebwizardry.books_pause_game=Books Pause Game +config.ebwizardry.books_pause_game.tooltip=Whether opening any of wizardry's books pauses the game in singleplayer. Has no effect on servers or LAN worlds. +config.ebwizardry.books_pause_game.true=Yes - I don't want any distractions! +config.ebwizardry.books_pause_game.false=No - I read to pass the time +config.ebwizardry.summoned_creature_names=Summoned Creature Names +config.ebwizardry.summoned_creature_names.tooltip=Controls whether summoned creatures' names and owners are displayed above their heads. +config.ebwizardry.summoned_creature_names.true=Shown +config.ebwizardry.summoned_creature_names.false=Hidden +config.ebwizardry.use_shaders=Use Custom Shaders +config.ebwizardry.use_shaders.tooltip=Whether to use custom shaders for certain spells. These use the vanilla shader system (like mob spectating shaders) and shouldn't have much of an effect on performance in most cases, but they may conflict with other shaders. +config.ebwizardry.use_shaders.true=Yes - gimme those sweet shaders! +config.ebwizardry.use_shaders.false=No - I'm running this on a potato + +config.ebwizardry.category.commands=Command Settings +config.ebwizardry.category.commands.tooltip=Configure wizardry's commands +config.ebwizardry.title.commands=Command Settings +config.ebwizardry.subtitle.commands=Settings for the commands added by Wizardry. + +config.ebwizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit +config.ebwizardry.cast_command_multiplier_limit.tooltip=Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned! +config.ebwizardry.cast_command_name=Cast Spell Command Name +config.ebwizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. +config.ebwizardry.discoverspell_command_name=Discover Spell Command Name +config.ebwizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. +config.ebwizardry.ally_command_name=Set Ally Command Name +config.ebwizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. +config.ebwizardry.allies_command_name=View Allies Command Name +config.ebwizardry.allies_command_name.tooltip=The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead. config.ebwizardry.category.resistances=Resistance Configuration config.ebwizardry.category.resistances.tooltip=Configure which mobs are immune to different types of magic config.ebwizardry.title.resistances=Resistance Configuration config.ebwizardry.subtitle.resistances=Settings which allow entities to be made immune to certain types of magic. -config.ebwizardry.tower_rarity=Tower Rarity -config.ebwizardry.ore_dimensions=Ore Dimensions -config.ebwizardry.flower_dimensions=Flower Dimensions -config.ebwizardry.tower_dimensions=Tower Dimensions -config.ebwizardry.spell_book_drop_chance=Spell Book Drop Chance -config.ebwizardry.generate_loot=Generate Loot -config.ebwizardry.firebomb_is_craftable=Firebomb Is Craftable -config.ebwizardry.poison_bomb_is_craftable=Poison Bomb Is Craftable -config.ebwizardry.smoke_bomb_is_craftable=Smoke Bomb Is Craftable -config.ebwizardry.use_alternate_scroll_recipe=Use Alternate Scroll Recipe -config.ebwizardry.teleport_through_unbreakable_blocks=Teleport Through Unbreakable Blocks -config.ebwizardry.show_summoned_creature_names=Show Summoned Creature Names -config.ebwizardry.friendly_fire=Friendly Fire -config.ebwizardry.telekinetic_disarmament=Telekinetic Disarmament -config.ebwizardry.discovery_mode=Discovery Mode -config.ebwizardry.enable_shift_scrolling=Enable Shift-scrolling -config.ebwizardry.reverse_scroll_direction=Reverse Scroll Direction -config.ebwizardry.minion_revenge_targeting=Minion Revenge Targeting -config.ebwizardry.player_damage_scaling=Player Damage Scaling Factor -config.ebwizardry.npc_damage_scaling=NPC Damage Scaling Factor -config.ebwizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit -config.ebwizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist -config.ebwizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist -config.ebwizardry.spell_hud_position=Spell HUD Position -config.ebwizardry.spell_hud_skin=Spell HUD Skin -config.ebwizardry.cast_command_name=Cast Spell Command Name -config.ebwizardry.discoverspell_command_name=Discover Spell Command Name -config.ebwizardry.ally_command_name=Set Ally Command Name -config.ebwizardry.allies_command_name=View Allies Command Name -config.ebwizardry.mind_control_targets_blacklist=Mind Control Targets Blacklist -config.ebwizardry.evil_wizard_dimensions=Evil Wizard Dimensions - config.ebwizardry.mobs_immune_to_fire=Mobs Immune To Fire +config.ebwizardry.mobs_immune_to_fire.tooltip=List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). config.ebwizardry.mobs_immune_to_ice=Mobs Immune To Ice +config.ebwizardry.mobs_immune_to_ice.tooltip=List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). config.ebwizardry.mobs_immune_to_lightning=Mobs Immune To Lightning +config.ebwizardry.mobs_immune_to_lightning.tooltip=List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). config.ebwizardry.mobs_immune_to_wither=Mobs Immune To Wither +config.ebwizardry.mobs_immune_to_wither.tooltip=List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). config.ebwizardry.mobs_immune_to_poison=Mobs Immune To Poison +config.ebwizardry.mobs_immune_to_poison.tooltip=List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry\:wizard). -config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely. -config.ebwizardry.ore_dimensions.tooltip=List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! -config.ebwizardry.flower_dimensions.tooltip=List of dimension ids in which crystal flowers will generate. -config.ebwizardry.tower_dimensions.tooltip=List of dimension ids in which wizard towers will generate. -config.ebwizardry.spell_book_drop_chance.tooltip=The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops. -config.ebwizardry.generate_loot.tooltip=Whether to generate wizardry loot in dungeon chests. -config.ebwizardry.firebomb_is_craftable.tooltip=Whether firebombs can be crafted or not. -config.ebwizardry.poison_bomb_is_craftable.tooltip=Whether poison bombs can be crafted or not. -config.ebwizardry.smoke_bomb_is_craftable.tooltip=Whether smoke bombs can be crafted or not. -config.ebwizardry.use_alternate_scroll_recipe.tooltip=Whether to require a magic crystal in the shapeless crafting recipe for blank scrolls. Set to true if another mod adds a conflicting recipe. -config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. -config.ebwizardry.show_summoned_creature_names.tooltip=Whether to show summoned creatures' names and owners above their heads. -config.ebwizardry.friendly_fire.tooltip=Whether to allow players to damage their designated allies using magic. -config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items. -config.ebwizardry.discovery_mode.tooltip=For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false. -config.ebwizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. -config.ebwizardry.reverse_scroll_direction.tooltip=Whether to reverse the scroll direction used to switch between spells on a wand while sneaking. -config.ebwizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge attack their owner if their owner attacks them. -config.ebwizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. -config.ebwizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. -config.ebwizardry.cast_command_multiplier_limit.tooltip=Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned! -config.ebwizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.spell_hud_position.tooltip=The position of the spell HUD. -config.ebwizardry.spell_hud_skin.tooltip=Change the look of the spell HUD... -config.ebwizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. -config.ebwizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. -config.ebwizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. -config.ebwizardry.allies_command_name.tooltip=The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead. -config.ebwizardry.mind_control_targets_blacklist.tooltip=List of names of entities which cannot be mind controlled, in addition to the defaults. Add creatures to this list if allowing them to be mind-controlled causes problems or could be exploited. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.evil_wizard_dimensions.tooltip=List of dimension ids in which evil wizards can spawn. +config.ebwizardry.category.compatibility=Mod Compatibility Settings +config.ebwizardry.category.compatibility.tooltip=Configure how wizardry interacts with other mods +config.ebwizardry.title.compatibility=Mod Compatibility Settings +config.ebwizardry.subtitle.compatibility=Settings that affect how wizardry interacts with other mods -config.ebwizardry.mobs_immune_to_fire.tooltip=List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.mobs_immune_to_ice.tooltip=List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.mobs_immune_to_lightning.tooltip=List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.mobs_immune_to_wither.tooltip=List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). -config.ebwizardry.mobs_immune_to_poison.tooltip=List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.damage_source_blacklist=Damage Source Blacklist +config.ebwizardry.damage_source_blacklist.tooltip=List of damage source string identifiers to be ignored when re-applying damage. Case-sensitive. A message will be logged if wizardry detects a damage source that should be added to this list. Otherwise, don't change unless instructed to do so. +config.ebwizardry.compatibility_warnings=Compatibility Warnings +config.ebwizardry.compatibility_warnings.tooltip=Whether to print compatibility warnings to the console. Set to false if excessive messages are being printed. +config.ebwizardry.baubles_integration=Baubles Integration +config.ebwizardry.baubles_integration.tooltip=If Baubles is installed, controls whether Baubles integration features are enabled. If this is disabled, wizardry will always behave as if Baubles is not installed. +config.ebwizardry.jei_integration=JEI Integration +config.ebwizardry.jei_integration.tooltip=If JEI (Just Enough Items) is installed, controls whether JEI integration features are enabled. If this is disabled, wizardry will always behave as if JEI is not installed. +config.ebwizardry.antique_atlas_integration=Antique Atlas Integration +config.ebwizardry.antique_atlas_integration.tooltip=If Antique Atlas is installed, controls whether Antique Atlas integration features are enabled. If this is disabled, wizardry will always behave as if Antique Atlas is not installed. +config.ebwizardry.auto_place_tower_markers=Auto-Place Tower Markers +config.ebwizardry.auto_place_tower_markers.tooltip=Controls whether wizardry automatically places antique atlas markers at the locations of wizard towers. +config.ebwizardry.auto_place_obelisk_markers=Auto-Place Obelisk Markers +config.ebwizardry.auto_place_obelisk_markers.tooltip=Controls whether wizardry automatically places antique atlas markers at the locations of obelisks. +config.ebwizardry.auto_place_shrine_markers=Auto-Place Shrine Markers +config.ebwizardry.auto_place_shrine_markers.tooltip=Controls whether wizardry automatically places antique atlas markers at the locations of shrines. + +integration.jei.category.ebwizardry\:arcane_workbench=Arcane Workbench + +integration.antiqueatlas.marker.ebwizardry\:wizard_tower=Wizard Tower +integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk +integration.antiqueatlas.marker.ebwizardry\:shrine=Shrine wizard.debug=%1$s, %2$s, %3$s diff --git a/src/main/resources/assets/ebwizardry/lang/es_es.lang b/src/main/resources/assets/ebwizardry/lang/es_es.lang index 3287ca13..ae625e31 100644 --- a/src/main/resources/assets/ebwizardry/lang/es_es.lang +++ b/src/main/resources/assets/ebwizardry/lang/es_es.lang @@ -29,13 +29,13 @@ item.ebwizardry:wand.mana=Mana: %1$s/%2$s item.ebwizardry:wand.addally=%1$s ha sido anadido a tu lista de aliados item.ebwizardry:wand.removeally=%1$s ha sido removido a tu lista de aliados -item.ebwizardry:basic_fire_wand.name=Varita de Ascuas -item.ebwizardry:basic_ice_wand.name=Varita de Escarcha -item.ebwizardry:basic_lightning_wand.name=Varita de Chispas -item.ebwizardry:basic_necromancy_wand.name=Varita de las Sombras -item.ebwizardry:basic_earth_wand.name=Varita del Bosque -item.ebwizardry:basic_sorcery_wand.name=Varita del Misterio -item.ebwizardry:basic_healing_wand.name=Varita de la Curacion +item.ebwizardry:novice_fire_wand.name=Varita de Ascuas +item.ebwizardry:novice_ice_wand.name=Varita de Escarcha +item.ebwizardry:novice_lightning_wand.name=Varita de Chispas +item.ebwizardry:novice_necromancy_wand.name=Varita de las Sombras +item.ebwizardry:novice_earth_wand.name=Varita del Bosque +item.ebwizardry:novice_sorcery_wand.name=Varita del Misterio +item.ebwizardry:novice_healing_wand.name=Varita de la Curacion item.ebwizardry:apprentice_fire_wand.name=Varita del Piromano Aprendiz item.ebwizardry:apprentice_ice_wand.name=Varita del Mago de Hielo Aprendiz @@ -212,56 +212,56 @@ entity.ebwizardry:lightning_pulse.name=Pulso de Relampago item_group.ebwizardry=Wizardry item_group.wizardryspells=Hechizos de Wizardry -advancement.wizardry:root=Wizardry -advancement.wizardry:root.desc=Avances -advancement.wizardry:crystal=Un Cristral Curioso... -advancement.wizardry:crystal.desc=Pica un Cristal Magico -advancement.wizardry:arcane_initiate=Inicio Arcano -advancement.wizardry:arcane_initiate.desc=Craftea una varita magica con una pepita de oro, un palo y un cristal magico -advancement.wizardry:apprentice=Aprendiz de Mago -advancement.wizardry:apprentice.desc=Usa un tomo de lo arcano para mejorar tu varita -advancement.wizardry:master=Maestro Arcano -advancement.wizardry:master.desc=Obten una varita de maestro -advancement.wizardry:all_spells=Mago de Todos los Oficios -advancement.wizardry:all_spells.desc=Lanza todos los hechizos disponibles -advancement.wizardry:wizard_trade=Comercio Magico -advancement.wizardry:wizard_trade.desc=Compra un objeto a un mago -advancement.wizardry:buy_master_spell=El Conocimiento es Poder -advancement.wizardry:buy_master_spell.desc=Compra un hechizo maestro a un mago -advancement.wizardry:freeze_blaze=Ya No Estas Tan Caliente -advancement.wizardry:freeze_blaze.desc=Congela a un blaze -advancement.wizardry:charge_creeper=Va a Explotar!! -advancement.wizardry:charge_creeper.desc='Accidentalmente' carga un creeper -advancement.wizardry:frankenstein=Frankenstein -advancement.wizardry:frankenstein.desc=Convierte a un cerdo en un hombrecerdo zombi usando el hechizo de rayo -advancement.wizardry:special_upgrade=Remiendo Arcano -advancement.wizardry:special_upgrade.desc=Aplica una mejora a una varita -advancement.wizardry:craft_flask=Es Magia, Embotellada! -advancement.wizardry:craft_flask.desc=Craftea un frasco de mana -advancement.wizardry:elemental=Elemental -advancement.wizardry:elemental.desc=Obten una varita elemental -advancement.wizardry:armour_set=Now Eres un Mago Apropiado -advancement.wizardry:armour_set.desc=Craftea y equipa el set completo de armadura de mago -advancement.wizardry:legendary=Legendario -advancement.wizardry:legendary.desc=Obten una pieza de armadura de mago legendaria -advancement.wizardry:self_destruct=Tiro por la culata -advancement.wizardry:self_destruct.desc=Muere por tu propia magia -advancement.wizardry:pig_tornado=No De Nuevo... -advancement.wizardry:pig_tornado.desc=Monta un cerdo hacia un tornado -advancement.wizardry:jam_wizard=Sesion de Interferencia -advancement.wizardry:jam_wizard.desc=Usa el hechizo arcano de interferencia en un mago -advancement.wizardry:slime_skeleton=Situacion Pegajosa -advancement.wizardry:slime_skeleton.desc=Sumerge un esqueleto en slime -advancement.wizardry:anger_wizard=Te Arrepentiras de Eso -advancement.wizardry:anger_wizard.desc=Haz que un mago se enoje -advancement.wizardry:defeat_evil_wizard=Justicia -advancement.wizardry:defeat_evil_wizard.desc=Derrota a un mago malvado -advancement.wizardry:max_out_wand=Equipada Al Maximo! -advancement.wizardry:max_out_wand.desc=Aplica el maximo numero de mejoras a una varita maestra -advancement.wizardry:element_master=Maestria Elemental -advancement.wizardry:element_master.desc=Lanza todos los hechizos de cualquier elemento -advancement.wizardry:identify_spell=Apreciacion Arcana -advancement.wizardry:identify_spell.desc=Usa un pergamino de la identificacion para identificar un libro de hechizos o pergamino +advancement.ebwizardry:root=Wizardry +advancement.ebwizardry:root.desc=Avances +advancement.ebwizardry:crystal=Un Cristral Curioso... +advancement.ebwizardry:crystal.desc=Pica un Cristal Magico +advancement.ebwizardry:arcane_initiate=Inicio Arcano +advancement.ebwizardry:arcane_initiate.desc=Craftea una varita magica con una pepita de oro, un palo y un cristal magico +advancement.ebwizardry:apprentice=Aprendiz de Mago +advancement.ebwizardry:apprentice.desc=Usa un tomo de lo arcano para mejorar tu varita +advancement.ebwizardry:master=Maestro Arcano +advancement.ebwizardry:master.desc=Obten una varita de maestro +advancement.ebwizardry:all_spells=Mago de Todos los Oficios +advancement.ebwizardry:all_spells.desc=Lanza todos los hechizos disponibles +advancement.ebwizardry:wizard_trade=Comercio Magico +advancement.ebwizardry:wizard_trade.desc=Compra un objeto a un mago +advancement.ebwizardry:buy_master_spell=El Conocimiento es Poder +advancement.ebwizardry:buy_master_spell.desc=Compra un hechizo maestro a un mago +advancement.ebwizardry:freeze_blaze=Ya No Estas Tan Caliente +advancement.ebwizardry:freeze_blaze.desc=Congela a un blaze +advancement.ebwizardry:charge_creeper=Va a Explotar!! +advancement.ebwizardry:charge_creeper.desc='Accidentalmente' carga un creeper +advancement.ebwizardry:frankenstein=Frankenstein +advancement.ebwizardry:frankenstein.desc=Convierte a un cerdo en un hombrecerdo zombi usando el hechizo de rayo +advancement.ebwizardry:special_upgrade=Remiendo Arcano +advancement.ebwizardry:special_upgrade.desc=Aplica una mejora a una varita +advancement.ebwizardry:craft_flask=Es Magia, Embotellada! +advancement.ebwizardry:craft_flask.desc=Craftea un frasco de mana +advancement.ebwizardry:elemental=Elemental +advancement.ebwizardry:elemental.desc=Obten una varita elemental +advancement.ebwizardry:armour_set=Now Eres un Mago Apropiado +advancement.ebwizardry:armour_set.desc=Craftea y equipa el set completo de armadura de mago +advancement.ebwizardry:legendary=Legendario +advancement.ebwizardry:legendary.desc=Obten una pieza de armadura de mago legendaria +advancement.ebwizardry:self_destruct=Tiro por la culata +advancement.ebwizardry:self_destruct.desc=Muere por tu propia magia +advancement.ebwizardry:pig_tornado=No De Nuevo... +advancement.ebwizardry:pig_tornado.desc=Monta un cerdo hacia un tornado +advancement.ebwizardry:jam_wizard=Sesion de Interferencia +advancement.ebwizardry:jam_wizard.desc=Usa el hechizo arcano de interferencia en un mago +advancement.ebwizardry:slime_skeleton=Situacion Pegajosa +advancement.ebwizardry:slime_skeleton.desc=Sumerge un esqueleto en slime +advancement.ebwizardry:anger_wizard=Te Arrepentiras de Eso +advancement.ebwizardry:anger_wizard.desc=Haz que un mago se enoje +advancement.ebwizardry:defeat_evil_wizard=Justicia +advancement.ebwizardry:defeat_evil_wizard.desc=Derrota a un mago malvado +advancement.ebwizardry:max_out_wand=Equipada Al Maximo! +advancement.ebwizardry:max_out_wand.desc=Aplica el maximo numero de mejoras a una varita maestra +advancement.ebwizardry:element_master=Maestria Elemental +advancement.ebwizardry:element_master.desc=Lanza todos los hechizos de cualquier elemento +advancement.ebwizardry:identify_spell=Apreciacion Arcana +advancement.ebwizardry:identify_spell.desc=Usa un pergamino de la identificacion para identificar un libro de hechizos o pergamino tile.ebwizardry:transportation_stone.confirm=A partir de ahora retornaras a este lugar cuando lances %1$s tile.ebwizardry:transportation_stone.invalid=Primero debes hacer un circulo con 8 piedras de transportacion! @@ -271,7 +271,7 @@ container.ebwizardry:arcane_workbench.apply=Aplicar container.ebwizardry:arcane_workbench.mana=Mana: container.ebwizardry:arcane_workbench.upgrades=Mejoras Aplicadas: -tier.basic=Novato +tier.novice=Novato tier.apprentice=Aprendiz tier.advanced=Avanzado tier.master=Maestro @@ -535,7 +535,7 @@ spell.ebwizardry:metamorphosis.desc=Cambia la forma del objetivo. Solo funciona spell.ebwizardry:meteor.desc=Algunos magos solo quieren ver el mundo arder... spell.ebwizardry:mind_control.desc=Toma control de la mente del objetivo por 30 segundos, provocando que cambie de bando y peleen a tu favor. No funciona con criaturas de voluntad muy fuerte. spell.ebwizardry:mind_trick.desc=Confunde y desorienta al objetivo por 15 segundos, volviendolo incapaz de atacar. El efecto se desactiva si el objetivo recibe dano. -spell.ebwizardry:none.desc=Para obtener un libro de hechizo con el comando /give, usa la metadata: /give [player] ebwizardry:spell_book 1 [spell id] (_si encontraste este libro en un cofre significa que otro mod esta alterando las cosas). +spell.ebwizardry:none.desc=Para obtener un libro de hechizo con el comando /give, usa la id: /give [player] ebwizardry:spell_book 1 [spell id] (_si encontraste este libro en un cofre significa que otro mod esta alterando las cosas). spell.ebwizardry:oakflesh.desc=Mejora la resistencia del amgo durante 30 segundos. spell.ebwizardry:petrify.desc=Convierte al objetivo en piedra hasta que se libere, con un chance de liberarse cuando se pone de noche. El objetivo no se puede mover ni atacar y no puede ser atacado. spell.ebwizardry:phase_step.desc=Transporta al mago a traves de una pared de 1 bloque de grosor. El rango mejora el grosor por el cual te puedes transportar. diff --git a/src/main/resources/assets/ebwizardry/lang/es_mx.lang b/src/main/resources/assets/ebwizardry/lang/es_mx.lang index 3287ca13..ae625e31 100644 --- a/src/main/resources/assets/ebwizardry/lang/es_mx.lang +++ b/src/main/resources/assets/ebwizardry/lang/es_mx.lang @@ -29,13 +29,13 @@ item.ebwizardry:wand.mana=Mana: %1$s/%2$s item.ebwizardry:wand.addally=%1$s ha sido anadido a tu lista de aliados item.ebwizardry:wand.removeally=%1$s ha sido removido a tu lista de aliados -item.ebwizardry:basic_fire_wand.name=Varita de Ascuas -item.ebwizardry:basic_ice_wand.name=Varita de Escarcha -item.ebwizardry:basic_lightning_wand.name=Varita de Chispas -item.ebwizardry:basic_necromancy_wand.name=Varita de las Sombras -item.ebwizardry:basic_earth_wand.name=Varita del Bosque -item.ebwizardry:basic_sorcery_wand.name=Varita del Misterio -item.ebwizardry:basic_healing_wand.name=Varita de la Curacion +item.ebwizardry:novice_fire_wand.name=Varita de Ascuas +item.ebwizardry:novice_ice_wand.name=Varita de Escarcha +item.ebwizardry:novice_lightning_wand.name=Varita de Chispas +item.ebwizardry:novice_necromancy_wand.name=Varita de las Sombras +item.ebwizardry:novice_earth_wand.name=Varita del Bosque +item.ebwizardry:novice_sorcery_wand.name=Varita del Misterio +item.ebwizardry:novice_healing_wand.name=Varita de la Curacion item.ebwizardry:apprentice_fire_wand.name=Varita del Piromano Aprendiz item.ebwizardry:apprentice_ice_wand.name=Varita del Mago de Hielo Aprendiz @@ -212,56 +212,56 @@ entity.ebwizardry:lightning_pulse.name=Pulso de Relampago item_group.ebwizardry=Wizardry item_group.wizardryspells=Hechizos de Wizardry -advancement.wizardry:root=Wizardry -advancement.wizardry:root.desc=Avances -advancement.wizardry:crystal=Un Cristral Curioso... -advancement.wizardry:crystal.desc=Pica un Cristal Magico -advancement.wizardry:arcane_initiate=Inicio Arcano -advancement.wizardry:arcane_initiate.desc=Craftea una varita magica con una pepita de oro, un palo y un cristal magico -advancement.wizardry:apprentice=Aprendiz de Mago -advancement.wizardry:apprentice.desc=Usa un tomo de lo arcano para mejorar tu varita -advancement.wizardry:master=Maestro Arcano -advancement.wizardry:master.desc=Obten una varita de maestro -advancement.wizardry:all_spells=Mago de Todos los Oficios -advancement.wizardry:all_spells.desc=Lanza todos los hechizos disponibles -advancement.wizardry:wizard_trade=Comercio Magico -advancement.wizardry:wizard_trade.desc=Compra un objeto a un mago -advancement.wizardry:buy_master_spell=El Conocimiento es Poder -advancement.wizardry:buy_master_spell.desc=Compra un hechizo maestro a un mago -advancement.wizardry:freeze_blaze=Ya No Estas Tan Caliente -advancement.wizardry:freeze_blaze.desc=Congela a un blaze -advancement.wizardry:charge_creeper=Va a Explotar!! -advancement.wizardry:charge_creeper.desc='Accidentalmente' carga un creeper -advancement.wizardry:frankenstein=Frankenstein -advancement.wizardry:frankenstein.desc=Convierte a un cerdo en un hombrecerdo zombi usando el hechizo de rayo -advancement.wizardry:special_upgrade=Remiendo Arcano -advancement.wizardry:special_upgrade.desc=Aplica una mejora a una varita -advancement.wizardry:craft_flask=Es Magia, Embotellada! -advancement.wizardry:craft_flask.desc=Craftea un frasco de mana -advancement.wizardry:elemental=Elemental -advancement.wizardry:elemental.desc=Obten una varita elemental -advancement.wizardry:armour_set=Now Eres un Mago Apropiado -advancement.wizardry:armour_set.desc=Craftea y equipa el set completo de armadura de mago -advancement.wizardry:legendary=Legendario -advancement.wizardry:legendary.desc=Obten una pieza de armadura de mago legendaria -advancement.wizardry:self_destruct=Tiro por la culata -advancement.wizardry:self_destruct.desc=Muere por tu propia magia -advancement.wizardry:pig_tornado=No De Nuevo... -advancement.wizardry:pig_tornado.desc=Monta un cerdo hacia un tornado -advancement.wizardry:jam_wizard=Sesion de Interferencia -advancement.wizardry:jam_wizard.desc=Usa el hechizo arcano de interferencia en un mago -advancement.wizardry:slime_skeleton=Situacion Pegajosa -advancement.wizardry:slime_skeleton.desc=Sumerge un esqueleto en slime -advancement.wizardry:anger_wizard=Te Arrepentiras de Eso -advancement.wizardry:anger_wizard.desc=Haz que un mago se enoje -advancement.wizardry:defeat_evil_wizard=Justicia -advancement.wizardry:defeat_evil_wizard.desc=Derrota a un mago malvado -advancement.wizardry:max_out_wand=Equipada Al Maximo! -advancement.wizardry:max_out_wand.desc=Aplica el maximo numero de mejoras a una varita maestra -advancement.wizardry:element_master=Maestria Elemental -advancement.wizardry:element_master.desc=Lanza todos los hechizos de cualquier elemento -advancement.wizardry:identify_spell=Apreciacion Arcana -advancement.wizardry:identify_spell.desc=Usa un pergamino de la identificacion para identificar un libro de hechizos o pergamino +advancement.ebwizardry:root=Wizardry +advancement.ebwizardry:root.desc=Avances +advancement.ebwizardry:crystal=Un Cristral Curioso... +advancement.ebwizardry:crystal.desc=Pica un Cristal Magico +advancement.ebwizardry:arcane_initiate=Inicio Arcano +advancement.ebwizardry:arcane_initiate.desc=Craftea una varita magica con una pepita de oro, un palo y un cristal magico +advancement.ebwizardry:apprentice=Aprendiz de Mago +advancement.ebwizardry:apprentice.desc=Usa un tomo de lo arcano para mejorar tu varita +advancement.ebwizardry:master=Maestro Arcano +advancement.ebwizardry:master.desc=Obten una varita de maestro +advancement.ebwizardry:all_spells=Mago de Todos los Oficios +advancement.ebwizardry:all_spells.desc=Lanza todos los hechizos disponibles +advancement.ebwizardry:wizard_trade=Comercio Magico +advancement.ebwizardry:wizard_trade.desc=Compra un objeto a un mago +advancement.ebwizardry:buy_master_spell=El Conocimiento es Poder +advancement.ebwizardry:buy_master_spell.desc=Compra un hechizo maestro a un mago +advancement.ebwizardry:freeze_blaze=Ya No Estas Tan Caliente +advancement.ebwizardry:freeze_blaze.desc=Congela a un blaze +advancement.ebwizardry:charge_creeper=Va a Explotar!! +advancement.ebwizardry:charge_creeper.desc='Accidentalmente' carga un creeper +advancement.ebwizardry:frankenstein=Frankenstein +advancement.ebwizardry:frankenstein.desc=Convierte a un cerdo en un hombrecerdo zombi usando el hechizo de rayo +advancement.ebwizardry:special_upgrade=Remiendo Arcano +advancement.ebwizardry:special_upgrade.desc=Aplica una mejora a una varita +advancement.ebwizardry:craft_flask=Es Magia, Embotellada! +advancement.ebwizardry:craft_flask.desc=Craftea un frasco de mana +advancement.ebwizardry:elemental=Elemental +advancement.ebwizardry:elemental.desc=Obten una varita elemental +advancement.ebwizardry:armour_set=Now Eres un Mago Apropiado +advancement.ebwizardry:armour_set.desc=Craftea y equipa el set completo de armadura de mago +advancement.ebwizardry:legendary=Legendario +advancement.ebwizardry:legendary.desc=Obten una pieza de armadura de mago legendaria +advancement.ebwizardry:self_destruct=Tiro por la culata +advancement.ebwizardry:self_destruct.desc=Muere por tu propia magia +advancement.ebwizardry:pig_tornado=No De Nuevo... +advancement.ebwizardry:pig_tornado.desc=Monta un cerdo hacia un tornado +advancement.ebwizardry:jam_wizard=Sesion de Interferencia +advancement.ebwizardry:jam_wizard.desc=Usa el hechizo arcano de interferencia en un mago +advancement.ebwizardry:slime_skeleton=Situacion Pegajosa +advancement.ebwizardry:slime_skeleton.desc=Sumerge un esqueleto en slime +advancement.ebwizardry:anger_wizard=Te Arrepentiras de Eso +advancement.ebwizardry:anger_wizard.desc=Haz que un mago se enoje +advancement.ebwizardry:defeat_evil_wizard=Justicia +advancement.ebwizardry:defeat_evil_wizard.desc=Derrota a un mago malvado +advancement.ebwizardry:max_out_wand=Equipada Al Maximo! +advancement.ebwizardry:max_out_wand.desc=Aplica el maximo numero de mejoras a una varita maestra +advancement.ebwizardry:element_master=Maestria Elemental +advancement.ebwizardry:element_master.desc=Lanza todos los hechizos de cualquier elemento +advancement.ebwizardry:identify_spell=Apreciacion Arcana +advancement.ebwizardry:identify_spell.desc=Usa un pergamino de la identificacion para identificar un libro de hechizos o pergamino tile.ebwizardry:transportation_stone.confirm=A partir de ahora retornaras a este lugar cuando lances %1$s tile.ebwizardry:transportation_stone.invalid=Primero debes hacer un circulo con 8 piedras de transportacion! @@ -271,7 +271,7 @@ container.ebwizardry:arcane_workbench.apply=Aplicar container.ebwizardry:arcane_workbench.mana=Mana: container.ebwizardry:arcane_workbench.upgrades=Mejoras Aplicadas: -tier.basic=Novato +tier.novice=Novato tier.apprentice=Aprendiz tier.advanced=Avanzado tier.master=Maestro @@ -535,7 +535,7 @@ spell.ebwizardry:metamorphosis.desc=Cambia la forma del objetivo. Solo funciona spell.ebwizardry:meteor.desc=Algunos magos solo quieren ver el mundo arder... spell.ebwizardry:mind_control.desc=Toma control de la mente del objetivo por 30 segundos, provocando que cambie de bando y peleen a tu favor. No funciona con criaturas de voluntad muy fuerte. spell.ebwizardry:mind_trick.desc=Confunde y desorienta al objetivo por 15 segundos, volviendolo incapaz de atacar. El efecto se desactiva si el objetivo recibe dano. -spell.ebwizardry:none.desc=Para obtener un libro de hechizo con el comando /give, usa la metadata: /give [player] ebwizardry:spell_book 1 [spell id] (_si encontraste este libro en un cofre significa que otro mod esta alterando las cosas). +spell.ebwizardry:none.desc=Para obtener un libro de hechizo con el comando /give, usa la id: /give [player] ebwizardry:spell_book 1 [spell id] (_si encontraste este libro en un cofre significa que otro mod esta alterando las cosas). spell.ebwizardry:oakflesh.desc=Mejora la resistencia del amgo durante 30 segundos. spell.ebwizardry:petrify.desc=Convierte al objetivo en piedra hasta que se libere, con un chance de liberarse cuando se pone de noche. El objetivo no se puede mover ni atacar y no puede ser atacado. spell.ebwizardry:phase_step.desc=Transporta al mago a traves de una pared de 1 bloque de grosor. El rango mejora el grosor por el cual te puedes transportar. diff --git a/src/main/resources/assets/ebwizardry/lang/fr_fr.lang b/src/main/resources/assets/ebwizardry/lang/fr_fr.lang new file mode 100644 index 00000000..b51fa23d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/lang/fr_fr.lang @@ -0,0 +1,760 @@ +tile.ebwizardry:arcane_workbench.name=Table des arcanes +tile.ebwizardry:crystal_ore.name=Minerais de cristal +tile.ebwizardry:petrified_stone.name=Roche pétrifiée +tile.ebwizardry:ice_statue.name=Statue de glace +tile.ebwizardry:crystal_flower.name=Fleur de cristal +tile.ebwizardry:snare.name=Ronces +tile.ebwizardry:transportation_stone.name=Pierre de Transportation +tile.ebwizardry:spectral_block.name=Bloc spectrale +tile.ebwizardry:crystal_block.name=Bloc de cristal + +item.ebwizardry:magic_crystal.name=Cristal magique +item.ebwizardry:magic_wand.name=Baguette magique +item.ebwizardry:apprentice_wand.name=Baguette d'apprenti +item.ebwizardry:advanced_wand.name=Baguette d'expert +item.ebwizardry:master_wand.name=Baguette de maître +item.ebwizardry:spell_book.name=Livre de sort + +item.ebwizardry:arcane_tome.name=Tome des arcanes +item.ebwizardry:arcane_tome.desc1=Améliore n'importe quelle +item.ebwizardry:arcane_tome.desc2=baguette du tier %1$s au tier %1$s + +item.ebwizardry:wizard_handbook.name=Le manuel du sorcier +item.ebwizardry:wizard_handbook.desc=par %1$s + +item.ebwizardry:wand.buff=+%1$s de puissance de %2$s +item.ebwizardry:wand.spell=Sort actuel: %1$s +item.ebwizardry:wand.mana=Mana: %1$s/%2$s + +item.ebwizardry:wand.addally=%1$s a été ajouté a vote liste d'alliés +item.ebwizardry:wand.removeally=%1$s a été retiré de votre liste d'alliés + +item.ebwizardry:basic_fire_wand.name=Baguette de braise +item.ebwizardry:basic_ice_wand.name=Baguette de gel +item.ebwizardry:basic_lightning_wand.name=Baguette d'étincelle +item.ebwizardry:basic_necromancy_wand.name=Baguette d'ombre +item.ebwizardry:basic_earth_wand.name=Bagette de bourgeon +item.ebwizardry:basic_sorcery_wand.name=Baguette de mystère +item.ebwizardry:basic_healing_wand.name=Baguette de soin + +item.ebwizardry:apprentice_fire_wand.name=Baguette d'apprenti pyromancien +item.ebwizardry:apprentice_ice_wand.name=Baguette d'apprenti cryomancien +item.ebwizardry:apprentice_lightning_wand.name=Baguette d'apprenti electromancien +item.ebwizardry:apprentice_necromancy_wand.name=Baguette d'apprenti necromancien +item.ebwizardry:apprentice_earth_wand.name=Baguette d'apprenti Geomancien +item.ebwizardry:apprentice_sorcery_wand.name=Baguette d'apprenti sorcier +item.ebwizardry:apprentice_healing_wand.name=Baguette d'apprenti soigneur + +item.ebwizardry:advanced_fire_wand.name=Baguette de brasier +item.ebwizardry:advanced_ice_wand.name=Baguette de blizzard +item.ebwizardry:advanced_lightning_wand.name=Baguette de foudre +item.ebwizardry:advanced_necromancy_wand.name=Baguette de necromancie +item.ebwizardry:advanced_earth_wand.name=Baguette de forêt +item.ebwizardry:advanced_sorcery_wand.name=Baguette de sorcier +item.ebwizardry:advanced_healing_wand.name=Baguette de soigneur + +item.ebwizardry:master_fire_wand.name=Baguette de maître pyromancien +item.ebwizardry:master_ice_wand.name=Baguette de maître cryomancien +item.ebwizardry:master_lightning_wand.name=Baguette de maître electromancien +item.ebwizardry:master_necromancy_wand.name=Baguette de maître necromancien +item.ebwizardry:master_earth_wand.name=Baguette de maître Geomancien +item.ebwizardry:master_sorcery_wand.name=Baguette de maître sorcier +item.ebwizardry:master_healing_wand.name=Baguette de maître soigneur + +item.ebwizardry:spectral_sword.name=Epée spectrale +item.ebwizardry:spectral_pickaxe.name=Pioche spectrale +item.ebwizardry:spectral_bow.name=Arc spectral + +item.ebwizardry:mana_flask.name=Fiole de mana +item.ebwizardry:storage_upgrade.name=Amélioration de baguette de capacité de mana +item.ebwizardry:siphon_upgrade.name=Amélioration de baguette de siphon de mana +item.ebwizardry:condenser_upgrade.name=Amélioration de puissance de baguette +item.ebwizardry:range_upgrade.name=Amélioration de portée de baguette +item.ebwizardry:duration_upgrade.name=Amélioration de durée de sort +item.ebwizardry:cooldown_upgrade.name=Amélioration de temps de rechargement de baguette +item.ebwizardry:blast_upgrade.name=Amélioration d'explosion de sort +item.ebwizardry:attunement_upgrade.name=Amélioration d'harmonisation de baguette + +item.ebwizardry:flaming_axe.name=Hache enflammée +item.ebwizardry:frost_axe.name=Hache gelée + +item.ebwizardry:firebomb.name=Bombe de feu +item.ebwizardry:poison_bomb.name=Bombe de poison +item.ebwizardry:smoke_bomb.name=Bombe de fumée + +item.ebwizardry:blank_scroll.name=Parchemin vierge +item.ebwizardry:scroll.name=Parchemin de %1$s +item.ebwizardry:scroll.undiscovered.name=Parchemin de "%1$s" +item.ebwizardry:identification_scroll.name=Parchemin d'identification +item.ebwizardry:identification_scroll.desc1=%1$sIdentifie un livre ou un +item.ebwizardry:identification_scroll.desc2=%1$sparchemin de sort inconnu +item.ebwizardry:identification_scroll.nothing_to_identify=Il n'y a rien à identifier! + +item.ebwizardry:armour_upgrade.name=Sceau arcanique de protection +item.ebwizardry:armour_upgrade.desc1=%1$sAméliore n'importe quelle +item.ebwizardry:armour_upgrade.desc2=%1$srobe au tier %2$slegendaire + +item.ebwizardry:magic_silk.name=Soie magique + +item.ebwizardry:wizard_armour.legendary=Legendaire +item.ebwizardry:wizard_armour.buff=-%1$s en coût de %2$s +item.ebwizardry:wizard_armour.mana=Mana: %1$s/%2$s + +item.ebwizardry:wizard_hat.name=Chapeau de sorcier +item.ebwizardry:wizard_robe.name=Robe de sorcier +item.ebwizardry:wizard_leggings.name=Pantalon de sorcier +item.ebwizardry:wizard_boots.name=Chaussures de sorcier + +item.ebwizardry:wizard_hat_fire.name=Chapeau de pyromancien +item.ebwizardry:wizard_robe_fire.name=Robe de pyromancien +item.ebwizardry:wizard_leggings_fire.name=Pantalon de pyromancien +item.ebwizardry:wizard_boots_fire.name=Bottes de pyromancien + +item.ebwizardry:wizard_hat_ice.name=Chapeau de cryomancien +item.ebwizardry:wizard_robe_ice.name=Robe de cryomancien +item.ebwizardry:wizard_leggings_ice.name=Pentalon de cryomancien +item.ebwizardry:wizard_boots_ice.name=Bottes de cryomancien + +item.ebwizardry:wizard_hat_lightning.name=Chapeau d'electomancien +item.ebwizardry:wizard_robe_lightning.name=Robe d'electromancien +item.ebwizardry:wizard_leggings_lightning.name=Pentalon d'electromancien +item.ebwizardry:wizard_boots_lightning.name=Bottes d'electromancien + +item.ebwizardry:wizard_hat_necromancy.name=Chapeau de necromancie +item.ebwizardry:wizard_robe_necromancy.name=Robe de necromancien +item.ebwizardry:wizard_leggings_necromancy.name=Pentalon de necromacien +item.ebwizardry:wizard_boots_necromancy.name=Bottes de necromancie + +item.ebwizardry:wizard_hat_earth.name=Chapeau de Geomancien +item.ebwizardry:wizard_robe_earth.name=Robe de Geomancien +item.ebwizardry:wizard_leggings_earth.name=Pentalon de Geomancien +item.ebwizardry:wizard_boots_earth.name=Bottes de Geomancien + +item.ebwizardry:wizard_hat_sorcery.name=Chapeau de sorcier +item.ebwizardry:wizard_robe_sorcery.name=Robe de sorcier +item.ebwizardry:wizard_leggings_sorcery.name=Pentalon de sorcier +item.ebwizardry:wizard_boots_sorcery.name=Bottes de sorcier + +item.ebwizardry:wizard_hat_healing.name=Chapeau de soigneur +item.ebwizardry:wizard_robe_healing.name=Robe de soigneur +item.ebwizardry:wizard_leggings_healing.name=Pentalon de soigneur +item.ebwizardry:wizard_boots_healing.name=Bottes de soigneur + +item.ebwizardry:spawn_wizard.name=Oeuf de sorcier +item.ebwizardry:spawn_evil_wizard.name=Oeuf de sorcier maléfique + +item.ebwizardry:spectral_helmet.name=Casque spectral +item.ebwizardry:spectral_chestplate.name=Plastron spectral +item.ebwizardry:spectral_leggings.name=Jambières spectrales +item.ebwizardry:spectral_boots.name=Bottes spectrales + +entity.ebwizardry:summonedcreature.nameplate=%1$s's %2$s +entity.ebwizardry:summonedcreature.nameplate_fallback=Someone's %1$s + +entity.ebwizardry:zombie_minion.name=Zombie +entity.ebwizardry:skeleton_minion.name=Squelette +entity.ebwizardry:spider_minion.name=Araignée +entity.ebwizardry:blaze_minion.name=Blaze +entity.ebwizardry:wither_skeleton_minion.name=Wither squelette +entity.ebwizardry:ice_wraith.name=Spectre de glace +entity.ebwizardry:lightning_wraith.name=Spectre de foudre +entity.ebwizardry:shadow_wraith.name=Spectre d'ombre +entity.ebwizardry:spirit_wolf.name=Esprit de loup +entity.ebwizardry:spirit_horse.name=Esprit de cheval +entity.ebwizardry:ice_giant.name=Geant de glace +entity.ebwizardry:phoenix.name=Phoenix +entity.ebwizardry:wizard.name=Sorcier +entity.ebwizardry:magic_slime.name=Slime magique +entity.ebwizardry:silverfish_minion.name=Poisson d'argent +entity.ebwizardry:storm_elemental.name=Tempête elementaire +entity.ebwizardry:evil_wizard.name=Sorcier +entity.ebwizardry:decoy.name=Leurre + +entity.ebwizardry:magic_missile.name=Magique +entity.ebwizardry:arc.name=Magique +entity.ebwizardry:spark_bomb.name=Magique +entity.ebwizardry:ice_shard.name=Magique +entity.ebwizardry:firebomb.name=Magique +entity.ebwizardry:poison_bomb.name=Magique +entity.ebwizardry:force_orb.name=Magique +entity.ebwizardry:spark.name=Magique +entity.ebwizardry:darkness_orb.name=Magique +entity.ebwizardry:fire_sigil.name=Magique +entity.ebwizardry:frost_sigil.name=Magique +entity.ebwizardry:lightning_sigil.name=Magique +entity.ebwizardry:lightning_arrow.name=Magique +entity.ebwizardry:firebolt.name=Magique +entity.ebwizardry:ice_charge.name=Magique +entity.ebwizardry:force_arrow.name=Magique +entity.ebwizardry:dart.name=Magique +entity.ebwizardry:lightning_disc.name=Magique +entity.ebwizardry:thunderbolt.name=Magique +entity.ebwizardry:decay.name=Magique +entity.ebwizardry:ice_lance.name=Magique +entity.ebwizardry:smoke_bomb.name=Magique +entity.ebwizardry:ice_spike.name=Magique + +entity.ebwizardry:black_hole.name=Trou noir +entity.ebwizardry:shield.name=Bouclier +entity.ebwizardry:meteor.name=Meteor +entity.ebwizardry:blizzard.name=Blizzard +entity.ebwizardry:bubble.name=Bulle +entity.ebwizardry:tornado.name=Tornade +entity.ebwizardry:lightning_hammer.name=Marteau de foudre +entity.ebwizardry:arrow_rain.name=Pluie de flèches +entity.ebwizardry:healing_aura.name=Aura de soin +entity.ebwizardry:forcefield.name=Champ de force +entity.ebwizardry:ring_of_fire.name=Anneau de feu +entity.ebwizardry:earthquake.name=Seisme +entity.ebwizardry:falling_grass.name=Chute d'herbe +entity.ebwizardry:hailstorm.name=Grêle +entity.ebwizardry:lightning_pulse.name=Pulsation electrique + +itemGroup.ebwizardry=Wizardry +itemGroup.ebwizardryspells=Spells + +advancement.ebwizardry:root=Sorcier +advancement.ebwizardry:root.desc=Le voyage d'un sorcier pour maîtriser les arcanes +advancement.ebwizardry:crystal=Un mystérieux cristal... +advancement.ebwizardry:crystal.desc=Miner un cristal magique +advancement.ebwizardry:arcane_initiate=Initiation arcanique +advancement.ebwizardry:arcane_initiate.desc=Fabriquer une baguette magique avec une pépite d'or, un bâton et un cristal magique +advancement.ebwizardry:apprentice=Apprenti Magicien +advancement.ebwizardry:apprentice.desc=Utilisez un tome d'arcane pour améliorer votre baguette +advancement.ebwizardry:master=Maître des Arcanes +advancement.ebwizardry:master.desc=Obtenir une baguette de maître +advancement.ebwizardry:all_spells=Mage de tous les métiers +advancement.ebwizardry:all_spells.desc=Lancer chaque sort du jeu +advancement.ebwizardry:wizard_trade=Transaction magique +advancement.ebwizardry:wizard_trade.desc=Acheter un objet auprès d'un sorcier +advancement.ebwizardry:buy_master_spell=Le savoir c'est le pouvoir +advancement.ebwizardry:buy_master_spell.desc=Acheter un sort de maître auprès d'un sorcier +advancement.ebwizardry:freeze_blaze=Petite brise... +advancement.ebwizardry:freeze_blaze.desc=Geler un blaze +advancement.ebwizardry:charge_creeper=Ça va peter! +advancement.ebwizardry:charge_creeper.desc=Charger accidentellement un creeper +advancement.ebwizardry:frankenstein=Frankenstein +advancement.ebwizardry:frankenstein.desc=Transformer un cochon en zombie cochon avec un éclair +advancement.ebwizardry:special_upgrade=Bricolage arcanique +advancement.ebwizardry:special_upgrade.desc=Appliquer une amélioration à une baguette +advancement.ebwizardry:craft_flask=De la magie en bouteille! +advancement.ebwizardry:craft_flask.desc=Fabriquer une fiole de mana +advancement.ebwizardry:elemental=Elementaire +advancement.ebwizardry:elemental.desc=Obtenir une baguette elementaire +advancement.ebwizardry:armour_set=Tu est un sorcier, Harry +advancement.ebwizardry:armour_set.desc=Fabriquer et equiper un set complet de sorcier +advancement.ebwizardry:legendary=Legendaire +advancement.ebwizardry:legendary.desc=Obtenir une pièce d'armure légendaire de sorcier +advancement.ebwizardry:self_destruct=Retour de flammes +advancement.ebwizardry:self_destruct.desc=Mourrir de sa propre magie +advancement.ebwizardry:pig_tornado=Pas encore... +advancement.ebwizardry:pig_tornado.desc=Monter un cochon dans une tornade +advancement.ebwizardry:jam_wizard=Perturbation arcanique +advancement.ebwizardry:jam_wizard.desc=Utiliser le sort de perturbation sur un sorcier +advancement.ebwizardry:slime_skeleton=Situation collante +advancement.ebwizardry:slime_skeleton.desc=Engluer un squelette dans un slime +advancement.ebwizardry:anger_wizard=Tu va le regreter... +advancement.ebwizardry:anger_wizard.desc=Enerver un sorcier +advancement.ebwizardry:defeat_evil_wizard=Mage vertueux +advancement.ebwizardry:defeat_evil_wizard.desc=Tuer un sorcier maléfique +advancement.ebwizardry:max_out_wand=Equipé de pied en cap +advancement.ebwizardry:max_out_wand.desc=Appliquer le maximum d'amélioration à une baguette de maître +advancement.ebwizardry:element_master=Maître des éléments +advancement.ebwizardry:element_master.desc=Lancer tout les sorts d'un élément +advancement.ebwizardry:identify_spell=Examin arcanique +advancement.ebwizardry:identify_spell.desc=Utiliser un parchemin pour identifier un livre ou un autre parchemin + +tile.ebwizardry:transportation_stone.confirm=Vous pouvez désormais revenir ici plus tard en lançant le sort %1$s +tile.ebwizardry:transportation_stone.invalid=Vous devez dabord faire un carré avec 8 pierres de transportation et vous y lier avec une baguette! + +container.ebwizardry:arcane_workbench=Table des arcanes +container.ebwizardry:arcane_workbench.apply=Appliquer +container.ebwizardry:arcane_workbench.mana=Mana: +container.ebwizardry:arcane_workbench.upgrades=Amélioration appliquée: + +tier.basic=Novice +tier.apprentice=Apprenti +tier.advanced=Expert +tier.master=Maître + +element.simple=Aucun +element.fire=Feu +element.ice=Glace +element.lightning=Foudre +element.necromancy=Necromancie +element.earth=Terra +element.sorcery=Sorcellerie +element.healing=Soin + +element.simple.wizard=Sorcier +element.fire.wizard=Pyromancien +element.ice.wizard=Cryomancien +element.lightning.wizard=Electromancien +element.necromancy.wizard=Necromancien +element.earth.wizard=Geomancien +element.sorcery.wizard=Sorcier +element.healing.wizard=Soigneur + +spelltype.attack=Attaque +spelltype.defence=Defense +spelltype.utility=Utilité +spelltype.minion=Sbire + +spell.disabled=%1$s a été désactivé dans la config! +spell.resist=%1$s a résisté à %2$s +spell.discover=Le sort %1$s a été découvert! + +spell.ebwizardry:agility=Agilité +spell.ebwizardry:arc=Arc +spell.ebwizardry:arcane_jammer=Perturbation arcanique +spell.ebwizardry:arrow_rain=Pluie de flèche +spell.ebwizardry:banish=Banissement +spell.ebwizardry:black_hole=Trou noir +spell.ebwizardry:blink=Teleportation +spell.ebwizardry:blizzard=Blizzard +spell.ebwizardry:bubble=Bulle +spell.ebwizardry:chain_lightning=Chaîne d'éclair +spell.ebwizardry:clairvoyance=Clairvoyance +spell.ebwizardry:cobwebs=Toile +spell.ebwizardry:conjure_armour=Conjuration d'armure +spell.ebwizardry:conjure_bow=Conjuration d'arc +spell.ebwizardry:conjure_pickaxe=Conjuration de pioche +spell.ebwizardry:conjure_sword=Conjuration d'épée +spell.ebwizardry:cure_effects=Curation +spell.ebwizardry:curse_of_soulbinding=Malédiction de liaison d'âme +spell.ebwizardry:darkness_orb=Orbe de ténèbre +spell.ebwizardry:darkvision=Nyctalopie +spell.ebwizardry:dart=Dard +spell.ebwizardry:decay=Decomposition +spell.ebwizardry:decoy=Leurre +spell.ebwizardry:detonate=Detonation +spell.ebwizardry:diamondflesh=Peau de diamant +spell.ebwizardry:earthquake=Seisme +spell.ebwizardry:entrapment=Piège de ténèbre +spell.ebwizardry:fireball=Boule de feu +spell.ebwizardry:firebolt=Eclair de feu +spell.ebwizardry:firebomb=Bombe de feu +spell.ebwizardry:fire_resistance=Resistance aux flammes +spell.ebwizardry:fire_sigil=Rune de feu +spell.ebwizardry:fireskin=Aura de feu +spell.ebwizardry:firestorm=Tempête de feu +spell.ebwizardry:flame_ray=Trait de feu +spell.ebwizardry:flaming_axe=Hache enflammé +spell.ebwizardry:flaming_weapon=Enflamment d'arme +spell.ebwizardry:flight=Vol +spell.ebwizardry:font_of_mana=Fontaine de mana +spell.ebwizardry:font_of_vitality=Fontaine de vitalité +spell.ebwizardry:force_arrow=Flèche de force +spell.ebwizardry:forcefield=Champ de force +spell.ebwizardry:force_orb=Orbe de force +spell.ebwizardry:forests_curse=Malédiction de la forêt +spell.ebwizardry:freeze=Gel +spell.ebwizardry:freezing_weapon=Gel d'arme +spell.ebwizardry:frost_axe=Hache de glace +spell.ebwizardry:frost_ray=Trait de glace +spell.ebwizardry:frost_sigil=Rune de glace +spell.ebwizardry:glide=Vol plané +spell.ebwizardry:greater_fireball=Grosse boule de feu +spell.ebwizardry:greater_heal=Soin magistral +spell.ebwizardry:group_heal=Soin de groupe +spell.ebwizardry:growth_aura=Aura de croissance +spell.ebwizardry:hailstorm=Grêle +spell.ebwizardry:heal=Soin +spell.ebwizardry:heal_ally=Touché soignant +spell.ebwizardry:healing_aura=Aura de soin +spell.ebwizardry:homing_spark=Etincelle auto-guidé +spell.ebwizardry:ice_age=Âge de glace +spell.ebwizardry:ice_charge=Charge de glace +spell.ebwizardry:ice_lance=Lance de glace +spell.ebwizardry:ice_shard=Eclat de glace +spell.ebwizardry:ice_shroud=Aura de glace +spell.ebwizardry:ice_spikes=Pic de glace +spell.ebwizardry:ice_statue=Statue de glace +spell.ebwizardry:ignite=Enflammer +spell.ebwizardry:imbue_weapon=imprégnation d'arme +spell.ebwizardry:intimidate=Intimidation +spell.ebwizardry:invigorating_presence=Présance tonifiante +spell.ebwizardry:invisibility=Invisibilité +spell.ebwizardry:invoke_weather=Tempête +spell.ebwizardry:ironflesh=Peau de fer +spell.ebwizardry:leap=Saut +spell.ebwizardry:levitation=Levitation +spell.ebwizardry:life_drain=Drain de vie +spell.ebwizardry:light=Lumière +spell.ebwizardry:lightning_arrow=Flèche de foudre +spell.ebwizardry:lightning_bolt=Eclair +spell.ebwizardry:lightning_disc=Disque de foudre +spell.ebwizardry:lightning_hammer=Marteau de foudre +spell.ebwizardry:lightning_pulse=Pulsation electrique +spell.ebwizardry:lightning_ray=Trait de foudre +spell.ebwizardry:lightning_sigil=Rune de foudre +spell.ebwizardry:lightning_web=Eclair en chaîne +spell.ebwizardry:magic_missile=Missile magique +spell.ebwizardry:metamorphosis=Metamorphose +spell.ebwizardry:meteor=Meteor +spell.ebwizardry:mind_control=Hypnose +spell.ebwizardry:mind_trick=Confusion +spell.ebwizardry:none=[Emplacement vide] +spell.ebwizardry:oakflesh=Peau de chêne +spell.ebwizardry:petrify=Petrification +spell.ebwizardry:phase_step=Passe muraille +spell.ebwizardry:plague_of_darkness=Peste ténébreuse +spell.ebwizardry:pocket_furnace=Cuisson +spell.ebwizardry:pocket_workbench=Conjuration d'etabli +spell.ebwizardry:poison=Poison +spell.ebwizardry:poison_bomb=Bombe de poison +spell.ebwizardry:replenish_hunger=Restoration +spell.ebwizardry:ring_of_fire=Anneau de feu +spell.ebwizardry:shadow_ward=Miroir d'ombre +spell.ebwizardry:shield=Barrière +spell.ebwizardry:shockwave=Onde de choc +spell.ebwizardry:silverfish_swarm=Essaim de poisson d'argent +spell.ebwizardry:sixth_sense=Sixième sense +spell.ebwizardry:slime=Slime +spell.ebwizardry:smoke_bomb=Bombe de fumée +spell.ebwizardry:snare=Ronce +spell.ebwizardry:snowball=Boule de neige +spell.ebwizardry:spark_bomb=Bombe electrique +spell.ebwizardry:spectral_pathway=Chemin spectral +spell.ebwizardry:spider_swarm=Essaim d'araignées +spell.ebwizardry:static_aura=Aura electrique +spell.ebwizardry:summon_blaze=Invocation de blaize +spell.ebwizardry:summon_ice_giant=Invocation de geant de glace +spell.ebwizardry:summon_ice_wraith=Invocation de spectre de glace +spell.ebwizardry:summon_iron_golem=Invocation de golem de fer +spell.ebwizardry:summon_lightning_wraith=Invocation de spectre de foudre +spell.ebwizardry:summon_phoenix=Invocation de Phoenix +spell.ebwizardry:summon_shadow_wraith=Invocation de spectre d'ombre +spell.ebwizardry:summon_skeleton=Invocation de squelette +spell.ebwizardry:summon_skeleton_legion=Invocation de legion de squelette +spell.ebwizardry:summon_snow_golem=Invocation de golem de neige +spell.ebwizardry:summon_spirit_horse=Invocation de cheval spectral +spell.ebwizardry:summon_spirit_wolf=Invocation de chien spectral +spell.ebwizardry:summon_storm_elemental=Invocation d'élémentaire de foudre +spell.ebwizardry:summon_wither_skeleton=Invocation de squelette wither +spell.ebwizardry:summon_zombie=Invocation de zombie +spell.ebwizardry:telekinesis=Telekinesie +spell.ebwizardry:thunderbolt=Coup de tonnerre +spell.ebwizardry:thunderstorm=Orage +spell.ebwizardry:tornado=Tornade +spell.ebwizardry:transience=Forme éthérée +spell.ebwizardry:transportation=Transportation +spell.ebwizardry:vanishing_box=Conjuration de coffre de l'ender +spell.ebwizardry:wall_of_frost=Mur de glace +spell.ebwizardry:water_breathing=Respiration aquatique +spell.ebwizardry:whirlwind=Bourrasque +spell.ebwizardry:wither=Wither +spell.ebwizardry:wither_skull=Crâne de wither + +spell.ebwizardry:agility.desc=Augmente la vitesse de déplacement et la hauteur de saut du lanceur pendant 30 secondes. +spell.ebwizardry:arc.desc=Tire une étincelle de foudre sur la cible. +spell.ebwizardry:arcane_jammer.desc=Empêche la cible d'utiliser la magie pendant 15 secondes. +spell.ebwizardry:arrow_rain.desc="Archers, tirez!" +spell.ebwizardry:banish.desc=Téléporte la cible contre sa volonté vers un emplacement aléatoire dans une certaine distance. +spell.ebwizardry:black_hole.desc=Déchirez la réalité. +spell.ebwizardry:blink.desc=Téléporte le lanceur sur une courte distance à l'endroit où il se vise. +spell.ebwizardry:blizzard.desc=Crée une zone de vent glacé tourbillonnant qui ralentit et endommage continuellement tout ce qui est piégé à l'intérieur. Le lanceur est immunisé contre les dégâts, mais il est quand même ralenti. +spell.ebwizardry:bubble.desc=Lance un jet de bulles qui capture tout ce qu’il frappe dans une bulle qui flottera vers le haut. La cible tombera après un certain temps ou si la bulle est endommagée. +spell.ebwizardry:chain_lightning.desc=Lance une étincelle de foudre sur la cible, qui frappe ensuite deux cibles supplémentaires. +spell.ebwizardry:clairvoyance.desc=Révèle le chemin vers un lieu mémorisé. Avec ce sort sélectionné, sneak-cliquez sur un bloc pour définir l'emplacement. Jetez ce sort normalement pour révéler le chemin. Le chemin disparaîtra au bout de 90 secondes. +spell.ebwizardry:cobwebs.desc=Crée des toiles d'araignées à l'endroit que vous visez, ce qui gêne grandement le mouvement des créatures prises dedans. Les toiles d'araignées disparaîtront après 20 secondes ou si elles sont cassées. +spell.ebwizardry:conjure_armour.desc=Crée une armure spectrale autour du lanceur qui offre une protection égale à celle d’une armure de fer. L'armure dure 60 secondes. Le lanceur doit avoir un emplacement d'armure vide. +spell.ebwizardry:conjure_bow.desc=Crée un arc spectral avec des flèches illimitées qui dure 30 secondes. +spell.ebwizardry:conjure_pickaxe.desc=Crée une pioche spectrale de force égale à une pioche de fer qui dure 30 secondes. +spell.ebwizardry:conjure_sword.desc=Crée une épée spectrale de force égale à une épée de fer qui dure 30 secondes. +spell.ebwizardry:cure_effects.desc=Supprime tous les effets de potion affectant actuellement le lanceur, bons ou mauvais. +spell.ebwizardry:curse_of_soulbinding.desc=Fait en sorte que l'âme de la cible soit inextricablement liée à celle du lanceur, ce qui signifie que tous les dommages qui lui sont infligés sont également infligés à la victime. Dure jusqu'à ce que la victime ou le lanceur meurt. +spell.ebwizardry:darkness_orb.desc=Tire un orbe d'énergie sombre se déplaçant lentement dans la direction que vous visez, causant l'effet wither à ce qu'il frappera. +spell.ebwizardry:darkvision.desc=Donne la vision nocturne au lanceur pendant 45 secondes. +spell.ebwizardry:dart.desc=Tire une flèche dans la direction que vous visez qui endommage et affaiblit sa cible. +spell.ebwizardry:decay.desc=Crée une flaque de décomposition sur le sol qui infecte toute créature qui la touche, causant des dégâts persistants au fil du temps et générant d'avantage de décomposition partout où elle se promène. +spell.ebwizardry:decoy.desc=Crée un clone illusoire du lanceur qui incite les monstres à l'attaquer à la place. Le leurre disparaîtra au bout de 30 secondes. +spell.ebwizardry:detonate.desc=Provoque une explosion à l'endroit où vous vous visez, causant des dommages à toutes les créatures proches, y compris le lanceur, si il est trop proche. +spell.ebwizardry:diamondflesh.desc="Vos flèches ne sont pas de taille contre moi!" +spell.ebwizardry:earthquake.desc=Un vrai maître de la magie de la terre peut déplacer des montagnes. +spell.ebwizardry:entrapment.desc=Enferme la cible dans une sphère de ténèbres qui la tire de façon impuissante vers le haut et l’endommage continuellement. +spell.ebwizardry:fireball.desc=Lance une boule de feu dans la direction que vous pointez. +spell.ebwizardry:firebolt.desc=Lance un jet de feu à une courte distance de vous. +spell.ebwizardry:firebomb.desc=Déclenche une bombe incendiaire dans la direction que vous pointez qui explose sous l’impact, ce qui met le feu à vos cibles. +spell.ebwizardry:fire_resistance.desc=Confère au lanceur une résistance au feu pendant 30 secondes. +spell.ebwizardry:fire_sigil.desc=Place un piège magique sur le sol qui endommage et met le feu à la créature qui le déclenche. +spell.ebwizardry:fireskin.desc=Le lanceur s'enveloppe de feu pendant 30 secondes, ce qui fait s'enflammer tout ce qui l'attaque. +spell.ebwizardry:firestorm.desc="Je suis le Dragon" +spell.ebwizardry:flame_ray.desc=Crée un souffle de flammes dans la direction que vous pointez qui enflamme et endommage continuellement les cibles. +spell.ebwizardry:flaming_axe.desc=Crée une hache enflammée qui met le feu à l'ennemi lorsqu'il est touché. Dure 30 secondes. +spell.ebwizardry:flaming_weapon.desc=La première arme de la barre de raccourci du lanceur est temporairement imprégnée du pouvoir de la flamme, ce qui incendie ses victimes. L'effet disparaît après 45 secondes. +spell.ebwizardry:flight.desc=Volez comme un aigle. +spell.ebwizardry:font_of_mana.desc="Nous étions remplis d'une intense énergie magique semblant émaner du centre de la ..." - Extrait du journal d'un mage oublié; le reste de la page a été brûlé. +spell.ebwizardry:font_of_vitality.desc=C'est incroyable. +spell.ebwizardry:force_arrow.desc=Tire une flèche de force dans la direction que vous pointez. +spell.ebwizardry:forcefield.desc=Crée un champ de force autour du lanceur qui repousse les créatures et dévie les projectiles. +spell.ebwizardry:force_orb.desc=Lance une sphère de force qui endommage et repousse les créatures proches lors de l'impact. +spell.ebwizardry:forests_curse.desc="Comment osez-vous entrer dans ma forêt!" +spell.ebwizardry:freeze.desc=Gèle la cible pendant 10 secondes. Peut également geler l'eau et créer de la neige sur le sol. +spell.ebwizardry:freezing_weapon.desc=La première arme située sur la barre de raccourci du lanceur est temporairement imprégnée de gel, ce qui gèle ses victimes. L'effet disparaît après 45 secondes. +spell.ebwizardry:frost_axe.desc=Crée une hache gelée qui gèle les ennemis quand ils sont touchés. Dure 30 secondes. +spell.ebwizardry:frost_ray.desc=Crée un jet de givre dans la direction que vous visez, ce qui ralentit et endommage continuellement les cibles. +spell.ebwizardry:frost_sigil.desc=Place un piège de glace magique sur le sol qui endommage et gèle la créature qui le déclenche. +spell.ebwizardry:glide.desc=Permet au lanceur de planer en l'air tout en maintenant enfoncé le bouton d'utilisation. +spell.ebwizardry:greater_fireball.desc=Lance une grosse boule de feu dans la direction que vous pointez qui explose à l’impact. +spell.ebwizardry:greater_heal.desc=Soigne le lanceur de 4 coeurs. +spell.ebwizardry:group_heal.desc=Soigne le lanceur et tous les alliés proches et les créatures invoquées de 3 coeurs. +spell.ebwizardry:growth_aura.desc=Fais pousser toutes les cultures près du lanceur. Fais pousser également des herbes hautes et des fleurs sur l’herbe. +spell.ebwizardry:hailstorm.desc=C'est au cours du grand hiver du troisième âge que les mages de glace ont découvert leur véritable pouvoir. +spell.ebwizardry:heal.desc=Soigne le lanceur de sorts de 2 coeurs. +spell.ebwizardry:heal_ally.desc=Soigne la cible de 2 cœurs et demi. +spell.ebwizardry:healing_aura.desc=Crée une zone d'énergie de guérison qui régénère la santé de tous les alliés qui s'y trouvent. Tout mort-vivant à l'intérieur de l'aura de guérison subira lentement des dégâts. +spell.ebwizardry:homing_spark.desc=Crée une étincelle flottante qui se déplace vers les ennemis. +spell.ebwizardry:ice_age.desc="Vous serez gelés pour une éternité!" +spell.ebwizardry:ice_charge.desc=Lance une charge de glace qui explose à l’impact, gèle les créatures proches et libère des éclats dans toutes les directions. +spell.ebwizardry:ice_lance.desc=Tire une grande lance de glace dans la direction que vous pointez, qui transperce les cibles, les endommageant et les gelant. +spell.ebwizardry:ice_shard.desc=Tire un éclat de glace dans la direction que vous pointez qui endommage et ralentit les cibles. +spell.ebwizardry:ice_shroud.desc=Crée un voile de froid autour du lanceur pendant 30 secondes, ce qui bloque tout les attaques. +spell.ebwizardry:ice_spikes.desc=Invoque des pointes de glace acérées comme des lames de rasoir qui s'élèvent du sol à l'endroit où vous visez, embrochant ainsi toutes les créatures dans la zone. +spell.ebwizardry:ice_statue.desc=Congèle entierement la cible pendant 20 secondes ou jusqu'à ce qu'elle soit cassée. La cible ne peut pas bouger ni faire quoi que ce soit tant qu'elle est gelée, mais est également insensible à tous les dégâts. +spell.ebwizardry:ignite.desc=Met le feu à la cible pendant 10 secondes. Fonctionne également comme un briquet. +spell.ebwizardry:imbue_weapon.desc=Imprègne temporairement la première arme de la barre de raccourci du lanceur pour la rendre plus efficace. L'effet disparaît après 45 secondes. +spell.ebwizardry:intimidate.desc=Émet un grondement intimidant qui provoque la peur des créatures proches. Les créatures frappées par la peur vont récupérer leur état normal après 30 secondes. +spell.ebwizardry:invigorating_presence.desc=Confère au lanceur et à tous les alliés à proximité une force accrue pendant 45 secondes. +spell.ebwizardry:invisibility.desc=Rend le lanceur invisible pendant 30 secondes. +spell.ebwizardry:invoke_weather.desc=Change la météo dans le monde. +spell.ebwizardry:ironflesh.desc=Améliore considérablement la résistance aux dégâts du lanceur pendant 30 secondes. +spell.ebwizardry:leap.desc=Le lanceur effectue un super saut. +spell.ebwizardry:levitation.desc=Fait léviter le lanceur vers le haut pendant que le bouton d'utilisation est maintenu enfoncé. Annulera également les dégâts de chute si utilisé avant de heurter le sol. +spell.ebwizardry:life_drain.desc=Crée un flux d’énergie de wither dans la direction que vous visez qui draine la vie de la cible et l’utilise pour régénérer progressivement votre santé. +spell.ebwizardry:light.desc=Crée un point de lumière magique qui illumine les environs. Dure 30 secondes. +spell.ebwizardry:lightning_arrow.desc=Tire une flèche de foudre dans la direction que vous visez. +spell.ebwizardry:lightning_bolt.desc=Fait frapper la foudre là où vous visez. +spell.ebwizardry:lightning_disc.desc=Envoie un disque de foudre dans la direction que vous pointez, qui cherche des cibles. +spell.ebwizardry:lightning_hammer.desc="Je te frappe par la colère des cieux!" +spell.ebwizardry:lightning_pulse.desc=Charge le sol autour du lanceur avec la foudre, endommageant et repoussant les créatures proches. +spell.ebwizardry:lightning_ray.desc=Crée un flot de foudre dans la direction que vous pointez qui endommage continuellement les cibles. +spell.ebwizardry:lightning_sigil.desc=Place un piège de foudre magique sur le sol qui endommage la créature qui le déclenche et diffuse la foudre en chaine à d'autres créatures proches. +spell.ebwizardry:lightning_web.desc="Concentre-toi. Canalise la tempête dans ton esprit à travers ta baguette et déchaîne sa fureur." +spell.ebwizardry:magic_missile.desc=Tire un éclair d'énergie magique dans la direction que vous pointez. +spell.ebwizardry:metamorphosis.desc=Change la cible en une autre variante. Ne fonctionne que sur certaines créatures. +spell.ebwizardry:meteor.desc=Certains sorciers veulent juste voir le monde brûler ... +spell.ebwizardry:mind_control.desc=Prend le contrôle de l'esprit de la cible pendant 30 secondes, la faisant changer de côté et se battre pour le lanceur à sa place. Ne fonctionnera pas sur des créatures à la volonté trop forte. +spell.ebwizardry:mind_trick.desc=Confond et désoriente la cible pendant 15 secondes, la rendant incapable d’attaquer efficacement. L'effet sera dissipé si la cible subit des dégâts. +spell.ebwizardry:none.desc=Pour obtenir un livre de sorts avec la commande / give, utilisez les métadonnées: / give [joueur] ebwizardry: spell_book 1 [nom de sort] (si vous avez trouvé ce livre dans un coffre, un autre mod a tout gâché). +spell.ebwizardry:oakflesh.desc=Améliore la résistance aux dégâts du lanceur pendant 30 secondes. +spell.ebwizardry:petrify.desc=Transforme la cible en pierre jusqu'à ce qu'elle soit éclatée, avec une chance pour qu'elle éclate quand il fait noir. La cible ne peut ni bouger ni faire quoi que ce soit tant qu'elle est pétrifiée, mais est également insensible à tous les dégâts. +spell.ebwizardry:phase_step.desc=Téléporte le lanceur à travers un mur épais d'un bloc devant eux. Les améliorations de portée augmenteront l'épaisseur à travers laquelle vous pourrez vous téléporter. +spell.ebwizardry:plague_of_darkness.desc=Les ténèbres les dévoreront tous ... +spell.ebwizardry:pocket_furnace.desc=Fait cuire jusqu'à 5 objets dans l'inventaire du lanceur. Les objets sur la barre de raccourci seront cuit en premier. +spell.ebwizardry:pocket_workbench.desc=Permet au lanceur de fabriquer des objets comme s'il était à une table d'artisanat. +spell.ebwizardry:poison.desc=Tire du poison dans la direction que vous pointez. +spell.ebwizardry:poison_bomb.desc=Lance une bombe empoisonnée dans la direction que vous visez, qui explose à l’impact et empoisonne les créatures proches. +spell.ebwizardry:replenish_hunger.desc=Remonte le niveau de nourriture du lanceur de 6 points de stamina. +spell.ebwizardry:ring_of_fire.desc=Crée un anneau de feu autour du lanceur, infligeant des dégâts à tous les ennemis proches et les incendiant. +spell.ebwizardry:shadow_ward.desc=Crée un mur de ténèbres devant le lanceur de sorts, qui inflige la moitié des dégâts à l'attaquant. +spell.ebwizardry:shield.desc=Crée une barrière protectrice de force qui bloque les projectiles et la magie. Confère également au lanceur un faible effet de résistance. +spell.ebwizardry:shockwave.desc=Boom. +spell.ebwizardry:silverfish_swarm.desc="Ahhhh! Ils se MULTIPLIENT!" +spell.ebwizardry:sixth_sense.desc=Permet au lanceur de détecter les emplacements des créatures proches, même à travers les murs, pendant 20 secondes. +spell.ebwizardry:slime.desc=Embourbe la cible dans la boue qui le ralentit et l’endommage continuellement. La boue éclate après 10 secondes. +spell.ebwizardry:smoke_bomb.desc=Lance une bombe de fumée dans la direction que vous pointez qui explose sous l’impact, libérant de la fumée et aveuglant les créatures à proximité pendant un court instant. +spell.ebwizardry:snare.desc=Met au sol un piège qui endommage et ralentit brièvement la créature qui le déclenche. +spell.ebwizardry:snowball.desc=Lance une boule de neige dans la direction que vous visez. +spell.ebwizardry:spark_bomb.desc=Lance une charge de choc dans la direction que vous pointez, ce qui libère des étincelles chez les ennemis proches lors de l’impact. +spell.ebwizardry:spectral_pathway.desc=Crée devant vous un pont magique indestructible qui s'étend sur 15 blocs. Le pont disparaît après 60 secondes. +spell.ebwizardry:spider_swarm.desc=Invoque un essaim d'araignées venimeuses qui se battent pour vous. Les araignées disparaîtront au bout de 30 secondes ou si elles sont tuées. +spell.ebwizardry:static_aura.desc=Entoure le lanceur avec un éclair pendant 30 secondes, projetant une étincelle sur tout ce qui le frappe. +spell.ebwizardry:summon_blaze.desc=Invoque un blaze pour se battre à vos côtés. Le blaze disparaîtra après 30 secondes ou s'il est tué. +spell.ebwizardry:summon_ice_giant.desc="Ecrasez les !" +spell.ebwizardry:summon_ice_wraith.desc=Invoque un spectre de glace qui se bat pour vous. Le spectre de glace disparaîtra après 30 secondes ou s'il est tué. +spell.ebwizardry:summon_iron_golem.desc=Automate autonome automatiquement automatisé. +spell.ebwizardry:summon_lightning_wraith.desc=Invoque un spectre de foudre pour qu'il se batte pour vous. Le spectre de foudre disparaîtra au bout de 30 secondes ou s'il est tué. +spell.ebwizardry:summon_phoenix.desc=De la cendre ... +spell.ebwizardry:summon_shadow_wraith.desc=Invoque un spectre de l'ombre qui se bat pour vous. +spell.ebwizardry:summon_skeleton.desc=Invoque un squelette pour qu'il se batte pour vous. Le squelette disparaîtra après 30 secondes ou s'il est tué. +spell.ebwizardry:summon_skeleton_legion.desc="Lèvez-vous, armée de morts-vivants!" +spell.ebwizardry:summon_snow_golem.desc=Crée un golem de neige qui se bat pour vous. Dure jusqu'à la mort du golem des neiges. +spell.ebwizardry:summon_spirit_horse.desc=Invoque un cheval spirituel à monter. Le cheval spirituel disparaîtra peu de temps après en être descendu, ou vous pouvez le renvoyer en faisant un shift-clic droit dessus avec n'importe quelle baguette. +spell.ebwizardry:summon_spirit_wolf.desc=Invoque un loup spirituel qui se bat pour vous. L'esprit loup ne disparaîtra que s'il est tué, ou vous pouvez le renvoyer en faisant un shift-clic droit dessus avec n'importe quelle baguette. +spell.ebwizardry:summon_storm_elemental.desc="Elementaire de foudre: Une ancienne manifestation des éléments, il peut difficilement contenir la puissance brute qu'il contient." - Le guide du sorcier sur les êtres arcaniques, volume I_i +spell.ebwizardry:summon_wither_skeleton.desc=Invoque un squelette wither qui se bat pour vous. Le squelette flétri disparaîtra après 30 secondes ou s'il est tué. +spell.ebwizardry:summon_zombie.desc=Invoque un zombie pour qu'il se batte pour vous. Le zombie disparaîtra au bout de 30 secondes ou s'il est tué. +spell.ebwizardry:telekinesis.desc=Déplace un objet ou un autre petit objet vers vous, ou cliquez avec le bouton droit sur le bloc que vous regardez. Peut également être utilisé pour désarmer les joueurs. +spell.ebwizardry:thunderbolt.desc=Tire un coup de tonnerre qui repousse les cibles. +spell.ebwizardry:thunderstorm.desc="Mwahahahahahaha!" +spell.ebwizardry:tornado.desc=Libère une tornade dans la direction que vous pointez qui projette tout ce qui se trouve sur son chemin vers le ciel. +spell.ebwizardry:transience.desc=Rend la lanceur éthéré pendant 20 secondes. Le lanceur est à l'abri de tous les dégâts en forme éthérée mais ne peut pas casser, placer de blocs ou causer des dégâts. +spell.ebwizardry:transportation.desc=Transporte le lanceur vers son cercle de pierres mémorisé. Pour utiliser ce sort, faites un cercle de pierres de transport, puis faites un clic droit dessus avec une baguette. +spell.ebwizardry:vanishing_box.desc=Donne au lanceur accès à son coffre de l'end. +spell.ebwizardry:wall_of_frost.desc=L'hiver au bout des doigts. +spell.ebwizardry:water_breathing.desc=Permet au lanceur de respirer sous l'eau pendant 60 secondes. +spell.ebwizardry:whirlwind.desc=Propulse la cible. +spell.ebwizardry:wither.desc=Tire un rayon d'obscurité qui inflige l'effet wither à tout ce qu'il touche. +spell.ebwizardry:wither_skull.desc=Lance un crâne de wither dans la direction que vous pointez. + +spell.ebwizardry:invoke_weather.sun=La pluie a cessé... +spell.ebwizardry:invoke_weather.rain=Le ciel se couvre... +spell.ebwizardry:transportation.missing=Vos pierres de téléportation sont obstruées ou inaccessible +spell.ebwizardry:transportation.undefined=Vous devez vous lier à un cercle de pierre de téléportation avant! +spell.ebwizardry:transportation.wrongdimension=Votre cercle de téléportation est dans une autre dimension... +spell.ebwizardry:clairvoyance.searching=Recherche... +spell.ebwizardry:clairvoyance.confirm=Une marque a été laissé. Utilisez le sort %1$s pour vous montrer le chemin pour y revenir plus tard. +spell.ebwizardry:clairvoyance.outofrange=La marque est trop loin ou est inaccessible... +spell.ebwizardry:clairvoyance.undefined=Vous devez dabord deposer une marque avec sneak-clic droit! +spell.ebwizardry:clairvoyance.wrongdimension=Votre marque est dans une dimension... + +potion.ebwizardry:frost=Morsure du froid +potion.ebwizardry:fireskin=Aura de feu +potion.ebwizardry:ice_shroud=Aura de glace +potion.ebwizardry:static_aura=Aura electrique +potion.ebwizardry:transience=Forme etheree +potion.ebwizardry:decay=Decomposition +potion.ebwizardry:sixth_sense=Sixième sense +potion.ebwizardry:arcane_jammer=Pertubation arcanique +potion.ebwizardry:mind_trick=Confusion +potion.ebwizardry:mind_control=Hypnose +potion.ebwizardry:font_of_mana=Fontaine de mana +potion.ebwizardry:fear=Peur + +enchantment.ebwizardry:magic_sword=Imprégné +enchantment.ebwizardry:magic_bow=Imprégné +enchantment.ebwizardry:flaming_weapon=Imprégné de feu +enchantment.ebwizardry:freezing_weapon=Imprégné de gel + +key.categories.ebwizardry=Wizardry + +key.ebwizardry.next_spell=Prochain sort +key.ebwizardry.previous_spell=Sort précédent + +death.attack.wizardry_magic=%1$s a été tué par %2$s avec de la magie +death.attack.indirect_wizardry_magic=%1$s a été tué par %2$s avec de la magie + +commands.ebwizardry:cast.usage=/%1$s [joueur] [multiplicateur dommage] [multiplicateur distance] [multiplicateur durée] [multiplicateur explosion] +commands.ebwizardry:cast.success=Sort %1$s lancé avec succès +commands.ebwizardry:cast.success_continuous=Sort %1$s lancé; recommencer la commande pour arreter +commands.ebwizardry:cast.success_remote=Sort %1$s lancé en tant que %2$s +commands.ebwizardry:cast.success_remote_continuous=Sort %1$s lancé en tant que %2$s; recommencer la commande pour arreter +commands.ebwizardry:cast.fail=Impossible de lancer %1$s +commands.ebwizardry:cast.not_found=Il n'y a pas de sort avec le nom %1$s +commands.ebwizardry:cast.tag_error=L'analyse des balises de données a échoué: %s + +commands.ebwizardry:ally.usage=/%1$s [joueur] +commands.ebwizardry:ally.addally=%1$s a été ajouté à la liste d'alliés de %2$s +commands.ebwizardry:ally.removeally=%1$s a été retiré de la liste d'alliés de %2$s +commands.ebwizardry:ally.self=Les joueurs ne peuvent pas être allié à eux même! +commands.ebwizardry:ally.permission=Vous n'avez pas la permission de changer les alliés des autres joueurs + +commands.ebwizardry:allies.usage=/%1$s [joueur] +commands.ebwizardry:allies.list=Vos alliés %1$s +commands.ebwizardry:allies.list_other=Joueurs alliés de %1$s: %2$s +commands.ebwizardry:allies.permission=Vous n'avez pas la permission de voir les alliés des autres +commands.ebwizardry:allies.none=Aucun + +commands.ebwizardry:discoverspell.usage=/%1$s [joueur] +commands.ebwizardry:discoverspell.not_found=Il n'y a pas de sort avec le nom: %1$s +commands.ebwizardry:discoverspell.clear=%1$s a oublié tout ses sortilèges +commands.ebwizardry:discoverspell.all=%1$s a appris tout les sortilèges +commands.ebwizardry:discoverspell.addspell=Ajout de %1$s à la mémoire de %2$s +commands.ebwizardry:discoverspell.removespell=Retrait de %1$s à la mémoire %2$s + +config.ebwizardry.title.general=Mod Options + +config.ebwizardry.category.gameplay=Paramètre de gameplay +config.ebwizardry.category.gameplay.tooltip=Configuration général de wizardry +config.ebwizardry.title.gameplay=Paramètre de gameplay +config.ebwizardry.subtitle.gameplay=Paramètres globaux qui affecte les mécaniques de jeu + +config.ebwizardry.category.worldgen=Paramètre de génération de monde +config.ebwizardry.category.worldgen.tooltip=Configuration des paramètre de génération de wizardry +config.ebwizardry.title.worldgen=Paramètre de génération de monde +config.ebwizardry.subtitle.worldgen=Paramètres qui affecte la génération du monde + +config.ebwizardry.category.commands=Paramètre de commande +config.ebwizardry.category.commands.tooltip=Configuration des commandes de wizardry +config.ebwizardry.title.commands=Paramètre de commande +config.ebwizardry.subtitle.commands=Paramètres pour les commandes ajoutés par wizardry + +config.ebwizardry.category.client=Paramètre personnel +config.ebwizardry.category.client.tooltip=Configuration coté client +config.ebwizardry.title.client=Paramètre personnel +config.ebwizardry.subtitle.client=Paramètres personnel qui n'affecte que votre jeu et non le serveur + +config.ebwizardry.category.spells=Configuration des sortilèges +config.ebwizardry.category.spells.tooltip=Selection du sort activé +config.ebwizardry.title.spells=Configuration des sortilèges +config.ebwizardry.subtitle.spells=Mettez un sort sur 'false' pour le desactiver + +config.ebwizardry.category.resistances=Configuration de la resistance +config.ebwizardry.category.resistances.tooltip=Configuration de quel mob est resistant a quel type de magie +config.ebwizardry.title.resistances=Configuration de la resistance +config.ebwizardry.subtitle.resistances=Paramètres permettant à certain monstres d'être résistant à tel sort + +config.ebwizardry.tower_rarity=Rareté des tours de sorcier +config.ebwizardry.ore_dimensions=Rareté des minerais +config.ebwizardry.flower_dimensions=Rareté des fleurs de cristal +config.ebwizardry.tower_dimensions=Rareté des tours +config.ebwizardry.spell_book_drop_chance=Chance de loot des livres de sorts +config.ebwizardry.generate_loot=Generation de loot +config.ebwizardry.firebomb_is_craftable=Bombe de feu fabricable +config.ebwizardry.poison_bomb_is_craftable=Bombe de poison fabricable +config.ebwizardry.smoke_bomb_is_craftable=Bombe de fumée fabricable +config.ebwizardry.use_alternate_scroll_recipe=Utilisation alternative de la recette du parchemin +config.ebwizardry.teleport_through_unbreakable_blocks=Teleportation au travers des blocs indestructible +config.ebwizardry.show_summoned_creature_names=Montrer les noms des invocations +config.ebwizardry.friendly_fire=Friendly Fire +config.ebwizardry.telekinetic_disarmament=Desarmement avec le sort de telekinesie +config.ebwizardry.discovery_mode=Mode decouverte +config.ebwizardry.enable_shift_scrolling=Permettre le Shift-scrolling +config.ebwizardry.minion_revenge_targeting=Les sbires peuvent se venger +config.ebwizardry.player_damage_scaling=Degats en fonction du joueur +config.ebwizardry.npc_damage_scaling=Degats en fonction du npc +config.ebwizardry.cast_command_multiplier_limit=Limite de multiplieur de la commande de cast +config.ebwizardry.summoned_creature_targets_whitelist=Whitelist des creatures ciblé par les invocations +config.ebwizardry.summoned_creature_targets_blacklist=Blacklist des creatures ciblé par les invocations +config.ebwizardry.spell_hud_position=Sortilège HUD Position +config.ebwizardry.cast_command_name=Nom de la commande de cast +config.ebwizardry.discoverspell_command_name=Nom de la commande de decouverte de sort +config.ebwizardry.ally_command_name=Nom de la commande pour s'ajouter des alliés +config.ebwizardry.allies_command_name=Nom de la commande pour voir les alliés +config.ebwizardry.mind_control_targets_blacklist=Blacklist des entités pouvant être controlé +config.ebwizardry.evil_wizard_dimensions=Dimension des sorcier maléfique + +config.ebwizardry.mobs_immune_to_fire=Monstre immunisé au feu +config.ebwizardry.mobs_immune_to_ice=Monstre immunisé à la glace +config.ebwizardry.mobs_immune_to_lightning=Monstre immunisé à la foudre +config.ebwizardry.mobs_immune_to_wither=Monstre immunisé au wither +config.ebwizardry.mobs_immune_to_poison=Monstre immunisé au poison + +config.ebwizardry.tower_rarity.tooltip=Rareté des tour de sorcier. Plus le chiffre est élevé, plus les tours sont rare. mettez la valeur sur 0 pour desactiver les tours completement. +config.ebwizardry.ore_dimensions.tooltip=La liste des dimensions où les minerais de cristaux peuvent apparaitre. Note: Enlever l'overworld (id:0) rendra le mod tres difficile! +config.ebwizardry.flower_dimensions.tooltip=La liste des dimensions où les fleurs de cristal peuvent apparaitre. +config.ebwizardry.tower_dimensions.tooltip=La liste des dimensions où les tours de sorcier peuvent apparaitre. +config.ebwizardry.spell_book_drop_chance.tooltip=La chance que les monstres drop un livre de sort. Plus le chiffre est élevé, plus vous avez de chance d'en loot. Valeur sur 0 = Aucun loot, valeur sur 200 = loot assuré +config.ebwizardry.generate_loot.tooltip=Generation des loot de wizardry dans les coffre de donjon ou non +config.ebwizardry.firebomb_is_craftable.tooltip=Frabrication des bombes de feu ou non +config.ebwizardry.poison_bomb_is_craftable.tooltip=Frabrication des bombes de poison ou non +config.ebwizardry.smoke_bomb_is_craftable.tooltip=Frabrication des bombes de fumée ou non +config.ebwizardry.use_alternate_scroll_recipe.tooltip=Ajouter ou non un cristal magic a la recette des parchemins. Mettez la valeur sur true si il y a un conflit. +config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=Teleportation possible ou non au traver des blocs indestructible(exemple bedrock) en utilisant le sort de passe muraille. (phase) +config.ebwizardry.show_summoned_creature_names.tooltip=Montrer ou non le nom des créatures invoqué ainsi que ceux de leur invocateur au dessus de celle-ci +config.ebwizardry.friendly_fire.tooltip=Autorise ou non les joueurs à blesser leurs alliés avec de la magie. +config.ebwizardry.telekinetic_disarmament.tooltip=Autorise ou non un joueur à desarmer un autre joueur avec le sort de telekinesie (false pour empecher les vols) +config.ebwizardry.discovery_mode.tooltip=Pour ceux qui aime un peu de mystères! Mettez la valeur sur true pour cacher le nom des sorts jusqu'a leur utilisation. Si la valeur est sur false, les parchemins d'identification ne pourrons plus être obtenable en survie. +config.ebwizardry.enable_shift_scrolling.tooltip=Configuration client, n'affecte pas les autres joueurs. Permet de switcher facilement entre les sorts en maintenant sneak et en scrollant la roulette de la souris. +config.ebwizardry.minion_revenge_targeting.tooltip=Vengeance ou non des invocations sur les invocateur si ceux ci les ont attaqué +config.ebwizardry.player_damage_scaling.tooltip=Facteur d’échelle de dommage global pour les dégâts infligés par les joueurs qui lancent des sorts, par rapport à 1. +config.ebwizardry.npc_damage_scaling.tooltip=Facteur d'échelle de dégâts global pour les dégâts infligés par les PNJ qui lancent des sorts, par rapport à 1. +config.ebwizardry.cast_command_multiplier_limit.tooltip=Limite supérieure pour les multiplicateurs passés dans la commande / cast. Ceci existe pour empêcher les joueurs de casser accidentellement un monde / serveur. Les multiplicateurs de grosses explosions peuvent causer un lag extrême - vous avez été prévenu! +config.ebwizardry.summoned_creature_targets_whitelist.tooltip=Liste des noms des entités que les créatures invoquées et les sorciers sont autorisés à attaquer, en plus des valeurs par défaut. Ajoutez des créatures de mod à cette liste si vous voulez que les créatures invoquées les attaquent et qu'elles ne le font pas déjà. Les noms d'entité ne sont pas sensibles à la case. Pour les entités de mod, préfixez l’ID du mod (par exemple, ebwizardry:wizard). +config.ebwizardry.summoned_creature_targets_blacklist.tooltip=Liste des noms des entités que les créatures invoquées et les sorciers ont l'interdiction d'attaquer, outrepassant ainsi les valeurs par défaut et la liste blanche. Ajouter des créatures à cette liste si les laisser se faire attaquer provoque des problèmes ou est trop destructif (le retrait des creeper de cette liste se fait à vos risques et périls!). Les noms d'entité ne sont pas sensibles à la case. Pour les entités de mod, préfixez l’ID du mod (par exemple, ebwizardry:wizard). +config.ebwizardry.spell_hud_position.tooltip=La position du HUD des sorts. +config.ebwizardry.cast_command_name.tooltip=Le nom de la commande /cast. C'est ce que vous tapez directement après le /; Par exemple, si cela était réglé sur 'magic', au lieu de taper /cast, vous taperiez plutôt /magic. +config.ebwizardry.discoverspell_command_name.tooltip=Le nom de la commande /discoverspell. C'est ce que vous tapez directement après le /; Par exemple, si cela était réglé sur 'magic', au lieu de taper /discoverspell, vous taperiez plutôt /magic. +config.ebwizardry.ally_command_name.tooltip=Le nom de la commande /ally. C'est ce que vous tapez directement après le /; Par exemple, si cette option est définie sur 'magic', au lieu de taper /allié, vous devez taper /magic à la place. +config.ebwizardry.allies_command_name.tooltip=Le nom de la commande /allies. C'est ce que vous tapez directement après le /; Par exemple, si cela était réglé sur 'magic', au lieu de taper /allies, vous taperiez plutôt /magic. +config.ebwizardry.mind_control_targets_blacklist.tooltip=Liste des noms d'entités qui ne peuvent pas être contrôlées par l'esprit, en plus des valeurs par défaut. Ajouter des créatures à cette liste si leur permettre d'être contrôlées par l'esprit crée des problèmes ou peut être exploité. Les noms d'entité ne sont pas sensibles à la case. Pour les entités de mod, préfixez l’ID du mod (par exemple, ebwizardry:wizard). +config.ebwizardry.evil_wizard_dimensions.tooltip=Liste des dimensions où les sorciers maléfiques peuvent apparaitre + +config.ebwizardry.mobs_immune_to_fire.tooltip=Liste des noms des entités immunisées au feu, en plus des valeurs par défaut. Ajoutez des créatures de mod à cette liste si vous voulez qu'elles soient immunisées à la magie de feu et qu'elles ne le sont pas déjà. Les noms d'entité ne sont pas sensibles à la case. Pour les entités de mod, préfixez l’ID du mod (par exemple, ebwizardry:wizard). +config.ebwizardry.mobs_immune_to_ice.tooltip=Liste des noms des entités immunisées contre la glace, en plus des valeurs par défaut. Ajoutez des créatures de mod à cette liste si vous voulez qu'elles soient immunisées contre la magie de glace et qu'elles ne le sont pas déjà. Les noms d'entité ne sont pas sensibles à la case. Pour les entités de mod, préfixez l’ID du mod (par exemple, ebwizardry:wizard). +config.ebwizardry.mobs_immune_to_lightning.tooltip=Liste des noms des entités immunisées contre la foudre, en plus des valeurs par défaut. Ajoutez des créatures de mod à cette liste si vous voulez qu'elles soient immunisées contre la magie de foudre et qu'elles ne le sont pas déjà. Les noms d'entité ne sont pas sensibles à la case. Pour les entités de mod, préfixez l’ID du mod (par exemple, ebwizardry:wizard).. +config.ebwizardry.mobs_immune_to_wither.tooltip=Liste des noms des entités immunisées contre l'effet wither, en plus des valeurs par défaut. Ajoutez des créatures de mod à cette liste si vous voulez qu'elles soient immunisées contre la magie de wither et qu'elles ne le sont pas déjà. Les noms d'entité ne sont pas sensibles à la case. Pour les entités de mod, préfixez l’ID du mod (par exemple, ebwizardry:wizard). +config.ebwizardry.mobs_immune_to_poison.tooltip=Liste des noms des entités immunisées contre le poison, en plus des valeurs par défaut. Ajoutez des créatures de mod à cette liste si vous voulez qu'elles soient immunisées contre la magie de poison et qu'elles ne le sont pas déjà. Les noms d'entité ne sont pas sensibles à la case. Pour les entités de mod, préfixez l’ID du mod (par exemple, ebwizardry:wizard). + +wizard.debug=%1$s, %2$s, %3$s diff --git a/src/main/resources/assets/ebwizardry/lang/ko_kr.lang b/src/main/resources/assets/ebwizardry/lang/ko_kr.lang new file mode 100644 index 00000000..468dd01f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/lang/ko_kr.lang @@ -0,0 +1,760 @@ +tile.ebwizardry:arcane_workbench.name=아케인 작업대 +tile.ebwizardry:crystal_ore.name=수정 광석 +tile.ebwizardry:petrified_stone.name=석화된 돌 +tile.ebwizardry:ice_statue.name=얼음 기둥 +tile.ebwizardry:crystal_flower.name=수정 꽃 +tile.ebwizardry:snare.name=덫 +tile.ebwizardry:transportation_stone.name=전이의 돌 +tile.ebwizardry:spectral_block.name=허상 블록 +tile.ebwizardry:crystal_block.name=수정 블록 + +item.ebwizardry:magic_crystal.name=마법 수정 +item.ebwizardry:magic_wand.name=시작의 지팡이 +item.ebwizardry:apprentice_wand.name=마법 지팡이 +item.ebwizardry:advanced_wand.name=고급 지팡이 +item.ebwizardry:master_wand.name=대가의 지팡이 +item.ebwizardry:spell_book.name=주문서 + +item.ebwizardry:arcane_tome.name=마도서 +item.ebwizardry:arcane_tome.desc1=아무 %1$s 지팡이를 +item.ebwizardry:arcane_tome.desc2=%1$s급으로 강화합니다 + +item.ebwizardry:wizard_handbook.name=마법사의 안내서 +item.ebwizardry:wizard_handbook.desc=by %1$s + +item.ebwizardry:wand.buff=+%1$s %2$s 강화 +item.ebwizardry:wand.spell=대기중인 주문: %1$s +item.ebwizardry:wand.mana=마나: %1$s/%2$s + +item.ebwizardry:wand.addally=%1$s has been added to your list of allies +item.ebwizardry:wand.removeally=%1$s has been removed from your list of allies + +item.ebwizardry:basic_fire_wand.name=따뜻한 지팡이 +item.ebwizardry:basic_ice_wand.name=차가운 지팡이 +item.ebwizardry:basic_lightning_wand.name=먹구름 지팡이 +item.ebwizardry:basic_necromancy_wand.name=음산한 지팡이 +item.ebwizardry:basic_earth_wand.name=단단한 지팡이 +item.ebwizardry:basic_sorcery_wand.name=신기한 지팡이 +item.ebwizardry:basic_healing_wand.name=온화한 지팡이 + +item.ebwizardry:apprentice_fire_wand.name=불꽃 지팡이 +item.ebwizardry:apprentice_ice_wand.name=서리 지팡이 +item.ebwizardry:apprentice_lightning_wand.name=번개 지팡이 +item.ebwizardry:apprentice_necromancy_wand.name=그림자 지팡이 +item.ebwizardry:apprentice_earth_wand.name=숲의 지팡이 +item.ebwizardry:apprentice_sorcery_wand.name=힘의 지팡이 +item.ebwizardry:apprentice_healing_wand.name=기력의 지팡이 + +item.ebwizardry:advanced_fire_wand.name=화염 지팡이 +item.ebwizardry:advanced_ice_wand.name=얼음 지팡이 +item.ebwizardry:advanced_lightning_wand.name=벼락 지팡이 +item.ebwizardry:advanced_necromancy_wand.name=암흑 지팡이 +item.ebwizardry:advanced_earth_wand.name=대지 지팡이 +item.ebwizardry:advanced_sorcery_wand.name=환영 지팡이 +item.ebwizardry:advanced_healing_wand.name=치유 지팡이 + +item.ebwizardry:master_fire_wand.name=겁화의 지팡이 +item.ebwizardry:master_ice_wand.name=빙결의 지팡이 +item.ebwizardry:master_lightning_wand.name=폭풍의 지팡이 +item.ebwizardry:master_necromancy_wand.name=심연의 지팡이 +item.ebwizardry:master_earth_wand.name=자연의 지팡이 +item.ebwizardry:master_sorcery_wand.name=미지의 지팡이 +item.ebwizardry:master_healing_wand.name=성자의 지팡이 + +item.ebwizardry:spectral_sword.name=허상의 검 +item.ebwizardry:spectral_pickaxe.name=허상의 곡괭이 +item.ebwizardry:spectral_bow.name=허상의 활 + +item.ebwizardry:mana_flask.name=마나 플라스크 +item.ebwizardry:storage_upgrade.name=마나 수용량 증가 +item.ebwizardry:siphon_upgrade.name=Wand Siphon Upgrade +item.ebwizardry:condenser_upgrade.name=마력 수복 +item.ebwizardry:range_upgrade.name=주문 사거리 증가 +item.ebwizardry:duration_upgrade.name=지속시간 증가 +item.ebwizardry:cooldown_upgrade.name=Wand Cooldown Upgrade +item.ebwizardry:blast_upgrade.name=Wand Blast Upgrade +item.ebwizardry:attunement_upgrade.name=주문 허용량 증가 + +item.ebwizardry:flaming_axe.name=불타오르는 도끼 +item.ebwizardry:frost_axe.name=얼어붙은 도끼 + +item.ebwizardry:firebomb.name=화염탄 +item.ebwizardry:poison_bomb.name=독 폭탄 +item.ebwizardry:smoke_bomb.name=연막탄 + +item.ebwizardry:blank_scroll.name=빈 두루마리 +item.ebwizardry:scroll.name=%1$s의 두루마리 +item.ebwizardry:scroll.undiscovered.name=Scroll "%1$s" +item.ebwizardry:identification_scroll.name=지식의 두루마리 +item.ebwizardry:identification_scroll.desc1=%1$s주문서나 두루마리를 +item.ebwizardry:identification_scroll.desc2=%1$s확인할 수 있습니다 +item.ebwizardry:identification_scroll.nothing_to_identify=알아볼 주문이 없습니다! + +item.ebwizardry:armour_upgrade.name=보호의 문양 +item.ebwizardry:armour_upgrade.desc1=%1$s아무 마법사의 보호구를 +item.ebwizardry:armour_upgrade.desc2=%1$s전설급으로 강화합니다 + +item.ebwizardry:magic_silk.name=마법 천 + +item.ebwizardry:wizard_armour.legendary=전설급 +item.ebwizardry:wizard_armour.buff=-%1$s %2$s 비용 +item.ebwizardry:wizard_armour.mana=마나: %1$s/%2$s + +item.ebwizardry:wizard_hat.name=마법사 모자 +item.ebwizardry:wizard_robe.name=마법사 로브 +item.ebwizardry:wizard_leggings.name=마법사 바지 +item.ebwizardry:wizard_boots.name=마법사 부츠 + +item.ebwizardry:wizard_hat_fire.name=화염술사의 모자 +item.ebwizardry:wizard_robe_fire.name=화염술사의 로브 +item.ebwizardry:wizard_leggings_fire.name=화염술사의 바지 +item.ebwizardry:wizard_boots_fire.name=화염술사의 부츠 + +item.ebwizardry:wizard_hat_ice.name=빙결술사의 모자 +item.ebwizardry:wizard_robe_ice.name=빙결술사의 로브 +item.ebwizardry:wizard_leggings_ice.name=빙결술사의 바지 +item.ebwizardry:wizard_boots_ice.name=빙결술사의 부츠 + +item.ebwizardry:wizard_hat_lightning.name=전격술사의 모자 +item.ebwizardry:wizard_robe_lightning.name=전격술사의 로브 +item.ebwizardry:wizard_leggings_lightning.name=전격술사의 바지 +item.ebwizardry:wizard_boots_lightning.name=전격술사의 부츠 + +item.ebwizardry:wizard_hat_necromancy.name=사령술사의 모자 +item.ebwizardry:wizard_robe_necromancy.name=사령술사의 로브 +item.ebwizardry:wizard_leggings_necromancy.name=사령술사의 바지 +item.ebwizardry:wizard_boots_necromancy.name=사령술사의 부츠 + +item.ebwizardry:wizard_hat_earth.name=자연술사의 모자 +item.ebwizardry:wizard_robe_earth.name=자연술사의 로브 +item.ebwizardry:wizard_leggings_earth.name=자연술사의 바지 +item.ebwizardry:wizard_boots_earth.name=자연술사의 부츠 + +item.ebwizardry:wizard_hat_sorcery.name=신비술사의 모자 +item.ebwizardry:wizard_robe_sorcery.name=신비술사의 로브 +item.ebwizardry:wizard_leggings_sorcery.name=신비술사의 바지 +item.ebwizardry:wizard_boots_sorcery.name=신비술사의 부츠 + +item.ebwizardry:wizard_hat_healing.name=치유사의 모자 +item.ebwizardry:wizard_robe_healing.name=치유사의 로브 +item.ebwizardry:wizard_leggings_healing.name=치유사의 바지 +item.ebwizardry:wizard_boots_healing.name=치유사의 부츠 + +item.ebwizardry:spawn_wizard.name=마법사 소환 +item.ebwizardry:spawn_evil_wizard.name=사악한 마법사 소환 + +item.ebwizardry:spectral_helmet.name=허상의 투구 +item.ebwizardry:spectral_chestplate.name=허상의 흉갑 +item.ebwizardry:spectral_leggings.name=허상의 각반 +item.ebwizardry:spectral_boots.name=허상의 부츠 + +entity.ebwizardry:summonedcreature.nameplate=%1$s의 %2$s +entity.ebwizardry:summonedcreature.nameplate_fallback=누군가의 %1$s + +entity.ebwizardry:zombie_minion.name=좀비 +entity.ebwizardry:skeleton_minion.name=스켈레톤 +entity.ebwizardry:spider_minion.name=독 거미 +entity.ebwizardry:blaze_minion.name=블레이즈 +entity.ebwizardry:wither_skeleton_minion.name=위더 스켈레톤 +entity.ebwizardry:ice_wraith.name=빙령 +entity.ebwizardry:lightning_wraith.name=뇌령 +entity.ebwizardry:shadow_wraith.name=암령 +entity.ebwizardry:spirit_wolf.name=늑대 혼령 +entity.ebwizardry:spirit_horse.name=말 혼령 +entity.ebwizardry:ice_giant.name=얼음 거인 +entity.ebwizardry:phoenix.name=피닉스 +entity.ebwizardry:wizard.name=마법사 +entity.ebwizardry:magic_slime.name=마법 슬라임 +entity.ebwizardry:silverfish_minion.name=좀벌레 +entity.ebwizardry:storm_elemental.name=폭풍 정령 +entity.ebwizardry:evil_wizard.name=사악한 마법사 +entity.ebwizardry:decoy.name=분신 + +entity.ebwizardry:magic_missile.name=마법 +entity.ebwizardry:arc.name=마법 +entity.ebwizardry:spark_bomb.name=마법 +entity.ebwizardry:ice_shard.name=마법 +entity.ebwizardry:firebomb.name=마법 +entity.ebwizardry:poison_bomb.name=마법 +entity.ebwizardry:force_orb.name=마법 +entity.ebwizardry:spark.name=마법 +entity.ebwizardry:darkness_orb.name=마법 +entity.ebwizardry:fire_sigil.name=마법 +entity.ebwizardry:frost_sigil.name=마법 +entity.ebwizardry:lightning_sigil.name=마법 +entity.ebwizardry:lightning_arrow.name=마법 +entity.ebwizardry:firebolt.name=마법 +entity.ebwizardry:ice_charge.name=마법 +entity.ebwizardry:force_arrow.name=마법 +entity.ebwizardry:dart.name=마법 +entity.ebwizardry:lightning_disc.name=마법 +entity.ebwizardry:thunderbolt.name=마법 +entity.ebwizardry:decay.name=마법 +entity.ebwizardry:ice_lance.name=마법 +entity.ebwizardry:smoke_bomb.name=마법 +entity.ebwizardry:ice_spike.name=마법 + +entity.ebwizardry:black_hole.name=블랙홀 +entity.ebwizardry:shield.name=방어막 +entity.ebwizardry:meteor.name=메테오 +entity.ebwizardry:blizzard.name=눈보라 +entity.ebwizardry:bubble.name=물방울 +entity.ebwizardry:tornado.name=회오리바람 +entity.ebwizardry:lightning_hammer.name=벼락 망치 +entity.ebwizardry:arrow_rain.name=화살 세례 +entity.ebwizardry:healing_aura.name=치유 공간 +entity.ebwizardry:forcefield.name=역장 +entity.ebwizardry:ring_of_fire.name=화염의 고리 +entity.ebwizardry:earthquake.name=지진 +entity.ebwizardry:falling_grass.name=떨어지는 풀 +entity.ebwizardry:hailstorm.name=얼음 폭풍 +entity.ebwizardry:lightning_pulse.name=번개 파동 + +itemGroup.ebwizardry=마법의 길 +itemGroup.ebwizardryspells=주문 + +advancement.ebwizardry:root=마법의 길 +advancement.ebwizardry:root.desc=마도를 걷는 여정길 +advancement.ebwizardry:crystal=신기한 수정이군... +advancement.ebwizardry:crystal.desc=마법 수정을 캐세요 +advancement.ebwizardry:arcane_initiate=마법 시작! +advancement.ebwizardry:arcane_initiate.desc=황금 조각, 막대기, 마법 수정 한개로 마법 지팡이를 만드세요 +advancement.ebwizardry:apprentice=마법사의 제자 +advancement.ebwizardry:apprentice.desc=마도서를 사용해 지팡이를 강화하세요 +advancement.ebwizardry:master=마법의 대가 +advancement.ebwizardry:master.desc=대가의 지팡이를 얻으세요 +advancement.ebwizardry:all_spells=현자 +advancement.ebwizardry:all_spells.desc=모든 주문을 시전하세요 +advancement.ebwizardry:wizard_trade=마법 거래 +advancement.ebwizardry:wizard_trade.desc=마법사에게서 아이템 한개를 구입하세요 +advancement.ebwizardry:buy_master_spell=지식은 힘이다 +advancement.ebwizardry:buy_master_spell.desc=마법사에게서 대가의 주문을 구입하세요 +advancement.ebwizardry:freeze_blaze=이젠 안 뜨거워 +advancement.ebwizardry:freeze_blaze.desc=블레이즈를 얼리세요 +advancement.ebwizardry:charge_creeper=바람이 부나? +advancement.ebwizardry:charge_creeper.desc='사고로' 충전된 크리퍼를 만드세요 +advancement.ebwizardry:frankenstein=프랑켄슈타인 +advancement.ebwizardry:frankenstein.desc='벼락' 주문으로 돼지를 좀비 피그맨으로 만드세요 +advancement.ebwizardry:special_upgrade=마개조 +advancement.ebwizardry:special_upgrade.desc=지팡이에 특별한 개조를 하세요 +advancement.ebwizardry:craft_flask=플라스크 속의 마법 +advancement.ebwizardry:craft_flask.desc=마나 플라스크를 만드세요 +advancement.ebwizardry:elemental=속성? +advancement.ebwizardry:elemental.desc=속성 지팡이 한개를 얻으세요 +advancement.ebwizardry:armour_set=이제야 제대로 된 마법사 같네 +advancement.ebwizardry:armour_set.desc=마법사 방어구 세트를 입으세요 +advancement.ebwizardry:legendary=전설! +advancement.ebwizardry:legendary.desc=전설급 마법사 방어구 한개를 얻으세요 +advancement.ebwizardry:self_destruct=마법은 돌아오는 거야 +advancement.ebwizardry:self_destruct.desc=자신의 마법에 죽으세요 +advancement.ebwizardry:pig_tornado=다시는... +advancement.ebwizardry:pig_tornado.desc=돼지를 타고 토네이도로 뛰어드세요 +advancement.ebwizardry:jam_wizard=방해 시간 +advancement.ebwizardry:jam_wizard.desc='마법 방해' 주문을 마법사에게 사용하세요 +advancement.ebwizardry:slime_skeleton=끈적한 상황 +advancement.ebwizardry:slime_skeleton.desc=스켈레톤에게 슬라임을 씌우세요 +advancement.ebwizardry:anger_wizard=후회할걸 +advancement.ebwizardry:anger_wizard.desc=마법사를 화나게 하세요 +advancement.ebwizardry:defeat_evil_wizard=당연한 일이야 +advancement.ebwizardry:defeat_evil_wizard.desc=사악한 마법사를 물리치세요 +advancement.ebwizardry:max_out_wand=강력하군! +advancement.ebwizardry:max_out_wand.desc=대가의 지팡이를 한계까지 개조하세요 +advancement.ebwizardry:element_master=Element Mastery +advancement.ebwizardry:element_master.desc=Cast all the spells of any element +advancement.ebwizardry:identify_spell=마법 감정 +advancement.ebwizardry:identify_spell.desc=지식의 두루마리로 미확인 주문을 확인하세요 + +tile.ebwizardry:transportation_stone.confirm=이제 %1$s을 사용하면 이곳으로 귀환합니다. +tile.ebwizardry:transportation_stone.invalid=먼저 전이의 돌 8개로 귀환진을 만들어야 합니다. + +container.ebwizardry:arcane_workbench=아케인 작업대 +container.ebwizardry:arcane_workbench.apply=완료 +container.ebwizardry:arcane_workbench.mana=마나: +container.ebwizardry:arcane_workbench.upgrades=개조 내역: + +tier.basic=초보자 +tier.apprentice=견습생 +tier.advanced=숙련자 +tier.master=대가 + +element.simple=무 +element.fire=화염 +element.ice=빙결 +element.lightning=전격 +element.necromancy=사령 +element.earth=자연 +element.sorcery=신비 +element.healing=치유 + +element.simple.wizard=마법사 +element.fire.wizard=화염술사 +element.ice.wizard=빙결술사 +element.lightning.wizard=전격술사 +element.necromancy.wizard=사령술사 +element.earth.wizard=자연술사 +element.sorcery.wizard=신비술사 +element.healing.wizard=치유사 + +spelltype.attack=공격 +spelltype.defence=수비 +spelltype.utility=보조 +spelltype.minion=소환 + +spell.disabled=%1$s은 config에 의해 비활성화 되었습니다. +spell.resist=%1$s(이)가 %2$s에 저항했습니다 +spell.discover=%1$s 주문을 알아냈습니다! + +spell.ebwizardry:agility=민첩 강화 +spell.ebwizardry:arc=전격파 +spell.ebwizardry:arcane_jammer=마법 방해 +spell.ebwizardry:arrow_rain=화살 세례 +spell.ebwizardry:banish=강제 전이 +spell.ebwizardry:black_hole=블랙홀 +spell.ebwizardry:blink=점멸 +spell.ebwizardry:blizzard=눈보라 +spell.ebwizardry:bubble=물방울 +spell.ebwizardry:chain_lightning=연쇄 번개 +spell.ebwizardry:clairvoyance=자연의 인도 +spell.ebwizardry:cobwebs=옭아매는 거미줄 +spell.ebwizardry:conjure_armour=허상의 갑옷 +spell.ebwizardry:conjure_bow=허상의 활 +spell.ebwizardry:conjure_pickaxe=허상의 곡괭이 +spell.ebwizardry:conjure_sword=허상의 검 +spell.ebwizardry:cure_effects=회복의 바람 +spell.ebwizardry:curse_of_soulbinding=묶여있는 영혼 +spell.ebwizardry:darkness_orb=암흑의 보주 +spell.ebwizardry:darkvision=암흑 시야 +spell.ebwizardry:dart=다트 +spell.ebwizardry:decay=부패하는 역병 +spell.ebwizardry:decoy=분산 +spell.ebwizardry:detonate=폭렬 +spell.ebwizardry:diamondflesh=불멸의 신체 +spell.ebwizardry:earthquake=지진 +spell.ebwizardry:entrapment=공포의 손아귀 +spell.ebwizardry:fireball=화염구 +spell.ebwizardry:firebolt=화염 탄환 +spell.ebwizardry:firebomb=화염탄 +spell.ebwizardry:fire_resistance=화염 저항 +spell.ebwizardry:fire_sigil=불의 표식 +spell.ebwizardry:fireskin=불타는 피부 +spell.ebwizardry:firestorm=불의 세례 +spell.ebwizardry:flame_ray=불꽃 광선 +spell.ebwizardry:flaming_axe=타오르는도끼 +spell.ebwizardry:flaming_weapon=타오르는무기 +spell.ebwizardry:flight=창공의 가호 +spell.ebwizardry:font_of_mana=마나의 축복 +spell.ebwizardry:font_of_vitality=생명의 축복 +spell.ebwizardry:force_arrow=인력의 화살 +spell.ebwizardry:forcefield=역장 +spell.ebwizardry:force_orb=반발의 보주 +spell.ebwizardry:forests_curse=자연의 저주 +spell.ebwizardry:freeze=서리바람 +spell.ebwizardry:freezing_weapon=얼어붙은 무기 +spell.ebwizardry:frost_axe=얼어붙은 도끼 +spell.ebwizardry:frost_ray=서리 광선 +spell.ebwizardry:frost_sigil=냉기의 표식 +spell.ebwizardry:glide=바람의 호의 +spell.ebwizardry:greater_fireball=불덩이 작렬 +spell.ebwizardry:greater_heal=대 치유 +spell.ebwizardry:group_heal=광역 치유 +spell.ebwizardry:growth_aura=수확의 축복 +spell.ebwizardry:hailstorm=얼음 폭풍 +spell.ebwizardry:heal=치유 +spell.ebwizardry:heal_ally=치유의 손길 +spell.ebwizardry:healing_aura=차오르는 체력 +spell.ebwizardry:homing_spark=전기 추적자 +spell.ebwizardry:ice_age=빙하기 +spell.ebwizardry:ice_charge=얼음 폭탄 +spell.ebwizardry:ice_lance=얼음창 +spell.ebwizardry:ice_shard=얼음 화살 +spell.ebwizardry:ice_shroud=서리 가호 +spell.ebwizardry:ice_spikes=차가운 가시밭 +spell.ebwizardry:ice_statue=결빙 +spell.ebwizardry:ignite=모닥불 +spell.ebwizardry:imbue_weapon=마력 부여 +spell.ebwizardry:intimidate=공포 유발 +spell.ebwizardry:invigorating_presence=강력한 손아귀 +spell.ebwizardry:invisibility=투명화 +spell.ebwizardry:invoke_weather=뇌우 +spell.ebwizardry:ironflesh=강철같은 신체 +spell.ebwizardry:leap=도약 +spell.ebwizardry:levitation=중력 반발 +spell.ebwizardry:life_drain=생명력 흡수 +spell.ebwizardry:light=빛 +spell.ebwizardry:lightning_arrow=번개 화살 +spell.ebwizardry:lightning_bolt=벼락 +spell.ebwizardry:lightning_disc=번개의 고리 +spell.ebwizardry:lightning_hammer=벼락 망치 +spell.ebwizardry:lightning_pulse=번개 파동 +spell.ebwizardry:lightning_ray=번개 광선 +spell.ebwizardry:lightning_sigil=번개의 표식 +spell.ebwizardry:lightning_web=이어지는 번개 +spell.ebwizardry:magic_missile=마법 화살 +spell.ebwizardry:metamorphosis=형태의 변이 +spell.ebwizardry:meteor=메테오 +spell.ebwizardry:mind_control=정신지배 +spell.ebwizardry:mind_trick=정신착란 +spell.ebwizardry:none=[빈 주문] +spell.ebwizardry:oakflesh=나무의 단단함 +spell.ebwizardry:petrify=석화 +spell.ebwizardry:phase_step=벽 안의 길 +spell.ebwizardry:plague_of_darkness=잠식하는 어둠 +spell.ebwizardry:pocket_furnace=마법 화로 +spell.ebwizardry:pocket_workbench=허상 작업대 +spell.ebwizardry:poison=독 +spell.ebwizardry:poison_bomb=독 폭탄 +spell.ebwizardry:replenish_hunger=풍족한 식사 +spell.ebwizardry:ring_of_fire=화염의 고리 +spell.ebwizardry:shadow_ward=마주하는 고통 +spell.ebwizardry:shield=방어막 +spell.ebwizardry:shockwave=충격 파동 +spell.ebwizardry:silverfish_swarm=소환 : 좀벌레 무리 +spell.ebwizardry:sixth_sense=제육감 +spell.ebwizardry:slime=바람의 거부 +spell.ebwizardry:smoke_bomb=연막탄 +spell.ebwizardry:snare=구속의 올가미 +spell.ebwizardry:snowball=눈덩이 +spell.ebwizardry:spark_bomb=전기 폭탄 +spell.ebwizardry:spectral_pathway=허상의 길 +spell.ebwizardry:spider_swarm=늪의 분노 +spell.ebwizardry:static_aura=벼락의 기운 +spell.ebwizardry:summon_blaze=소환 : 블레이즈 +spell.ebwizardry:summon_ice_giant=소환 : 얼음 거인 +spell.ebwizardry:summon_ice_wraith=소환 : 빙령 +spell.ebwizardry:summon_iron_golem=소환 : 철 골렘 +spell.ebwizardry:summon_lightning_wraith=소환 : 뇌령 +spell.ebwizardry:summon_phoenix=소환 : 피닉스 +spell.ebwizardry:summon_shadow_wraith=소환 : 암령 +spell.ebwizardry:summon_skeleton=소환 : 스켈레톤 +spell.ebwizardry:summon_skeleton_legion=소환 : 스켈레톤 군단 +spell.ebwizardry:summon_snow_golem=소환 : 눈 골렘 +spell.ebwizardry:summon_spirit_horse=소환 : 말 혼령 +spell.ebwizardry:summon_spirit_wolf=소환 : 늑대 혼령 +spell.ebwizardry:summon_storm_elemental=소환 : 폭풍 정령 +spell.ebwizardry:summon_wither_skeleton=소환 : 위더 스켈레톤 +spell.ebwizardry:summon_zombie=소환 : 좀비 +spell.ebwizardry:telekinesis=염동력 +spell.ebwizardry:thunderbolt=번개 충격 +spell.ebwizardry:thunderstorm=번개폭풍 +spell.ebwizardry:tornado=회오리바람 +spell.ebwizardry:transience=공허의 보호 +spell.ebwizardry:transportation=귀환 +spell.ebwizardry:vanishing_box=아공간 +spell.ebwizardry:wall_of_frost=서리 장벽 +spell.ebwizardry:water_breathing=수중 호흡 +spell.ebwizardry:whirlwind=땅의 추방 +spell.ebwizardry:wither=쇠약의 물결 +spell.ebwizardry:wither_skull=사악한 폭격 + +spell.ebwizardry:agility.desc=시전자에게 신속과 점프 강화를 30초 부여합니다. +spell.ebwizardry:arc.desc=대상에게 전기충격을 가합니다. +spell.ebwizardry:arcane_jammer.desc=대상의 마법 사용을 15초 막습니다. +spell.ebwizardry:arrow_rain.desc="궁수! 발사!" +spell.ebwizardry:banish.desc=대상을 일정 범위 내에 무작위로 전이시킵니다. +spell.ebwizardry:black_hole.desc="도망쳐 보시지..." +spell.ebwizardry:blink.desc=시전자를 약간 앞으로 전이시킵니다 +spell.ebwizardry:blizzard.desc=휘몰아치는 눈보라를 만들어 범위 내의 대상을 느리게 하고 지속적인 피해를 줍니다. 시전자는 피해는 입지 않지만 느려집니다. +spell.ebwizardry:bubble.desc=닿은 대상을 하늘로 떠올리는 물거품을 발사합니다. 지속시간이 다 되거나 피해를 입으면 사라집니다. +spell.ebwizardry:chain_lightning.desc=발사된 번개가 대상과 근처 적에게 피해를 입힙니다. +spell.ebwizardry:clairvoyance.desc=지정된 위치를 안내하는 빛무리를 보여줍니다. 이 주문을 든 상태에서 지정할 위치의 블록을 쉬프트-우클릭 하세요. 빛무리는 90동안 유지됩니다. +spell.ebwizardry:cobwebs.desc=사용한 위치에 20초간 유지되는 거미줄을 만듭니다. +spell.ebwizardry:conjure_armour.desc=철 갑옷과 같은 방어도를 갖는 허상의 갑옷을 착용합니다. 갑옷은 1분동안 유지되며 빈 장비칸이 필요합니다. +spell.ebwizardry:conjure_bow.desc=30초 동안 유지되는 무한한 허상의 활을 만듭니다. +spell.ebwizardry:conjure_pickaxe.desc=30초 동안 유지되는 철 곡괭이와 동급의 허상의 곡괭이를 만듭니다. +spell.ebwizardry:conjure_sword.desc=30초 동안 유지되는 철 검과 동급의 허상의 검을 만듭니다. +spell.ebwizardry:cure_effects.desc=시전자에게 적용된 모든 상태이상을 제거합니다. +spell.ebwizardry:curse_of_soulbinding.desc=대상과 자신의 영혼을 묶습니다. 모든 피해를 공유하며 누구 하나가 죽을 때까지 지속됩니다. +spell.ebwizardry:darkness_orb.desc=느리게 움직이는 암흑 에너지로 된 구체를 날립니다. 맞은 대상은 시듦 상태에 빠집니다. +spell.ebwizardry:darkvision.desc=야간 투시 45초를 얻습니다. +spell.ebwizardry:dart.desc=피해와 나약함을 입히는 다트를 발사합니다. +spell.ebwizardry:decay.desc=부패된 땅을 만들고 그 위를 지나는 모든 생물체에게 '부패'를 입힙니다. 부패된 생물체가 움직이면 그곳에도 '부패'가 퍼집니다. +spell.ebwizardry:decoy.desc=30초 동안 유지되는 시전자와 똑같이 생긴 분신을 만들어 적을 혼란시킵니다. +spell.ebwizardry:detonate.desc=시전한 지점에 폭발을 일으켜 주변의 모든 크리쳐를 공격합니다. +spell.ebwizardry:diamondflesh.desc="네 공격은 통하지 않는다!" +spell.ebwizardry:earthquake.desc="진정한 자연의 마법사는 산을 옮길수도 있지." +spell.ebwizardry:entrapment.desc=대상을 어둠에 구체에 가둬 지속 피해를 주며 하늘로 띄웁니다. +spell.ebwizardry:fireball.desc=시전한 방향으로 화염구를 발사합니다. +spell.ebwizardry:firebolt.desc=전방으로 짧은 불꽃 탄환을 발사합니다. +spell.ebwizardry:firebomb.desc=시전한 방향으로 화염탄을 던져서 주변 적을 불태웁니다. +spell.ebwizardry:fire_resistance.desc=화염 저항 30초를 얻습니다. +spell.ebwizardry:fire_sigil.desc=약간의 피해와 화상을 입히는 마법 함정을 설치합니다. +spell.ebwizardry:fireskin.desc=30초 동안 시전자를 화염으로 감싸, 공격하는 적에게 화상을 입힙니다. +spell.ebwizardry:firestorm.desc="내가 바로 화염룡이다!" +spell.ebwizardry:flame_ray.desc=불타는 광선을 내뿜어 땅과 적을 불태웁니다. +spell.ebwizardry:flaming_axe.desc=30초 동안 유지되는 적을 불태우는 도끼를 만듭니다. +spell.ebwizardry:flaming_weapon.desc=시전자의 핫바에 존재하는 무기 하나에 45초 동안 지속되는 '불꽃의 마력' 인챈트를 부여합니다. +spell.ebwizardry:flight.desc="날기를 매와 같이." +spell.ebwizardry:font_of_mana.desc="우리를 가득 채운 강력한 에너지는 중앙..." - 잊혀진 마법사의 일지에서 발췌, 나머지 페이지는 불타 사라졌다. +spell.ebwizardry:font_of_vitality.desc="끝내주는 기분이군." +spell.ebwizardry:force_arrow.desc=시전한 방향으로 나아가는 힘의 화살을 발사합니다. +spell.ebwizardry:forcefield.desc=시전자를 중심으로 허가받지 못한 모든 것을 거부하는 공간을 만듭니다. +spell.ebwizardry:force_orb.desc=주변을 밀쳐내며 피해를 주는 힘의 구체를 던집니다. +spell.ebwizardry:forests_curse.desc="이곳이 어디라고 발을 디디느냐!" +spell.ebwizardry:freeze.desc=대상을 10초 동안 얼립니다. 또는 물을 얼리거나 눈을 내릴 수 있습니다. +spell.ebwizardry:freezing_weapon.desc=시전자의 핫바에 존재하는 무기 하나에 45초 동안 지속되는 '서리의 마력' 인챈트를 부여합니다. +spell.ebwizardry:frost_axe.desc=30초 동안 유지되는 적을 얼리는 도끼를 만듭니다. +spell.ebwizardry:frost_ray.desc=대상에게 피해와 동상을 주는 서리 광선을 발사합니다. +spell.ebwizardry:frost_sigil.desc=약간의 피해와 동상을 입히는 마법 함정을 설치합니다. +spell.ebwizardry:glide.desc=낙하중 사용하는 동안 부드럽게 활강합니다. +spell.ebwizardry:greater_fireball.desc=주변을 파괴하고 충격을 주는 거대한 화염구를 발사합니다. +spell.ebwizardry:greater_heal.desc=시전자의 하트 4칸을 회복합니다. +spell.ebwizardry:group_heal.desc=시전자와 주변 생명의 하트 3칸을 회복합니다. +spell.ebwizardry:growth_aura.desc=시전자 주변의 모든 식물이 자라납니다. +spell.ebwizardry:hailstorm.desc="빙결술사들이 진정한 힘을 깨닳은건 3번째 겨울이었습니다." +spell.ebwizardry:heal.desc=시전자의 하트 2칸을 회복합니다. +spell.ebwizardry:heal_ally.desc=대상의 하트 2개 반을 회복시킵니다. +spell.ebwizardry:healing_aura.desc=체력을 서서히 회복하는 신성한 공간을 만듭니다. 범위 내의 언데드는 지속 피해를 입습니다. +spell.ebwizardry:homing_spark.desc=주변 적으로 움직이는 전기 구슬을 발사합니다. +spell.ebwizardry:ice_age.desc="내가, 겨울이다." +spell.ebwizardry:ice_charge.desc=산산조각나 주변에 한기와 얼음 파편을 뿌리는 얼음 폭탄을 던집니다. +spell.ebwizardry:ice_lance.desc=맞은 대상에게 피해와 감속을 입히는 관통하는 얼음의 창을 발사합니다. +spell.ebwizardry:ice_shard.desc=피해와 감속을 입히는 얼음 파편을 날립니다. +spell.ebwizardry:ice_shroud.desc=30초 동안 시전자를 서리로 감싸 공격하는 적을 얼어붙게 합니다. +spell.ebwizardry:ice_spikes.desc=날카로운 얼음 가시들을 땅에서 솟게합니다. +spell.ebwizardry:ice_statue.desc=대상을 20초 동안이나 얼음이 깨질때 까지 얼음 기둥에 가둡니다. 갖힌 대상은 피해를 받지 않습니다. +spell.ebwizardry:ignite.desc=사용 지점에 불을 붙입니다. 라이터와 같습니다. +spell.ebwizardry:imbue_weapon.desc=시전자의 핫바에 존재하는 무기 하나에 45초 동안 마력을 부여합니다. +spell.ebwizardry:intimidate.desc=주변 크리쳐들을 공포를 주어 도망가게 합니다. 대상은 30초 뒤에 회복됩니다. +spell.ebwizardry:invigorating_presence.desc=시전자와 주변 동맹에 힘2를 부여합니다. +spell.ebwizardry:invisibility.desc=투명화 30초를 얻습니다. +spell.ebwizardry:invoke_weather.desc=날씨를 바꿉니다. +spell.ebwizardry:ironflesh.desc=저항3 30초를 얻습니다. +spell.ebwizardry:leap.desc=약간 앞으로 나아가며 높이 도약합니다. +spell.ebwizardry:levitation.desc=주문을 유지하는 동안 시전자를 하늘로 떠오르게 합니다. +spell.ebwizardry:life_drain.desc=쇠약의 기운을 발사해 대상의 체력을 뺏어와 시전자의 체력을 보충합니다. +spell.ebwizardry:light.desc=30초 동안 유지되는 마법적인 조명을 생성합니다. +spell.ebwizardry:lightning_arrow.desc=전방으로 번개의 화살을 발사합니다. +spell.ebwizardry:lightning_bolt.desc=사용 지점에 벼락을 내리꽂습니다. +spell.ebwizardry:lightning_disc.desc=고리모양의 번개를 빠른 속도로 날립니다. +spell.ebwizardry:lightning_hammer.desc="신의 망치를 받아라!" +spell.ebwizardry:lightning_pulse.desc=시전자를 중심으로 번개를 방출하여 주변 적에게 피해를 주고 밀쳐냅니다. +spell.ebwizardry:lightning_ray.desc=적을 감전시켜 피해를 입히는 번개를 지속적으로 방출합니다. +spell.ebwizardry:lightning_sigil.desc=연쇄 번개를 내뿜는 마법 함정을 설치합니다. +spell.ebwizardry:lightning_web.desc="집중해. 네 안의 폭풍을 지팡이 밖으로 내뿜는거야." +spell.ebwizardry:magic_missile.desc=약간의 피해를 입히는 기본적인 마법 화살을 발사합니다. +spell.ebwizardry:metamorphosis.desc=대상을 같은 종류의 다른 형태로 바꿉니다. +spell.ebwizardry:meteor.desc="가끔은 이 세상이 불타는걸 보고싶기도 하지..." +spell.ebwizardry:mind_control.desc=의지가 약한 대상의 정신을 사로잡아 30초 동안 시전자를 위해 싸우게 합니다. +spell.ebwizardry:mind_trick.desc=대상의 정신에 충격을 가해 15초가 지나거나 공격을 받을때 까지 아무것도 하지 못하게 합니다. +spell.ebwizardry:none.desc=주문서를 얻으세요. /give command, use id: /give [player] ebwizardry:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up). +spell.ebwizardry:oakflesh.desc=저항2 30초를 얻습니다. +spell.ebwizardry:petrify.desc=대상을 돌에 가둬 아무것도 할수 없지만 피해 또한 받지 않게 합니다. 캐거나 어두운 곳에 있을때 까지 지속됩니다. +spell.ebwizardry:phase_step.desc=전방의 1칸 두깨의 벽을 통과합니다. 사거리 추가 개조로 강화할 수 있습니다. +spell.ebwizardry:plague_of_darkness.desc="어둠이 모든것을 먹어 치우리라..." +spell.ebwizardry:pocket_furnace.desc=인벤토리의 제련할 수 있는 아이템을 5개씩 제련합니다. 핫바를 우선 합니다. +spell.ebwizardry:pocket_workbench.desc=어디서든 작업대를 열 수 있습니다. +spell.ebwizardry:poison.desc=전방으로 독을 발사합니다. +spell.ebwizardry:poison_bomb.desc=약간의 피해와 주변에 독을 뿌리는 폭탄을 던집니다. +spell.ebwizardry:replenish_hunger.desc=시전자의 배고픔을 6점(3칸) 회복합니다. +spell.ebwizardry:ring_of_fire.desc=시전자 주위로 화염의 고리를 만들어서 들어오는 적을 불태웁니다. +spell.ebwizardry:shadow_ward.desc=시전자 전방에 어둠의 방패를 만들어 적이 가하는 공격의 절반을 돌려줍니다. +spell.ebwizardry:shield.desc=발사체와 마법을 막는 방패를 소환합니다. 유지되는 동안 저항을 얻습니다. +spell.ebwizardry:shockwave.desc="펑." +spell.ebwizardry:silverfish_swarm.desc="으아아! 벌레다!!!" +spell.ebwizardry:sixth_sense.desc=20초 동안 주변의 모든 크리쳐를 어디에 있던 볼 수 있습니다. +spell.ebwizardry:slime.desc=대상에게 10초 동안 슬라임을 씌워 느리게 하고 피해를 입힙니다. +spell.ebwizardry:smoke_bomb.desc=연막을 터트려 짧은 시간 대상을 실명 시킵니다. +spell.ebwizardry:snare.desc=피해와 구속을 거는 덫을 설치합니다. +spell.ebwizardry:snowball.desc=눈덩이를 던집니다. +spell.ebwizardry:spark_bomb.desc=주변 적에게 전기 충격을 가하는 전기 덩어리를 던집니다. +spell.ebwizardry:spectral_pathway.desc=전방에 60초 동안 유지되는 파괴할 수 없는 마법의 다리를 만듭니다. +spell.ebwizardry:spider_swarm.desc=30초 동안 시전자를 위해 싸우는 독 거미 무리를 소환합니다. +spell.ebwizardry:static_aura.desc=시전자를 전기로 감싸 공격하는 적들을 지집니다. +spell.ebwizardry:summon_blaze.desc=30초 동안 시전자를 위해 싸우는 블레이즈를 소환합니다. +spell.ebwizardry:summon_ice_giant.desc="날려버려!" +spell.ebwizardry:summon_ice_wraith.desc=30초 동안 시전자를 위해 싸우는 얼어붙은 귀신을 소환합니다. +spell.ebwizardry:summon_iron_golem.desc="시스템, 정상 가동 중." +spell.ebwizardry:summon_lightning_wraith.desc=30초 동안 시전자를 위해 싸우는 번개의 귀신을 소환합니다. +spell.ebwizardry:summon_phoenix.desc="잿더미에서 다시 타오르리라." +spell.ebwizardry:summon_shadow_wraith.desc="어둠이, 함께한다..." +spell.ebwizardry:summon_skeleton.desc=30초 동안 시전자를 위해 싸우는 스켈레톤을 소환합니다. +spell.ebwizardry:summon_skeleton_legion.desc="어둠의 병사들이여! 명을 받들라!" +spell.ebwizardry:summon_snow_golem.desc=죽을때 까지 남아있는 눈 골렘을 소환합니다. +spell.ebwizardry:summon_spirit_horse.desc=조련된 유령마를 소환합니다. 유령마는 내린 후 잠시 뒤 사라지거나 아무 지팡이로 쉬프트-우클릭을 통해 송환할 수 있습니다. +spell.ebwizardry:summon_spirit_wolf.desc=죽을때 까지 시전자를 위해 싸우는 유령 늑대를 소환합니다. 아무 지팡이로 쉬프트-우클릭을 통해 송환할 수 있습니다. +spell.ebwizardry:summon_storm_elemental.desc="폭풍의 정령 : 원소의 순수한 형태. 그 힘을 억제할 수 없다." - 마법의 길 : 원소의 서 발췌 +spell.ebwizardry:summon_wither_skeleton.desc=30초 동안 시전자를 위해 싸우는 위더 스켈레톤을 소환합니다. +spell.ebwizardry:summon_zombie.desc=30초 동안 시전자를 위해 싸우는 좀비를 소환합니다. +spell.ebwizardry:telekinesis.desc=멀리 있는 아이템을 가져옵니다. +spell.ebwizardry:thunderbolt.desc=적을 밀치는 빠른 전기 구슬을 발사합니다. +spell.ebwizardry:thunderstorm.desc="으하하하하하하하!" +spell.ebwizardry:tornado.desc=앞으로 나아가는 회오리를 내보내, 적을 날려버립니다. +spell.ebwizardry:transience.desc=20초 동안 공허에 숨어 모든 피해를 무시합니다. +spell.ebwizardry:transportation.desc=전이의 진을 만들고 전이의 돌을 우클릭해 위치를 기록합니다. 다시 우클릭을 하면 귀환진으로 귀환합니다. +spell.ebwizardry:vanishing_box.desc=어디서든 엔더 상자를 열 수 있습니다. +spell.ebwizardry:wall_of_frost.desc="겨울이 온다..." +spell.ebwizardry:water_breathing.desc=수중 호흡 60초를 얻습니다. +spell.ebwizardry:whirlwind.desc=대상을 빠르게 당신에게서 밀쳐냅니다. +spell.ebwizardry:wither.desc=암흑의 광선을 쏘아 닿는 크리쳐에게 위더를 부여합니다. +spell.ebwizardry:wither_skull.desc=위더 폭탄을 발사합니다. + +spell.ebwizardry:invoke_weather.sun=뇌우가 물러갑니다. +spell.ebwizardry:invoke_weather.rain=뇌우가 몰려듭니다. +spell.ebwizardry:transportation.missing=귀환진이 사라졌거나 파괴되었습니다. +spell.ebwizardry:transportation.undefined=먼저 귀환진을 만드세요! +spell.ebwizardry:transportation.wrongdimension=귀환진이 다른 세계에 있습니다. +spell.ebwizardry:clairvoyance.searching=탐색중... +spell.ebwizardry:clairvoyance.confirm=이제 %1$s를 사용하면 이곳을 알려줍니다. +spell.ebwizardry:clairvoyance.outofrange=장소가 너무 멀거나 연결된 길이 없습니다. +spell.ebwizardry:clairvoyance.undefined=먼저 위치를 지정하세요! +spell.ebwizardry:clairvoyance.wrongdimension=장소가 다른 세계에 있습니다... + +potion.ebwizardry:frost=동상 +potion.ebwizardry:fireskin=불타는 피부 +potion.ebwizardry:ice_shroud=서리 가호 +potion.ebwizardry:static_aura=벼락의 기운 +potion.ebwizardry:transience=공허의 보호 +potion.ebwizardry:decay=부패하는 역병 +potion.ebwizardry:sixth_sense=제육감 +potion.ebwizardry:arcane_jammer=마법 방해 +potion.ebwizardry:mind_trick=정신착란 +potion.ebwizardry:mind_control=정신지배 +potion.ebwizardry:font_of_mana=마나의 축복 +potion.ebwizardry:fear=공포 + +enchantment.ebwizardry:magic_sword=마력 부여 +enchantment.ebwizardry:magic_bow=마력 부여 +enchantment.ebwizardry:flaming_weapon=불꽃의 마력 +enchantment.ebwizardry:freezing_weapon=서리의 마력 + +key.categories.ebwizardry=마법의 길 + +key.ebwizardry.next_spell=다음 주문 +key.ebwizardry.previous_spell=이전 주문 + +death.attack.wizardry_magic=%1$s(은)는 %2$s(이)가 사용한 마법에 살해당했습니다. +death.attack.indirect_wizardry_magic=%1$s(은)는 %2$s(이)가 사용한 마법에 살해당했습니다. + +commands.ebwizardry:cast.usage=/%1$s [player] [damage multiplier] [range multiplier] [duration multiplier] [blast multiplier] +commands.ebwizardry:cast.success=Successfully cast %1$s +commands.ebwizardry:cast.success_continuous=Successfully cast %1$s; repeat the command to stop +commands.ebwizardry:cast.success_remote=Successfully cast %1$s as %2$s +commands.ebwizardry:cast.success_remote_continuous=Successfully cast %1$s as %2$s; repeat the command to stop +commands.ebwizardry:cast.fail=Unable to cast %1$s +commands.ebwizardry:cast.not_found=There is no such spell with ID %1$s +commands.ebwizardry:cast.tag_error=Data tag parsing failed: %s + +commands.ebwizardry:ally.usage=/%1$s [player] +commands.ebwizardry:ally.addally=%1$s has been added to %2$s's list of allies +commands.ebwizardry:ally.removeally=%1$s has been removed from %2$s's list of allies +commands.ebwizardry:ally.self=Players cannot be an ally of themselves! +commands.ebwizardry:ally.permission=You do not have permission to change other players' allies + +commands.ebwizardry:allies.usage=/%1$s [player] +commands.ebwizardry:allies.list=Players allied to you: %1$s +commands.ebwizardry:allies.list_other=Players allied to %1$s: %2$s +commands.ebwizardry:allies.permission=You do not have permission to view other players' allies +commands.ebwizardry:allies.none=None + +commands.ebwizardry:discoverspell.usage=/%1$s [player] +commands.ebwizardry:discoverspell.not_found=There is no such spell with ID %1$s +commands.ebwizardry:discoverspell.clear=Cleared all spell discovery data for %1$s +commands.ebwizardry:discoverspell.all=Added all spells to %1$s's spell discovery data +commands.ebwizardry:discoverspell.addspell=Added %1$s to %2$s's spell discovery data +commands.ebwizardry:discoverspell.removespell=Removed %1$s from %2$s's spell discovery data + +config.ebwizardry.title.general=Mod Options + +config.ebwizardry.category.gameplay=Gameplay Settings +config.ebwizardry.category.gameplay.tooltip=Configure wizardry's general gameplay +config.ebwizardry.title.gameplay=Gameplay Settings +config.ebwizardry.subtitle.gameplay=Global settings that affect game mechanics. + +config.ebwizardry.category.worldgen=World Generation Settings +config.ebwizardry.category.worldgen.tooltip=Configure wizardry's world generation features +config.ebwizardry.title.worldgen=World Generation Settings +config.ebwizardry.subtitle.worldgen=Settings that affect world generation. + +config.ebwizardry.category.commands=Command Settings +config.ebwizardry.category.commands.tooltip=Configure wizardry's commands +config.ebwizardry.title.commands=Command Settings +config.ebwizardry.subtitle.commands=Settings for the commands added by Wizardry. + +config.ebwizardry.category.client=Client Settings +config.ebwizardry.category.client.tooltip=Configure wizardry's display and controls +config.ebwizardry.title.client=Client Settings +config.ebwizardry.subtitle.client=Client-side settings that only affect the local minecraft game. + +config.ebwizardry.category.spells=Spell Configuration +config.ebwizardry.category.spells.tooltip=Select which spells are enabled +config.ebwizardry.title.spells=Spell Configuration +config.ebwizardry.subtitle.spells=Set a spell to false to disable it. + +config.ebwizardry.category.resistances=Resistance Configuration +config.ebwizardry.category.resistances.tooltip=Configure which mobs are immune to different types of magic +config.ebwizardry.title.resistances=Resistance Configuration +config.ebwizardry.subtitle.resistances=Settings which allow entities to be made immune to certain types of magic. + +config.ebwizardry.tower_rarity=Tower Rarity +config.ebwizardry.ore_dimensions=Ore Dimensions +config.ebwizardry.flower_dimensions=Flower Dimensions +config.ebwizardry.tower_dimensions=Tower Dimensions +config.ebwizardry.spell_book_drop_chance=Spell Book Drop Chance +config.ebwizardry.generate_loot=Generate Loot +config.ebwizardry.firebomb_is_craftable=Firebomb Is Craftable +config.ebwizardry.poison_bomb_is_craftable=Poison Bomb Is Craftable +config.ebwizardry.smoke_bomb_is_craftable=Smoke Bomb Is Craftable +config.ebwizardry.use_alternate_scroll_recipe=Use Alternate Scroll Recipe +config.ebwizardry.teleport_through_unbreakable_blocks=Teleport Through Unbreakable Blocks +config.ebwizardry.show_summoned_creature_names=Show Summoned Creature Names +config.ebwizardry.friendly_fire=Friendly Fire +config.ebwizardry.telekinetic_disarmament=Telekinetic Disarmament +config.ebwizardry.discovery_mode=Discovery Mode +config.ebwizardry.enable_shift_scrolling=Enable Shift-scrolling +config.ebwizardry.minion_revenge_targeting=Minion Revenge Targeting +config.ebwizardry.player_damage_scaling=Player Damage Scaling Factor +config.ebwizardry.npc_damage_scaling=NPC Damage Scaling Factor +config.ebwizardry.cast_command_multiplier_limit=Cast Command Multiplier Limit +config.ebwizardry.summoned_creature_targets_whitelist=Summoned Creature Target Whitelist +config.ebwizardry.summoned_creature_targets_blacklist=Summoned Creature Target Blacklist +config.ebwizardry.spell_hud_position=Spell HUD Position +config.ebwizardry.cast_command_name=Cast Spell Command Name +config.ebwizardry.discoverspell_command_name=Discover Spell Command Name +config.ebwizardry.ally_command_name=Set Ally Command Name +config.ebwizardry.allies_command_name=View Allies Command Name +config.ebwizardry.mind_control_targets_blacklist=Mind Control Targets Blacklist +config.ebwizardry.evil_wizard_dimensions=Evil Wizard Dimensions + +config.ebwizardry.mobs_immune_to_fire=Mobs Immune To Fire +config.ebwizardry.mobs_immune_to_ice=Mobs Immune To Ice +config.ebwizardry.mobs_immune_to_lightning=Mobs Immune To Lightning +config.ebwizardry.mobs_immune_to_wither=Mobs Immune To Wither +config.ebwizardry.mobs_immune_to_poison=Mobs Immune To Poison + +config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. Higher numbers are rarer. Set to 0 to disable wizard towers completely. +config.ebwizardry.ore_dimensions.tooltip=List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! +config.ebwizardry.flower_dimensions.tooltip=List of dimension ids in which crystal flowers will generate. +config.ebwizardry.tower_dimensions.tooltip=List of dimension ids in which wizard towers will generate. +config.ebwizardry.spell_book_drop_chance.tooltip=The chance for mobs to drop a spell book when killed. The greater this number, the more often they will drop. Set to 0 to disable spell book drops. Set to 200 for guaranteed drops. +config.ebwizardry.generate_loot.tooltip=Whether to generate wizardry loot in dungeon chests. +config.ebwizardry.firebomb_is_craftable.tooltip=Whether firebombs can be crafted or not. +config.ebwizardry.poison_bomb_is_craftable.tooltip=Whether poison bombs can be crafted or not. +config.ebwizardry.smoke_bomb_is_craftable.tooltip=Whether smoke bombs can be crafted or not. +config.ebwizardry.use_alternate_scroll_recipe.tooltip=Whether to require a magic crystal in the shapeless crafting recipe for blank scrolls. Set to true if another mod adds a conflicting recipe. +config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=Whether players are allowed to teleport through unbreakable blocks (e.g. bedrock) using the phase step spell. +config.ebwizardry.show_summoned_creature_names.tooltip=Whether to show summoned creatures' names and owners above their heads. +config.ebwizardry.friendly_fire.tooltip=Whether to allow players to damage their designated allies using magic. +config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Set to false to prevent stealing of items. +config.ebwizardry.discovery_mode.tooltip=For those who like a sense of mystery! When set to true, spells you haven't cast yet will be unreadable until you cast them (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in survival mode if this is false. +config.ebwizardry.enable_shift_scrolling.tooltip=Whether you can switch between spells on a wand by scrolling with the mouse wheel while sneaking. Note that this will only affect you; other players connected to the same server obey their own settings. +config.ebwizardry.minion_revenge_targeting.tooltip=Whether summoned creatures can revenge attack their owner if their owner attacks them. +config.ebwizardry.player_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by players casting spells, relative to 1. +config.ebwizardry.npc_damage_scaling.tooltip=Global damage scaling factor for the damage dealt by NPCs casting spells, relative to 1. +config.ebwizardry.cast_command_multiplier_limit.tooltip=Upper limit for the multipliers passed into the /cast command. This is here to stop players from accidentally breaking a world/server. Large blast mutipliers can cause extreme lag - you have been warned! +config.ebwizardry.summoned_creature_targets_whitelist.tooltip=List of names of entities which summoned creatures and wizards are allowed to attack, in addition to the defaults. Add mod creatures to this list if you want summoned creatures to attack them and they aren't already doing so. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.summoned_creature_targets_blacklist.tooltip=List of names of entities which summoned creatures and wizards are specifically not allowed to attack, overriding the defaults and the whitelist. Add creatures to this list if allowing them to be attacked causes problems or is too destructive (removing creepers from this list is done at your own risk!). Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.spell_hud_position.tooltip=The position of the spell HUD. +config.ebwizardry.cast_command_name.tooltip=The name of the /cast command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /cast you would type /magic instead. +config.ebwizardry.discoverspell_command_name.tooltip=The name of the /discoverspell command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /discoverspell you would type /magic instead. +config.ebwizardry.ally_command_name.tooltip=The name of the /ally command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /ally you would type /magic instead. +config.ebwizardry.allies_command_name.tooltip=The name of the /allies command. This is what you type directly after the /; for example if this was set to 'magic' then instead of typing /allies you would type /magic instead. +config.ebwizardry.mind_control_targets_blacklist.tooltip=List of names of entities which cannot be mind controlled, in addition to the defaults. Add creatures to this list if allowing them to be mind-controlled causes problems or could be exploited. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.evil_wizard_dimensions.tooltip=List of dimension ids in which evil wizards can spawn. + +config.ebwizardry.mobs_immune_to_fire.tooltip=List of names of entities that are immune to fire, in addition to the defaults. Add mod creatures to this list if you want them to be immune to fire magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.mobs_immune_to_ice.tooltip=List of names of entities that are immune to ice, in addition to the defaults. Add mod creatures to this list if you want them to be immune to ice magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.mobs_immune_to_lightning.tooltip=List of names of entities that are immune to lightning, in addition to the defaults. Add mod creatures to this list if you want them to be immune to lightning magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.mobs_immune_to_wither.tooltip=List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). +config.ebwizardry.mobs_immune_to_poison.tooltip=List of names of entities that are immune to poison, in addition to the defaults. Add mod creatures to this list if you want them to be immune to poison magic and they aren't already. Entity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. ebwizardry:wizard). + +wizard.debug=%1$s, %2$s, %3$s diff --git a/src/main/resources/assets/ebwizardry/lang/ru_ru.lang b/src/main/resources/assets/ebwizardry/lang/ru_ru.lang index d7d2ec74..0a5fdac1 100644 --- a/src/main/resources/assets/ebwizardry/lang/ru_ru.lang +++ b/src/main/resources/assets/ebwizardry/lang/ru_ru.lang @@ -26,13 +26,13 @@ item.ebwizardry:wand.buff=+%1$s %2$s эффективность item.ebwizardry:wand.spell=Текущее Заклинание: %1$s item.ebwizardry:wand.mana=Мана: %1$s/%2$s -item.ebwizardry:basic_fire_wand.name=Жезл Огня -item.ebwizardry:basic_ice_wand.name=Жезл Мороза -item.ebwizardry:basic_lightning_wand.name=Жезл Искр -item.ebwizardry:basic_necromancy_wand.name=Жезл Теней -item.ebwizardry:basic_earth_wand.name=Жезл Леса -item.ebwizardry:basic_sorcery_wand.name=Жезл Тайн -item.ebwizardry:basic_healing_wand.name=Жезл Лечения +item.ebwizardry:novice_fire_wand.name=Жезл Огня +item.ebwizardry:novice_ice_wand.name=Жезл Мороза +item.ebwizardry:novice_lightning_wand.name=Жезл Искр +item.ebwizardry:novice_necromancy_wand.name=Жезл Теней +item.ebwizardry:novice_earth_wand.name=Жезл Леса +item.ebwizardry:novice_sorcery_wand.name=Жезл Тайн +item.ebwizardry:novice_healing_wand.name=Жезл Лечения item.ebwizardry:apprentice_fire_wand.name=Жезл Ученика Пироманта item.ebwizardry:apprentice_ice_wand.name=Жезл Ученика Ледяного Мага @@ -189,56 +189,56 @@ entity.ebwizardry:ring_of_fire.name=Кольцо Огня item_group.ebwizardry=Волшебство item_group.wizardryspells=Волшебные Заклинания -advancement.wizardry:root=Wizardry -advancement.wizardry:root.desc=достижения -advancement.wizardry:crystal=Любопытный Кристалл... -advancement.wizardry:crystal.desc=Добудьте Магический Кристалл -advancement.wizardry:arcane_initiate=Посвящение В Магию -advancement.wizardry:arcane_initiate.desc=Создайте Волшебную Палочку Из Золотого Самородка И Магического Кристалла -advancement.wizardry:apprentice=Ученик Волшебника -advancement.wizardry:apprentice.desc=Используйте Фолиант Арканы Для Улучшения Жезла -advancement.wizardry:master=Мастер Магии -advancement.wizardry:master.desc=Получите Жезл Мастера -advancement.wizardry:all_spells=Маг Всех Профессий -advancement.wizardry:all_spells.desc=Используйте Каждое Заклинание В Игре -advancement.wizardry:wizard_trade=Магическая Сделка -advancement.wizardry:wizard_trade.desc=Купите Предмет У Волшебника -advancement.wizardry:buy_master_spell=Знание-сила -advancement.wizardry:buy_master_spell.desc=Купите заклинание мастера у волшебника -advancement.wizardry:freeze_blaze=Не Так Жарко -advancement.wizardry:freeze_blaze.desc=Заморозьте Блейза -advancement.wizardry:charge_creeper=Это Сейчас Взорвётся -advancement.wizardry:charge_creeper.desc="Случайно" Зарядите Крипира -advancement.wizardry:frankenstein=Франкенштейн -advancement.wizardry:frankenstein.desc=Привратите Свинью В Свинозомби С Помощью Молнии -advancement.wizardry:special_upgrade=Чародейское Ремесло -advancement.wizardry:special_upgrade.desc=Применить Специальное Улучшение Для Жезла -advancement.wizardry:craft_flask=Это Магия В Бутылке! -advancement.wizardry:craft_flask.desc=Создайте Ману В Бутылке -advancement.wizardry:elemental=Стихии -advancement.wizardry:elemental.desc=Получите Стихийный Жезл -advancement.wizardry:armour_set=Теперь Ты Настоящий Волшебник -advancement.wizardry:armour_set.desc=Создайте И Экипируйте Полный Набор Одеяния Волшебника -advancement.wizardry:legendary=Легендарный -advancement.wizardry:legendary.desc=Получите Часть Легендарного Одеяния Волшебника -advancement.wizardry:self_destruct=Обратно -advancement.wizardry:self_destruct.desc=Убейся Собственной Магией -advancement.wizardry:pig_tornado=Не Сейчас... -advancement.wizardry:pig_tornado.desc=Заедьте На Свинье В Торнадо -advancement.wizardry:max_out_wand=Полное Оснощение -advancement.wizardry:max_out_wand.desc=Примените максимальное количество улучшений к жезлу мастера -advancement.wizardry:slime_skeleton=Липкая Ситуация -advancement.wizardry:slime_skeleton.desc=Захватите скелета слизьнем -advancement.wizardry:jam_wizard=Помехи -advancement.wizardry:jam_wizard.desc=Используйте заклинание магическая глушилка на волшебнике -advancement.wizardry:identify_spell=Тайная Экспертиза -advancement.wizardry:identify_spell.desc=Используйте свиток идентификации для неизвестной книги заклинания или свитка -advancement.wizardry:element_master=Мастер Элементов -advancement.wizardry:element_master.desc=Используйте все заклинания любого элемента -advancement.wizardry:anger_wizard=Ты пожалеешь об этом -advancement.wizardry:anger_wizard.desc=Разозлите волшебника -advancement.wizardry:defeat_evil_wizard=Праведность -advancement.wizardry:defeat_evil_wizard.desc=Победите злого волшебника +advancement.ebwizardry:root=Wizardry +advancement.ebwizardry:root.desc=достижения +advancement.ebwizardry:crystal=Любопытный Кристалл... +advancement.ebwizardry:crystal.desc=Добудьте Магический Кристалл +advancement.ebwizardry:arcane_initiate=Посвящение В Магию +advancement.ebwizardry:arcane_initiate.desc=Создайте Волшебную Палочку Из Золотого Самородка И Магического Кристалла +advancement.ebwizardry:apprentice=Ученик Волшебника +advancement.ebwizardry:apprentice.desc=Используйте Фолиант Арканы Для Улучшения Жезла +advancement.ebwizardry:master=Мастер Магии +advancement.ebwizardry:master.desc=Получите Жезл Мастера +advancement.ebwizardry:all_spells=Маг Всех Профессий +advancement.ebwizardry:all_spells.desc=Используйте Каждое Заклинание В Игре +advancement.ebwizardry:wizard_trade=Магическая Сделка +advancement.ebwizardry:wizard_trade.desc=Купите Предмет У Волшебника +advancement.ebwizardry:buy_master_spell=Знание-сила +advancement.ebwizardry:buy_master_spell.desc=Купите заклинание мастера у волшебника +advancement.ebwizardry:freeze_blaze=Не Так Жарко +advancement.ebwizardry:freeze_blaze.desc=Заморозьте Блейза +advancement.ebwizardry:charge_creeper=Это Сейчас Взорвётся +advancement.ebwizardry:charge_creeper.desc="Случайно" Зарядите Крипира +advancement.ebwizardry:frankenstein=Франкенштейн +advancement.ebwizardry:frankenstein.desc=Привратите Свинью В Свинозомби С Помощью Молнии +advancement.ebwizardry:special_upgrade=Чародейское Ремесло +advancement.ebwizardry:special_upgrade.desc=Применить Специальное Улучшение Для Жезла +advancement.ebwizardry:craft_flask=Это Магия В Бутылке! +advancement.ebwizardry:craft_flask.desc=Создайте Ману В Бутылке +advancement.ebwizardry:elemental=Стихии +advancement.ebwizardry:elemental.desc=Получите Стихийный Жезл +advancement.ebwizardry:armour_set=Теперь Ты Настоящий Волшебник +advancement.ebwizardry:armour_set.desc=Создайте И Экипируйте Полный Набор Одеяния Волшебника +advancement.ebwizardry:legendary=Легендарный +advancement.ebwizardry:legendary.desc=Получите Часть Легендарного Одеяния Волшебника +advancement.ebwizardry:self_destruct=Обратно +advancement.ebwizardry:self_destruct.desc=Убейся Собственной Магией +advancement.ebwizardry:pig_tornado=Не Сейчас... +advancement.ebwizardry:pig_tornado.desc=Заедьте На Свинье В Торнадо +advancement.ebwizardry:max_out_wand=Полное Оснощение +advancement.ebwizardry:max_out_wand.desc=Примените максимальное количество улучшений к жезлу мастера +advancement.ebwizardry:slime_skeleton=Липкая Ситуация +advancement.ebwizardry:slime_skeleton.desc=Захватите скелета слизьнем +advancement.ebwizardry:jam_wizard=Помехи +advancement.ebwizardry:jam_wizard.desc=Используйте заклинание магическая глушилка на волшебнике +advancement.ebwizardry:identify_spell=Тайная Экспертиза +advancement.ebwizardry:identify_spell.desc=Используйте свиток идентификации для неизвестной книги заклинания или свитка +advancement.ebwizardry:element_master=Мастер Элементов +advancement.ebwizardry:element_master.desc=Используйте все заклинания любого элемента +advancement.ebwizardry:anger_wizard=Ты пожалеешь об этом +advancement.ebwizardry:anger_wizard.desc=Разозлите волшебника +advancement.ebwizardry:defeat_evil_wizard=Праведность +advancement.ebwizardry:defeat_evil_wizard.desc=Победите злого волшебника @@ -250,7 +250,7 @@ container.ebwizardry:arcane_workbench.apply=Применить container.ebwizardry:arcane_workbench.mana=Мана: container.ebwizardry:arcane_workbench.upgrades=Применённые Улучшения: -tier.basic=Начинающий +tier.novice=Начинающий tier.apprentice=Ученик tier.advanced=Продвинутый tier.master=Мастер diff --git a/src/main/resources/assets/ebwizardry/lang/zh_cn.lang b/src/main/resources/assets/ebwizardry/lang/zh_cn.lang index 5ad2ffae..353baa89 100644 --- a/src/main/resources/assets/ebwizardry/lang/zh_cn.lang +++ b/src/main/resources/assets/ebwizardry/lang/zh_cn.lang @@ -29,13 +29,13 @@ item.ebwizardry:wand.mana=魔力: %1$s/%2$s item.ebwizardry:wand.addally=%1$s 已添加到你的盟友名单 item.ebwizardry:wand.removeally=%1$s 已移出你的盟友名单 -item.ebwizardry:basic_fire_wand.name=余火法杖 -item.ebwizardry:basic_ice_wand.name=寒霜法杖 -item.ebwizardry:basic_lightning_wand.name=星火法杖 -item.ebwizardry:basic_necromancy_wand.name=暗影法杖 -item.ebwizardry:basic_earth_wand.name=森林法杖 -item.ebwizardry:basic_sorcery_wand.name=神秘法杖 -item.ebwizardry:basic_healing_wand.name=治愈法杖 +item.ebwizardry:novice_fire_wand.name=余火法杖 +item.ebwizardry:novice_ice_wand.name=寒霜法杖 +item.ebwizardry:novice_lightning_wand.name=星火法杖 +item.ebwizardry:novice_necromancy_wand.name=暗影法杖 +item.ebwizardry:novice_earth_wand.name=森林法杖 +item.ebwizardry:novice_sorcery_wand.name=神秘法杖 +item.ebwizardry:novice_healing_wand.name=治愈法杖 item.ebwizardry:apprentice_fire_wand.name=学徒烈焰法杖 item.ebwizardry:apprentice_ice_wand.name=学徒冰霜法杖 @@ -213,56 +213,56 @@ entity.ebwizardry:lightning_pulse.name=闪电脉冲 itemGroup.ebwizardry=巫术学 itemGroup.ebwizardryspells=卷轴 -advancement.wizardry:root=新兴巫术 -advancement.wizardry:root.desc=一个巫师掌握奥术的旅程 -advancement.wizardry:crystal=一个奇异的水晶... -advancement.wizardry:crystal.desc=挖掘一个魔法水晶 -advancement.wizardry:arcane_initiate=奥术启程 -advancement.wizardry:arcane_initiate.desc=利用金锭,木棍和魔法水晶制造一根法杖 -advancement.wizardry:apprentice=见习巫师 -advancement.wizardry:apprentice.desc=使用奥法宝典来升级你的法杖 -advancement.wizardry:master=大师级巫师 -advancement.wizardry:master.desc=获得大师级法杖 -advancement.wizardry:all_spells=巫师的自我修养 -advancement.wizardry:all_spells.desc=在游戏中施放所有法术 -advancement.wizardry:wizard_trade=魔法交易 -advancement.wizardry:wizard_trade.desc=向巫师购买物品 -advancement.wizardry:buy_master_spell=知识就是力量 -advancement.wizardry:buy_master_spell.desc=向巫师购买一个大师级卷轴 -advancement.wizardry:freeze_blaze=现在不太热了 -advancement.wizardry:freeze_blaze.desc=把烈焰人冻成傻子 -advancement.wizardry:charge_creep=它要炸了 -advancement.wizardry:charge_creeper.desc='意外' 捕获爬行者 -advancement.wizardry:frankenstein=弗兰肯斯坦 -advancement.wizardry:frankenstein.desc=用闪电法术将猪变成僵尸猪人 -advancement.wizardry:special_upgrade=奥术工匠 -advancement.wizardry:special_upgrade.desc=对法杖进行特殊升级 -advancement.wizardry:craft_flask=这是魔力,装瓶! -advancement.wizardry:craft_flask.desc=制作一个魔力瓶 -advancement.wizardry:elemental=元素 -advancement.wizardry:elemental.desc=获得元素法杖 -advancement.wizardry:armour_set=现在你是一个正确的巫师 -advancement.wizardry:armour_set.desc=制作并装备全套巫师护具 -advancement.wizardry:legendary=传奇! -advancement.wizardry:legendary.desc=获得一件传奇级装备 -advancement.wizardry:self_destruct=真是倒霉 -advancement.wizardry:self_destruct.desc=被自己的魔法杀死 -advancement.wizardry:pig_tornado=不会再次... -advancement.wizardry:pig_tornado.desc=骑着猪卷进飓风 -advancement.wizardry:jam_wizard=扰乱会议 -advancement.wizardry:jam_wizard.desc=对一个巫师使用奥术干扰 -advancement.wizardry:slime_skeleton=棘手局面 -advancement.wizardry:slime_skeleton.desc=利用史莱姆吞噬骷髅 -advancement.wizardry:anger_wizard=你会后悔的 -advancement.wizardry:anger_wizard.desc=使一个巫师发怒 -advancement.wizardry:defeat_evil_wizard=正义降临 -advancement.wizardry:defeat_evil_wizard.desc=击败邪恶巫师 -advancement.wizardry:max_out_wand=整装上阵 -advancement.wizardry:max_out_wand.desc=将大师级法杖升级到最强 -advancement.wizardry:element_master=元素掌控 -advancement.wizardry:element_master.desc=施放任何元素的法术 -advancement.wizardry:identify_spell=奥术鉴定 -advancement.wizardry:identify_spell.desc=使用鉴定卷轴来鉴定法术书或卷轴 +advancement.ebwizardry:root=新兴巫术 +advancement.ebwizardry:root.desc=一个巫师掌握奥术的旅程 +advancement.ebwizardry:crystal=一个奇异的水晶... +advancement.ebwizardry:crystal.desc=挖掘一个魔法水晶 +advancement.ebwizardry:arcane_initiate=奥术启程 +advancement.ebwizardry:arcane_initiate.desc=利用金锭,木棍和魔法水晶制造一根法杖 +advancement.ebwizardry:apprentice=见习巫师 +advancement.ebwizardry:apprentice.desc=使用奥法宝典来升级你的法杖 +advancement.ebwizardry:master=大师级巫师 +advancement.ebwizardry:master.desc=获得大师级法杖 +advancement.ebwizardry:all_spells=巫师的自我修养 +advancement.ebwizardry:all_spells.desc=在游戏中施放所有法术 +advancement.ebwizardry:wizard_trade=魔法交易 +advancement.ebwizardry:wizard_trade.desc=向巫师购买物品 +advancement.ebwizardry:buy_master_spell=知识就是力量 +advancement.ebwizardry:buy_master_spell.desc=向巫师购买一个大师级卷轴 +advancement.ebwizardry:freeze_blaze=现在不太热了 +advancement.ebwizardry:freeze_blaze.desc=把烈焰人冻成傻子 +advancement.ebwizardry:charge_creep=它要炸了 +advancement.ebwizardry:charge_creeper.desc='意外' 捕获爬行者 +advancement.ebwizardry:frankenstein=弗兰肯斯坦 +advancement.ebwizardry:frankenstein.desc=用闪电法术将猪变成僵尸猪人 +advancement.ebwizardry:special_upgrade=奥术工匠 +advancement.ebwizardry:special_upgrade.desc=对法杖进行特殊升级 +advancement.ebwizardry:craft_flask=这是魔力,装瓶! +advancement.ebwizardry:craft_flask.desc=制作一个魔力瓶 +advancement.ebwizardry:elemental=元素 +advancement.ebwizardry:elemental.desc=获得元素法杖 +advancement.ebwizardry:armour_set=现在你是一个正确的巫师 +advancement.ebwizardry:armour_set.desc=制作并装备全套巫师护具 +advancement.ebwizardry:legendary=传奇! +advancement.ebwizardry:legendary.desc=获得一件传奇级装备 +advancement.ebwizardry:self_destruct=真是倒霉 +advancement.ebwizardry:self_destruct.desc=被自己的魔法杀死 +advancement.ebwizardry:pig_tornado=不会再次... +advancement.ebwizardry:pig_tornado.desc=骑着猪卷进飓风 +advancement.ebwizardry:jam_wizard=扰乱会议 +advancement.ebwizardry:jam_wizard.desc=对一个巫师使用奥术干扰 +advancement.ebwizardry:slime_skeleton=棘手局面 +advancement.ebwizardry:slime_skeleton.desc=利用史莱姆吞噬骷髅 +advancement.ebwizardry:anger_wizard=你会后悔的 +advancement.ebwizardry:anger_wizard.desc=使一个巫师发怒 +advancement.ebwizardry:defeat_evil_wizard=正义降临 +advancement.ebwizardry:defeat_evil_wizard.desc=击败邪恶巫师 +advancement.ebwizardry:max_out_wand=整装上阵 +advancement.ebwizardry:max_out_wand.desc=将大师级法杖升级到最强 +advancement.ebwizardry:element_master=元素掌控 +advancement.ebwizardry:element_master.desc=施放任何元素的法术 +advancement.ebwizardry:identify_spell=奥术鉴定 +advancement.ebwizardry:identify_spell.desc=使用鉴定卷轴来鉴定法术书或卷轴 tile.ebwizardry:transportation_stone.confirm=施展法术时你将会回到这里 %1$s tile.ebwizardry:transportation_stone.invalid=你必须先将八个传送石围成圆圈! @@ -272,7 +272,7 @@ container.ebwizardry:arcane_workbench.apply=应用 container.ebwizardry:arcane_workbench.mana=魔力: container.ebwizardry:arcane_workbench.upgrades=应用升级: -tier.basic=新手 +tier.novice=新手 tier.apprentice=学徒 tier.advanced=进阶 tier.master=大师 diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/dungeon_additions.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/dungeon_additions.json index 354086ff..db383025 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/chests/dungeon_additions.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/dungeon_additions.json @@ -3,34 +3,34 @@ { "name": "wizardry", "rolls": { - "min": 3, - "max": 7 + "min": 1, + "max": 3 }, "entries": [ { "type": "loot_table", - "name": "ebwizardry:subsets/novice_wands", - "weight": 3 + "name": "ebwizardry:subsets/elemental_crystals", + "weight": 6 }, { "type": "loot_table", "name": "ebwizardry:subsets/wizard_armour", - "weight": 6 + "weight": 10 }, { "type": "loot_table", "name": "ebwizardry:subsets/arcane_tomes", - "weight": 6 + "weight": 8 }, { "type": "loot_table", "name": "ebwizardry:subsets/wand_upgrades", - "weight": 2 + "weight": 4 }, { "type": "item", "name": "ebwizardry:magic_crystal", - "weight": 5, + "weight": 10, "functions": [ { "function": "set_count", @@ -44,23 +44,57 @@ { "type": "item", "name": "ebwizardry:spell_book", - "weight": 20, + "weight": 40, "functions": [ { - "function": "ebwizardry:random_spell" + "function": "ebwizardry:random_spell", + "undiscovered_bias": 0.3 } ] }, { "type": "item", "name": "ebwizardry:scroll", - "weight": 10, + "weight": 14, "functions": [ { - "function": "ebwizardry:random_spell" + "function": "ebwizardry:random_spell", + "undiscovered_bias": 0.3 + }, + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } } ] }, + { + "type": "item", + "name": "ebwizardry:identification_scroll", + "weight": 6 + }, + { + "type": "item", + "name": "ebwizardry:firebomb", + "weight": 8 + }, + { + "type": "item", + "name": "ebwizardry:poison_bomb", + "weight": 8 + }, + { + "type": "item", + "name": "ebwizardry:smoke_bomb", + "weight": 8 + }, + { + "type": "item", + "name": "ebwizardry:spark_bomb", + "weight": 8 + }, { "type": "item", "name": "ebwizardry:armour_upgrade", @@ -68,23 +102,18 @@ }, { "type": "item", - "name": "ebwizardry:identification_scroll", - "weight": 3 + "name": "ebwizardry:astral_diamond", + "weight": 1 }, { "type": "item", - "name": "ebwizardry:firebomb", - "weight": 4 + "name": "ebwizardry:purifying_elixir", + "weight": 1 }, { "type": "item", - "name": "ebwizardry:poison_bomb", - "weight": 4 - }, - { - "type": "item", - "name": "ebwizardry:smoke_bomb", - "weight": 4 + "name": "ebwizardry:grand_crystal", + "weight": 1 } ] } diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/jungle_dispenser_additions.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/jungle_dispenser_additions.json new file mode 100644 index 00000000..c517f0fb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/jungle_dispenser_additions.json @@ -0,0 +1,65 @@ +{ + "pools": [ + { + "name": "wizardry_dispenser", + "rolls": 1, + "conditions": [ + { + "condition": "random_chance", + "chance": 0.4 + } + ], + "entries": [ + { + "type": "item", + "name": "ebwizardry:scroll", + "weight": 1, + "functions": [ + { + "function": "ebwizardry:random_spell", + "spells": [ + "magic_missile", + "arc", + "thunderbolt", + "summon_zombie", + "dart", + "ice_shard", + "firebolt", + "poison", + "flame_ray", + "frost_ray" + ] + }, + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + }, + { + "type": "item", + "name": "ebwizardry:firebomb", + "weight": 3 + }, + { + "type": "item", + "name": "ebwizardry:poison_bomb", + "weight": 3 + }, + { + "type": "item", + "name": "ebwizardry:smoke_bomb", + "weight": 3 + }, + { + "type": "item", + "name": "ebwizardry:spark_bomb", + "weight": 3 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/obelisk.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/obelisk.json new file mode 100644 index 00000000..7a0a73a4 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/obelisk.json @@ -0,0 +1,195 @@ +{ + "pools": [ + { + "name": "high_value", + "rolls": { + "min": 1, + "max": 1 + }, + "entries": [ + { + "type": "loot_table", + "name": "ebwizardry:subsets/arcane_tomes", + "weight": 3 + }, + { + "type": "loot_table", + "name": "ebwizardry:subsets/wand_upgrades", + "weight": 2 + }, + { + "type": "item", + "name": "ebwizardry:spell_book", + "weight": 20, + "functions": [ + { + "function": "ebwizardry:random_spell", + "tiers": [ + "novice", + "apprentice", + "advanced" + ], + "undiscovered_bias": 0.3 + } + ] + }, + { + "type": "item", + "name": "ebwizardry:scroll", + "weight": 7, + "functions": [ + { + "function": "ebwizardry:random_spell", + "tiers": [ + "novice", + "apprentice", + "advanced" + ], + "undiscovered_bias": 0.3 + }, + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + }, + { + "type": "item", + "name": "ebwizardry:identification_scroll", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:gold_nugget", + "weight": 5, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ] + }, + { + "type": "item", + "name": "minecraft:emerald", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:grand_crystal", + "weight": 1 + } + ] + }, + { + "name": "low_value", + "rolls": { + "min": 3, + "max": 5 + }, + "entries": [ + { + "type": "loot_table", + "name": "ebwizardry:subsets/elemental_crystals", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:magic_crystal", + "weight": 5, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ] + }, + { + "type": "item", + "name": "ebwizardry:firebomb", + "weight": 4 + }, + { + "type": "item", + "name": "ebwizardry:poison_bomb", + "weight": 4 + }, + { + "type": "item", + "name": "ebwizardry:smoke_bomb", + "weight": 4 + }, + { + "type": "item", + "name": "ebwizardry:spark_bomb", + "weight": 4 + }, + { + "type": "item", + "name": "minecraft:book", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 2 + } + } + ] + }, + { + "type": "item", + "name": "minecraft:string", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + }, + { + "type": "item", + "name": "minecraft:paper", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + }, + { + "type": "item", + "name": "ebwizardry:crystal_shard", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/shrine.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/shrine.json new file mode 100644 index 00000000..76af240f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/shrine.json @@ -0,0 +1,210 @@ +{ + "pools": [ + { + "name": "artefact", + "rolls": 1, + "entries": [ + { + "type": "loot_table", + "name": "ebwizardry:subsets/uncommon_artefacts", + "weight": 5 + }, + { + "type": "loot_table", + "name": "ebwizardry:subsets/rare_artefacts", + "weight": 3 + }, + { + "type": "loot_table", + "name": "ebwizardry:subsets/epic_artefacts", + "weight": 1 + } + ] + }, + { + "name": "high_value", + "rolls": { + "min": 1, + "max": 2 + }, + "entries": [ + { + "type": "loot_table", + "name": "ebwizardry:subsets/arcane_tomes", + "weight": 6 + }, + { + "type": "loot_table", + "name": "ebwizardry:subsets/wand_upgrades", + "weight": 4 + }, + { + "type": "item", + "name": "ebwizardry:spell_book", + "weight": 40, + "functions": [ + { + "function": "ebwizardry:random_spell", + "undiscovered_bias": 0.3 + } + ] + }, + { + "type": "item", + "name": "ebwizardry:scroll", + "weight": 14, + "functions": [ + { + "function": "ebwizardry:random_spell", + "undiscovered_bias": 0.3 + }, + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + }, + { + "type": "item", + "name": "ebwizardry:identification_scroll", + "weight": 6 + }, + { + "type": "item", + "name": "minecraft:gold_ingot", + "weight": 6, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ] + }, + { + "type": "item", + "name": "minecraft:emerald", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 3 + } + } + ] + }, + { + "type": "item", + "name": "ebwizardry:armour_upgrade", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:astral_diamond", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:purifying_elixir", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:grand_crystal", + "weight": 1 + } + ] + }, + { + "name": "low_value", + "rolls": { + "min": 2, + "max": 4 + }, + "entries": [ + { + "type": "loot_table", + "name": "ebwizardry:subsets/elemental_crystals", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:magic_crystal", + "weight": 5, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 12 + } + } + ] + }, + { + "type": "item", + "name": "minecraft:book", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 2 + } + } + ] + }, + { + "type": "item", + "name": "minecraft:string", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + }, + { + "type": "item", + "name": "minecraft:paper", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + }, + { + "type": "item", + "name": "ebwizardry:crystal_shard", + "weight": 2, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/loot_tables/chests/wizard_tower.json b/src/main/resources/assets/ebwizardry/loot_tables/chests/wizard_tower.json index 6e6dc805..4bb9c235 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/chests/wizard_tower.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/chests/wizard_tower.json @@ -9,7 +9,7 @@ "entries": [ { "type": "loot_table", - "name": "ebwizardry:subsets/novice_wands", + "name": "ebwizardry:subsets/elemental_crystals", "weight": 3 }, { @@ -20,7 +20,7 @@ { "type": "loot_table", "name": "ebwizardry:subsets/arcane_tomes", - "weight": 6 + "weight": 4 }, { "type": "loot_table", @@ -47,17 +47,26 @@ "weight": 20, "functions": [ { - "function": "ebwizardry:random_spell" + "function": "ebwizardry:random_spell", + "undiscovered_bias": 0.3 } ] }, { "type": "item", "name": "ebwizardry:scroll", - "weight": 10, + "weight": 7, "functions": [ { - "function": "ebwizardry:random_spell" + "function": "ebwizardry:random_spell", + "undiscovered_bias": 0.3 + }, + { + "function": "set_count", + "count": { + "min": 1, + "max": 5 + } } ] }, diff --git a/src/main/resources/assets/ebwizardry/loot_tables/entities/mob_additions.json b/src/main/resources/assets/ebwizardry/loot_tables/entities/mob_additions.json index bf5c34d1..fa25f7e6 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/entities/mob_additions.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/entities/mob_additions.json @@ -1,6 +1,7 @@ { "pools": [ { + "name": "wizardry", "conditions": [ { "condition": "killed_by_player" @@ -19,7 +20,12 @@ "weight": 1, "functions": [ { - "function": "ebwizardry:random_spell" + "function": "ebwizardry:random_spell", + "tiers": [ + "novice", + "apprentice", + "advanced" + ] } ] } diff --git a/src/main/resources/assets/ebwizardry/loot_tables/subsets/elemental_crystals.json b/src/main/resources/assets/ebwizardry/loot_tables/subsets/elemental_crystals.json new file mode 100644 index 00000000..56631c6d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/loot_tables/subsets/elemental_crystals.json @@ -0,0 +1,24 @@ +{ + "pools": [ + { + "name": "crystals", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "ebwizardry:magic_crystal", + "weight": 1, + "functions": [ + { + "function": "set_data", + "data": { + "min": 1, + "max": 7 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/loot_tables/subsets/epic_artefacts.json b/src/main/resources/assets/ebwizardry/loot_tables/subsets/epic_artefacts.json new file mode 100644 index 00000000..dd8cd8cb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/loot_tables/subsets/epic_artefacts.json @@ -0,0 +1,75 @@ +{ + "pools": [ + { + "name": "epic_artefacts", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "ebwizardry:ring_combustion", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_arcane_frost", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_seeking", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_hammer", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_mana_return", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_interdiction", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_ice_immunity", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_wither_immunity", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_glide", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_resurrection", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_experience_tome", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_silk_touch", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_stop_time", + "weight": 1 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/loot_tables/subsets/novice_wands.json b/src/main/resources/assets/ebwizardry/loot_tables/subsets/novice_wands.json deleted file mode 100644 index 8ed04e9b..00000000 --- a/src/main/resources/assets/ebwizardry/loot_tables/subsets/novice_wands.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "pools": [ - { - "name": "wands", - "rolls": 1, - "entries": [ - { - "type": "item", - "name": "ebwizardry:magic_wand", - "weight": 1 - }, - { - "type": "item", - "name": "ebwizardry:basic_fire_wand", - "weight": 1 - }, - { - "type": "item", - "name": "ebwizardry:basic_ice_wand", - "weight": 1 - }, - { - "type": "item", - "name": "ebwizardry:basic_lightning_wand", - "weight": 1 - }, - { - "type": "item", - "name": "ebwizardry:basic_necromancy_wand", - "weight": 1 - }, - { - "type": "item", - "name": "ebwizardry:basic_earth_wand", - "weight": 1 - }, - { - "type": "item", - "name": "ebwizardry:basic_sorcery_wand", - "weight": 1 - }, - { - "type": "item", - "name": "ebwizardry:basic_healing_wand", - "weight": 1 - } - ] - } - ] -} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/loot_tables/subsets/rare_artefacts.json b/src/main/resources/assets/ebwizardry/loot_tables/subsets/rare_artefacts.json new file mode 100644 index 00000000..24a74e24 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/loot_tables/subsets/rare_artefacts.json @@ -0,0 +1,145 @@ +{ + "pools": [ + { + "name": "rare_artefacts", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "ebwizardry:ring_condensing", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_battlemage", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_disintegration", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_shattering", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_storm", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_soulbinding", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_leeching", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_mind_control", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_poison", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_full_moon", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_blockwrangler", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_conjurer", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_defender", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_arcane_defence", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_wisdom", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_fire_cloaking", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_potential", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_anchoring", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_transience", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_auto_shield", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_haggler", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_auto_smelt", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_storm", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_minion_variants", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_flight", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_abseiling", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_light", + "weight": 1 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/loot_tables/subsets/uncommon_artefacts.json b/src/main/resources/assets/ebwizardry/loot_tables/subsets/uncommon_artefacts.json new file mode 100644 index 00000000..c52abb3d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/loot_tables/subsets/uncommon_artefacts.json @@ -0,0 +1,115 @@ +{ + "pools": [ + { + "name": "uncommon_artefacts", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "ebwizardry:ring_siphoning", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_fire_melee", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_fire_biome", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_ice_melee", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_ice_biome", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_lightning_melee", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_necromancy_melee", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_earth_melee", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_earth_biome", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_extraction", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:ring_paladin", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_warding", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_fire_protection", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_ice_protection", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_channeling", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_lich", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_banishing", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:amulet_recovery", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_minion_health", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_growth", + "weight": 1 + }, + { + "type": "item", + "name": "ebwizardry:charm_feeding", + "weight": 1 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/loot_tables/subsets/wand_upgrades.json b/src/main/resources/assets/ebwizardry/loot_tables/subsets/wand_upgrades.json index 3409fd48..327c379b 100644 --- a/src/main/resources/assets/ebwizardry/loot_tables/subsets/wand_upgrades.json +++ b/src/main/resources/assets/ebwizardry/loot_tables/subsets/wand_upgrades.json @@ -43,7 +43,12 @@ "type": "item", "name": "ebwizardry:attunement_upgrade", "weight": 1 - } + }, + { + "type": "item", + "name": "ebwizardry:melee_upgrade", + "weight": 1 + } ] } ] diff --git a/src/main/resources/assets/ebwizardry/models/block/earth_crystal_block.json b/src/main/resources/assets/ebwizardry/models/block/earth_crystal_block.json new file mode 100644 index 00000000..c0baec0f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/earth_crystal_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/crystal_block_earth" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/earth_runestone_1.json b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_1.json new file mode 100644 index 00000000..105a76c9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_1.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_earth_0", + "rune": "ebwizardry:blocks/runestone_earth_1", + "overlay": "ebwizardry:blocks/runestone_earth_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/earth_runestone_2.json b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_2.json new file mode 100644 index 00000000..5cba9240 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_2.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_earth_0", + "rune": "ebwizardry:blocks/runestone_earth_2", + "overlay": "ebwizardry:blocks/runestone_earth_2_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/earth_runestone_3.json b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_3.json new file mode 100644 index 00000000..72f72fd0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_3.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_earth_0", + "rune": "ebwizardry:blocks/runestone_earth_3", + "overlay": "ebwizardry:blocks/runestone_earth_3_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/earth_runestone_4.json b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_4.json new file mode 100644 index 00000000..e712f365 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_4.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_earth_0", + "rune": "ebwizardry:blocks/runestone_earth_4", + "overlay": "ebwizardry:blocks/runestone_earth_4_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/earth_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_pedestal.json new file mode 100644 index 00000000..c0c68819 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/earth_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:block/runestone_pedestal", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_earth", + "top": "ebwizardry:blocks/runestone_earth_0", + "bottom": "ebwizardry:blocks/runestone_earth_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_earth_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/fire_crystal_block.json b/src/main/resources/assets/ebwizardry/models/block/fire_crystal_block.json new file mode 100644 index 00000000..fc76eed1 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/fire_crystal_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/crystal_block_fire" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/fire_runestone_1.json b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_1.json new file mode 100644 index 00000000..91f6f742 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_1.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_fire_0", + "rune": "ebwizardry:blocks/runestone_fire_1", + "overlay": "ebwizardry:blocks/runestone_fire_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/fire_runestone_2.json b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_2.json new file mode 100644 index 00000000..4b09137d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_2.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_fire_0", + "rune": "ebwizardry:blocks/runestone_fire_2", + "overlay": "ebwizardry:blocks/runestone_fire_2_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/fire_runestone_3.json b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_3.json new file mode 100644 index 00000000..8a29a569 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_3.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_fire_0", + "rune": "ebwizardry:blocks/runestone_fire_3", + "overlay": "ebwizardry:blocks/runestone_fire_3_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/fire_runestone_4.json b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_4.json new file mode 100644 index 00000000..b947eff0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_4.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_fire_0", + "rune": "ebwizardry:blocks/runestone_fire_4", + "overlay": "ebwizardry:blocks/runestone_fire_4_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/fire_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_pedestal.json new file mode 100644 index 00000000..217052eb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/fire_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:block/runestone_pedestal", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_fire", + "top": "ebwizardry:blocks/runestone_fire_0", + "bottom": "ebwizardry:blocks/runestone_fire_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_fire_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/healing_crystal_block.json b/src/main/resources/assets/ebwizardry/models/block/healing_crystal_block.json new file mode 100644 index 00000000..8b3b9b59 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/healing_crystal_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/crystal_block_healing" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/healing_runestone_1.json b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_1.json new file mode 100644 index 00000000..0d22b1c2 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_1.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_healing_0", + "rune": "ebwizardry:blocks/runestone_healing_1", + "overlay": "ebwizardry:blocks/runestone_healing_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/healing_runestone_2.json b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_2.json new file mode 100644 index 00000000..d53d274d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_2.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_healing_0", + "rune": "ebwizardry:blocks/runestone_healing_2", + "overlay": "ebwizardry:blocks/runestone_healing_2_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/healing_runestone_3.json b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_3.json new file mode 100644 index 00000000..072acd5d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_3.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_healing_0", + "rune": "ebwizardry:blocks/runestone_healing_3", + "overlay": "ebwizardry:blocks/runestone_healing_3_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/healing_runestone_4.json b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_4.json new file mode 100644 index 00000000..c4c5c93e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_4.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_healing_0", + "rune": "ebwizardry:blocks/runestone_healing_4", + "overlay": "ebwizardry:blocks/runestone_healing_4_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/healing_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_pedestal.json new file mode 100644 index 00000000..ae6c6622 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/healing_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:block/runestone_pedestal", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_healing", + "top": "ebwizardry:blocks/runestone_healing_0", + "bottom": "ebwizardry:blocks/runestone_healing_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_healing_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/ice_crystal_block.json b/src/main/resources/assets/ebwizardry/models/block/ice_crystal_block.json new file mode 100644 index 00000000..d9a986c8 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/ice_crystal_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/crystal_block_ice" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/ice_runestone_1.json b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_1.json new file mode 100644 index 00000000..29ad56da --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_1.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_ice_0", + "rune": "ebwizardry:blocks/runestone_ice_1", + "overlay": "ebwizardry:blocks/runestone_ice_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/ice_runestone_2.json b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_2.json new file mode 100644 index 00000000..238ba14b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_2.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_ice_0", + "rune": "ebwizardry:blocks/runestone_ice_2", + "overlay": "ebwizardry:blocks/runestone_ice_2_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/ice_runestone_3.json b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_3.json new file mode 100644 index 00000000..08b19d15 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_3.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_ice_0", + "rune": "ebwizardry:blocks/runestone_ice_3", + "overlay": "ebwizardry:blocks/runestone_ice_3_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/ice_runestone_4.json b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_4.json new file mode 100644 index 00000000..657dbaa1 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_4.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_ice_0", + "rune": "ebwizardry:blocks/runestone_ice_4", + "overlay": "ebwizardry:blocks/runestone_ice_4_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/ice_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_pedestal.json new file mode 100644 index 00000000..b627123b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/ice_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:block/runestone_pedestal", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_ice", + "top": "ebwizardry:blocks/runestone_ice_0", + "bottom": "ebwizardry:blocks/runestone_ice_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_ice_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/lightning_crystal_block.json b/src/main/resources/assets/ebwizardry/models/block/lightning_crystal_block.json new file mode 100644 index 00000000..b9dd389e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/lightning_crystal_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/crystal_block_lightning" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_1.json b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_1.json new file mode 100644 index 00000000..3773208b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_1.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_lightning_0", + "rune": "ebwizardry:blocks/runestone_lightning_1", + "overlay": "ebwizardry:blocks/runestone_lightning_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_2.json b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_2.json new file mode 100644 index 00000000..2e461a41 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_2.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_lightning_0", + "rune": "ebwizardry:blocks/runestone_lightning_2", + "overlay": "ebwizardry:blocks/runestone_lightning_2_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_3.json b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_3.json new file mode 100644 index 00000000..1db68f01 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_3.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_lightning_0", + "rune": "ebwizardry:blocks/runestone_lightning_3", + "overlay": "ebwizardry:blocks/runestone_lightning_3_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_4.json b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_4.json new file mode 100644 index 00000000..e4cca3cc --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_4.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_lightning_0", + "rune": "ebwizardry:blocks/runestone_lightning_4", + "overlay": "ebwizardry:blocks/runestone_lightning_4_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_pedestal.json new file mode 100644 index 00000000..212353ee --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/lightning_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:block/runestone_pedestal", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_lightning", + "top": "ebwizardry:blocks/runestone_lightning_0", + "bottom": "ebwizardry:blocks/runestone_lightning_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_lightning_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/crystal_block.json b/src/main/resources/assets/ebwizardry/models/block/magic_crystal_block.json similarity index 100% rename from src/main/resources/assets/ebwizardry/models/block/crystal_block.json rename to src/main/resources/assets/ebwizardry/models/block/magic_crystal_block.json diff --git a/src/main/resources/assets/ebwizardry/models/block/necromancy_crystal_block.json b/src/main/resources/assets/ebwizardry/models/block/necromancy_crystal_block.json new file mode 100644 index 00000000..52268c00 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/necromancy_crystal_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/crystal_block_necromancy" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_1.json b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_1.json new file mode 100644 index 00000000..9d9bf318 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_1.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_necromancy_0", + "rune": "ebwizardry:blocks/runestone_necromancy_1", + "overlay": "ebwizardry:blocks/runestone_necromancy_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_2.json b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_2.json new file mode 100644 index 00000000..8004eac5 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_2.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_necromancy_0", + "rune": "ebwizardry:blocks/runestone_necromancy_2", + "overlay": "ebwizardry:blocks/runestone_necromancy_2_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_3.json b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_3.json new file mode 100644 index 00000000..0eea58e9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_3.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_necromancy_0", + "rune": "ebwizardry:blocks/runestone_necromancy_3", + "overlay": "ebwizardry:blocks/runestone_necromancy_3_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_4.json b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_4.json new file mode 100644 index 00000000..4a83a330 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_4.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_necromancy_0", + "rune": "ebwizardry:blocks/runestone_necromancy_4", + "overlay": "ebwizardry:blocks/runestone_necromancy_4_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_pedestal.json new file mode 100644 index 00000000..a787cd59 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/necromancy_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:block/runestone_pedestal", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_necromancy", + "top": "ebwizardry:blocks/runestone_necromancy_0", + "bottom": "ebwizardry:blocks/runestone_necromancy_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_necromancy_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_0.json b/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_0.json new file mode 100644 index 00000000..d353e00c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_0.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/obsidian_crust_0" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_1.json b/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_1.json new file mode 100644 index 00000000..a18b3ea2 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_1.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/obsidian_crust_1" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_2.json b/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_2.json new file mode 100644 index 00000000..b29fb73b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_2.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/obsidian_crust_2" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_3.json b/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_3.json new file mode 100644 index 00000000..a25d73bd --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/obsidian_crust_3.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/obsidian_crust_3" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/runestone.json b/src/main/resources/assets/ebwizardry/models/block/runestone.json new file mode 100644 index 00000000..ed3e9fa6 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/runestone.json @@ -0,0 +1,27 @@ +{ + "parent": "block/block", + "textures": { + "particle": "#rune" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#rune", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "east" } + } + }, + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "north" } + } + } + ] +} diff --git a/src/main/resources/assets/ebwizardry/models/block/runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/block/runestone_pedestal.json new file mode 100644 index 00000000..63677186 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/runestone_pedestal.json @@ -0,0 +1,30 @@ +{ + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "east" } + } + }, + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "east" } + } + } + ] +} diff --git a/src/main/resources/assets/ebwizardry/models/block/sorcery_crystal_block.json b/src/main/resources/assets/ebwizardry/models/block/sorcery_crystal_block.json new file mode 100644 index 00000000..2c775847 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/sorcery_crystal_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ebwizardry:blocks/crystal_block_sorcery" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_1.json b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_1.json new file mode 100644 index 00000000..75c4f206 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_1.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_sorcery_0", + "rune": "ebwizardry:blocks/runestone_sorcery_1", + "overlay": "ebwizardry:blocks/runestone_sorcery_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_2.json b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_2.json new file mode 100644 index 00000000..a8d1eb5a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_2.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_sorcery_0", + "rune": "ebwizardry:blocks/runestone_sorcery_2", + "overlay": "ebwizardry:blocks/runestone_sorcery_2_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_3.json b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_3.json new file mode 100644 index 00000000..f280d0e4 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_3.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_sorcery_0", + "rune": "ebwizardry:blocks/runestone_sorcery_3", + "overlay": "ebwizardry:blocks/runestone_sorcery_3_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_4.json b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_4.json new file mode 100644 index 00000000..37cc5471 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_4.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:block/runestone", + "textures": { + "side": "ebwizardry:blocks/runestone_sorcery_0", + "rune": "ebwizardry:blocks/runestone_sorcery_4", + "overlay": "ebwizardry:blocks/runestone_sorcery_4_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_pedestal.json new file mode 100644 index 00000000..05fa63dc --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/sorcery_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:block/runestone_pedestal", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_sorcery", + "top": "ebwizardry:blocks/runestone_sorcery_0", + "bottom": "ebwizardry:blocks/runestone_sorcery_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_sorcery_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_lower_0.json b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_0.json new file mode 100644 index 00000000..78a4386f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_0.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_lower_0" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_lower_1.json b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_1.json new file mode 100644 index 00000000..70929b50 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_1.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_lower_1" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_lower_2.json b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_2.json new file mode 100644 index 00000000..09671006 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_2.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_lower_2" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_lower_3.json b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_3.json new file mode 100644 index 00000000..9ad8e92d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_3.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_lower_3" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_lower_4.json b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_4.json new file mode 100644 index 00000000..00234c0d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_4.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_lower_4" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_lower_5.json b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_5.json new file mode 100644 index 00000000..3697dbd0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_5.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_lower_5" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_lower_6.json b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_6.json new file mode 100644 index 00000000..8bf7cd08 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_6.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_lower_6" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_lower_7.json b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_7.json new file mode 100644 index 00000000..558dfa08 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_lower_7.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_lower_7" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_upper_0.json b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_0.json new file mode 100644 index 00000000..8a652816 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_0.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_upper_0" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_upper_1.json b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_1.json new file mode 100644 index 00000000..b7d8b60f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_1.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_upper_1" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_upper_2.json b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_2.json new file mode 100644 index 00000000..aef33fc7 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_2.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_upper_2" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_upper_3.json b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_3.json new file mode 100644 index 00000000..795e030d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_3.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_upper_3" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_upper_4.json b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_4.json new file mode 100644 index 00000000..47360602 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_4.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_upper_4" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_upper_5.json b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_5.json new file mode 100644 index 00000000..78b61bd2 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_5.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_upper_5" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_upper_6.json b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_6.json new file mode 100644 index 00000000..ffc50f97 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_6.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_upper_6" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/block/thorns_upper_7.json b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_7.json new file mode 100644 index 00000000..c1cf103f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/block/thorns_upper_7.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cross", + "textures": { + "cross": "ebwizardry:blocks/thorns_upper_7" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_anchoring.json b/src/main/resources/assets/ebwizardry/models/item/amulet_anchoring.json new file mode 100644 index 00000000..9414c2cb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_anchoring.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_anchoring" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_arcane_defence.json b/src/main/resources/assets/ebwizardry/models/item/amulet_arcane_defence.json new file mode 100644 index 00000000..fd13bda3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_arcane_defence.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_arcane_defence" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_auto_shield.json b/src/main/resources/assets/ebwizardry/models/item/amulet_auto_shield.json new file mode 100644 index 00000000..e587e072 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_auto_shield.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_auto_shield" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_banishing.json b/src/main/resources/assets/ebwizardry/models/item/amulet_banishing.json new file mode 100644 index 00000000..d79c9040 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_banishing.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_banishing" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_channeling.json b/src/main/resources/assets/ebwizardry/models/item/amulet_channeling.json new file mode 100644 index 00000000..a1e52aa6 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_channeling.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_channeling" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_fire_cloaking.json b/src/main/resources/assets/ebwizardry/models/item/amulet_fire_cloaking.json new file mode 100644 index 00000000..a08ebc3a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_fire_cloaking.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_fire_cloaking" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_fire_protection.json b/src/main/resources/assets/ebwizardry/models/item/amulet_fire_protection.json new file mode 100644 index 00000000..cea2dd3c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_fire_protection.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_fire_protection" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_glide.json b/src/main/resources/assets/ebwizardry/models/item/amulet_glide.json new file mode 100644 index 00000000..7ffa1018 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_glide.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_glide" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_ice_immunity.json b/src/main/resources/assets/ebwizardry/models/item/amulet_ice_immunity.json new file mode 100644 index 00000000..e0794036 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_ice_immunity.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_ice_immunity" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_ice_protection.json b/src/main/resources/assets/ebwizardry/models/item/amulet_ice_protection.json new file mode 100644 index 00000000..d18a09cd --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_ice_protection.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_ice_protection" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_lich.json b/src/main/resources/assets/ebwizardry/models/item/amulet_lich.json new file mode 100644 index 00000000..79c28033 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_lich.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_lich" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_potential.json b/src/main/resources/assets/ebwizardry/models/item/amulet_potential.json new file mode 100644 index 00000000..1d0e2976 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_potential.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_potential" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_recovery.json b/src/main/resources/assets/ebwizardry/models/item/amulet_recovery.json new file mode 100644 index 00000000..dd9d0739 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_recovery.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_recovery" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_resurrection.json b/src/main/resources/assets/ebwizardry/models/item/amulet_resurrection.json new file mode 100644 index 00000000..4191270c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_resurrection.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_resurrection" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_transience.json b/src/main/resources/assets/ebwizardry/models/item/amulet_transience.json new file mode 100644 index 00000000..116b66ff --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_transience.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_transience" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_warding.json b/src/main/resources/assets/ebwizardry/models/item/amulet_warding.json new file mode 100644 index 00000000..88587ffd --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_warding.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_warding" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_wisdom.json b/src/main/resources/assets/ebwizardry/models/item/amulet_wisdom.json new file mode 100644 index 00000000..290e0231 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_wisdom.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_wisdom" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/amulet_wither_immunity.json b/src/main/resources/assets/ebwizardry/models/item/amulet_wither_immunity.json new file mode 100644 index 00000000..71c142fa --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/amulet_wither_immunity.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/amulet_wither_immunity" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/astral_diamond.json b/src/main/resources/assets/ebwizardry/models/item/astral_diamond.json new file mode 100644 index 00000000..c5f31ce7 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/astral_diamond.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/astral_diamond" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/basic_lightning_wand.json b/src/main/resources/assets/ebwizardry/models/item/basic_lightning_wand.json deleted file mode 100644 index b65b8970..00000000 --- a/src/main/resources/assets/ebwizardry/models/item/basic_lightning_wand.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/handheld", - "textures": { - "layer0": "ebwizardry:items/wand_basic_lightning" - } -} diff --git a/src/main/resources/assets/ebwizardry/models/item/basic_necromancy_wand.json b/src/main/resources/assets/ebwizardry/models/item/basic_necromancy_wand.json deleted file mode 100644 index 6af0d640..00000000 --- a/src/main/resources/assets/ebwizardry/models/item/basic_necromancy_wand.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/handheld", - "textures": { - "layer0": "ebwizardry:items/wand_basic_necromancy" - } -} diff --git a/src/main/resources/assets/ebwizardry/models/item/basic_sorcery_wand.json b/src/main/resources/assets/ebwizardry/models/item/basic_sorcery_wand.json deleted file mode 100644 index c46f8182..00000000 --- a/src/main/resources/assets/ebwizardry/models/item/basic_sorcery_wand.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/handheld", - "textures": { - "layer0": "ebwizardry:items/wand_basic_sorcery" - } -} diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_abseiling.json b/src/main/resources/assets/ebwizardry/models/item/charm_abseiling.json new file mode 100644 index 00000000..d8981e3b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_abseiling.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_abseiling" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_auto_smelt.json b/src/main/resources/assets/ebwizardry/models/item/charm_auto_smelt.json new file mode 100644 index 00000000..e1463ad7 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_auto_smelt.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_auto_smelt" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_experience_tome.json b/src/main/resources/assets/ebwizardry/models/item/charm_experience_tome.json new file mode 100644 index 00000000..c4a13245 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_experience_tome.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_experience_tome" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_feeding.json b/src/main/resources/assets/ebwizardry/models/item/charm_feeding.json new file mode 100644 index 00000000..a44e41bb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_feeding.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_feeding" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_flight.json b/src/main/resources/assets/ebwizardry/models/item/charm_flight.json new file mode 100644 index 00000000..3afe790e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_flight.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_flight" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_growth.json b/src/main/resources/assets/ebwizardry/models/item/charm_growth.json new file mode 100644 index 00000000..8538a441 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_growth.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_growth" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_haggler.json b/src/main/resources/assets/ebwizardry/models/item/charm_haggler.json new file mode 100644 index 00000000..351127fa --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_haggler.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_haggler" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_lava_walking.json b/src/main/resources/assets/ebwizardry/models/item/charm_lava_walking.json new file mode 100644 index 00000000..380c928b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_lava_walking.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_lava_walking" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_light.json b/src/main/resources/assets/ebwizardry/models/item/charm_light.json new file mode 100644 index 00000000..a26d6b90 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_light.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_light" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_minion_health.json b/src/main/resources/assets/ebwizardry/models/item/charm_minion_health.json new file mode 100644 index 00000000..ae89ce50 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_minion_health.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_minion_health" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_minion_variants.json b/src/main/resources/assets/ebwizardry/models/item/charm_minion_variants.json new file mode 100644 index 00000000..0ad912bd --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_minion_variants.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_minion_variants" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_silk_touch.json b/src/main/resources/assets/ebwizardry/models/item/charm_silk_touch.json new file mode 100644 index 00000000..0461fcb6 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_silk_touch.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_silk_touch" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_stop_time.json b/src/main/resources/assets/ebwizardry/models/item/charm_stop_time.json new file mode 100644 index 00000000..5f518c1d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_stop_time.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_stop_time" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_storm.json b/src/main/resources/assets/ebwizardry/models/item/charm_storm.json new file mode 100644 index 00000000..3132cab8 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_storm.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_storm" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/charm_transportation.json b/src/main/resources/assets/ebwizardry/models/item/charm_transportation.json new file mode 100644 index 00000000..71c0e708 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/charm_transportation.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/charm_transportation" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/crystal_block.json deleted file mode 100644 index 0070e57f..00000000 --- a/src/main/resources/assets/ebwizardry/models/item/crystal_block.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "ebwizardry:block/crystal_block" -} diff --git a/src/main/resources/assets/ebwizardry/models/item/magic_crystal.json b/src/main/resources/assets/ebwizardry/models/item/crystal_earth.json similarity index 53% rename from src/main/resources/assets/ebwizardry/models/item/magic_crystal.json rename to src/main/resources/assets/ebwizardry/models/item/crystal_earth.json index 9e2e4903..723d42e0 100644 --- a/src/main/resources/assets/ebwizardry/models/item/magic_crystal.json +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_earth.json @@ -1,6 +1,6 @@ { "parent": "item/generated", "textures": { - "layer0": "ebwizardry:items/magic_crystal" + "layer0": "ebwizardry:items/crystal_earth" } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_fire.json b/src/main/resources/assets/ebwizardry/models/item/crystal_fire.json new file mode 100644 index 00000000..573dfe03 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_fire.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_fire" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_healing.json b/src/main/resources/assets/ebwizardry/models/item/crystal_healing.json new file mode 100644 index 00000000..d91d3939 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_healing.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_healing" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_ice.json b/src/main/resources/assets/ebwizardry/models/item/crystal_ice.json new file mode 100644 index 00000000..c879ac46 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_ice.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_ice" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_lightning.json b/src/main/resources/assets/ebwizardry/models/item/crystal_lightning.json new file mode 100644 index 00000000..1c09de74 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_lightning.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_lightning" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_magic.json b/src/main/resources/assets/ebwizardry/models/item/crystal_magic.json new file mode 100644 index 00000000..23f6c4c2 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_magic.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_magic" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_necromancy.json b/src/main/resources/assets/ebwizardry/models/item/crystal_necromancy.json new file mode 100644 index 00000000..bd3310a9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_necromancy.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_necromancy" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_shard.json b/src/main/resources/assets/ebwizardry/models/item/crystal_shard.json new file mode 100644 index 00000000..b0cd0f4d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_shard.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_shard" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/crystal_sorcery.json b/src/main/resources/assets/ebwizardry/models/item/crystal_sorcery.json new file mode 100644 index 00000000..0291367b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/crystal_sorcery.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_sorcery" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/earth_crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/earth_crystal_block.json new file mode 100644 index 00000000..dcdb4abd --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/earth_crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "ebwizardry:block/earth_crystal_block" +} diff --git a/src/main/resources/assets/ebwizardry/models/item/earth_runestone.json b/src/main/resources/assets/ebwizardry/models/item/earth_runestone.json new file mode 100644 index 00000000..cd9da38a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/earth_runestone.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:item/runestone_item", + "textures": { + "side": "ebwizardry:blocks/runestone_earth_0", + "rune": "ebwizardry:blocks/runestone_earth_1", + "overlay": "ebwizardry:blocks/runestone_earth_1_overlay" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/earth_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/item/earth_runestone_pedestal.json new file mode 100644 index 00000000..a63834d2 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/earth_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:item/runestone_pedestal_item", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_earth", + "top": "ebwizardry:blocks/runestone_earth_0", + "bottom": "ebwizardry:blocks/runestone_earth_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_earth_overlay" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/fire_crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/fire_crystal_block.json new file mode 100644 index 00000000..d3b21460 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/fire_crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "ebwizardry:block/fire_crystal_block" +} diff --git a/src/main/resources/assets/ebwizardry/models/item/fire_runestone.json b/src/main/resources/assets/ebwizardry/models/item/fire_runestone.json new file mode 100644 index 00000000..9d526484 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/fire_runestone.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:item/runestone_item", + "textures": { + "side": "ebwizardry:blocks/runestone_fire_0", + "rune": "ebwizardry:blocks/runestone_fire_1", + "overlay": "ebwizardry:blocks/runestone_fire_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/fire_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/item/fire_runestone_pedestal.json new file mode 100644 index 00000000..e82c1691 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/fire_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:item/runestone_pedestal_item", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_fire", + "top": "ebwizardry:blocks/runestone_fire_0", + "bottom": "ebwizardry:blocks/runestone_fire_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_fire_overlay" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe.json index d2893024..8275b14c 100644 --- a/src/main/resources/assets/ebwizardry/models/item/flaming_axe.json +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe.json @@ -2,5 +2,62 @@ "parent": "item/handheld", "textures": { "layer0": "ebwizardry:items/flaming_axe" - } + }, + "overrides": [ + { + "predicate": { + "conjuring": 1 + }, + "model": "ebwizardry:item/flaming_axe_conjuring_0" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.125 + }, + "model": "ebwizardry:item/flaming_axe_conjuring_1" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.25 + }, + "model": "ebwizardry:item/flaming_axe_conjuring_2" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.375 + }, + "model": "ebwizardry:item/flaming_axe_conjuring_3" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.5 + }, + "model": "ebwizardry:item/flaming_axe_conjuring_4" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.625 + }, + "model": "ebwizardry:item/flaming_axe_conjuring_5" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.75 + }, + "model": "ebwizardry:item/flaming_axe_conjuring_6" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.875 + }, + "model": "ebwizardry:item/flaming_axe_conjuring_7" + } + ] } diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_0.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_0.json new file mode 100644 index 00000000..6465ed5b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_0.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/flaming_axe_conjuring_0" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_1.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_1.json new file mode 100644 index 00000000..9b42df9a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_1.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/flaming_axe_conjuring_1" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_2.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_2.json new file mode 100644 index 00000000..5a5e5692 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/flaming_axe_conjuring_2" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_3.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_3.json new file mode 100644 index 00000000..bec94f1b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_3.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/flaming_axe_conjuring_3" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_4.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_4.json new file mode 100644 index 00000000..e0951dad --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_4.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/flaming_axe_conjuring_4" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_5.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_5.json new file mode 100644 index 00000000..d9c99c9e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_5.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/flaming_axe_conjuring_5" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_6.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_6.json new file mode 100644 index 00000000..47959abb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_6.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/flaming_axe_conjuring_6" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_7.json b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_7.json new file mode 100644 index 00000000..76d698cb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/flaming_axe_conjuring_7.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/flaming_axe_conjuring_7" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe.json index 198a09db..57a68827 100644 --- a/src/main/resources/assets/ebwizardry/models/item/frost_axe.json +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe.json @@ -2,5 +2,62 @@ "parent": "item/handheld", "textures": { "layer0": "ebwizardry:items/frost_axe" - } + }, + "overrides": [ + { + "predicate": { + "conjuring": 1 + }, + "model": "ebwizardry:item/frost_axe_conjuring_0" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.125 + }, + "model": "ebwizardry:item/frost_axe_conjuring_1" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.25 + }, + "model": "ebwizardry:item/frost_axe_conjuring_2" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.375 + }, + "model": "ebwizardry:item/frost_axe_conjuring_3" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.5 + }, + "model": "ebwizardry:item/frost_axe_conjuring_4" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.625 + }, + "model": "ebwizardry:item/frost_axe_conjuring_5" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.75 + }, + "model": "ebwizardry:item/frost_axe_conjuring_6" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.875 + }, + "model": "ebwizardry:item/frost_axe_conjuring_7" + } + ] } diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_0.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_0.json new file mode 100644 index 00000000..d72f22b9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_0.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/frost_axe_conjuring_0" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_1.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_1.json new file mode 100644 index 00000000..39af7f39 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_1.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/frost_axe_conjuring_1" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_2.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_2.json new file mode 100644 index 00000000..bed93962 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/frost_axe_conjuring_2" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_3.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_3.json new file mode 100644 index 00000000..1d1f7838 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_3.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/frost_axe_conjuring_3" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_4.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_4.json new file mode 100644 index 00000000..fb7d4fd3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_4.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/frost_axe_conjuring_4" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_5.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_5.json new file mode 100644 index 00000000..6f34b837 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_5.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/frost_axe_conjuring_5" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_6.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_6.json new file mode 100644 index 00000000..6eeac463 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_6.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/frost_axe_conjuring_6" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_7.json b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_7.json new file mode 100644 index 00000000..33bc3775 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/frost_axe_conjuring_7.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/frost_axe_conjuring_7" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/grand_crystal.json b/src/main/resources/assets/ebwizardry/models/item/grand_crystal.json new file mode 100644 index 00000000..c58097d9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/grand_crystal.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/crystal_grand" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/healing_crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/healing_crystal_block.json new file mode 100644 index 00000000..2932f2ad --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/healing_crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "ebwizardry:block/healing_crystal_block" +} diff --git a/src/main/resources/assets/ebwizardry/models/item/healing_runestone.json b/src/main/resources/assets/ebwizardry/models/item/healing_runestone.json new file mode 100644 index 00000000..c583f383 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/healing_runestone.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:item/runestone_item", + "textures": { + "side": "ebwizardry:blocks/runestone_healing_0", + "rune": "ebwizardry:blocks/runestone_healing_1", + "overlay": "ebwizardry:blocks/runestone_healing_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/healing_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/item/healing_runestone_pedestal.json new file mode 100644 index 00000000..7089d574 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/healing_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:item/runestone_pedestal_item", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_healing", + "top": "ebwizardry:blocks/runestone_healing_0", + "bottom": "ebwizardry:blocks/runestone_healing_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_healing_overlay" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ice_crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/ice_crystal_block.json new file mode 100644 index 00000000..f2bf82fd --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ice_crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "ebwizardry:block/ice_crystal_block" +} diff --git a/src/main/resources/assets/ebwizardry/models/item/ice_runestone.json b/src/main/resources/assets/ebwizardry/models/item/ice_runestone.json new file mode 100644 index 00000000..f3313d51 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ice_runestone.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:item/runestone_item", + "textures": { + "side": "ebwizardry:blocks/runestone_ice_0", + "rune": "ebwizardry:blocks/runestone_ice_1", + "overlay": "ebwizardry:blocks/runestone_ice_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/ice_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/item/ice_runestone_pedestal.json new file mode 100644 index 00000000..e90ed3eb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ice_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:item/runestone_pedestal_item", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_ice", + "top": "ebwizardry:blocks/runestone_ice_0", + "bottom": "ebwizardry:blocks/runestone_ice_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_ice_overlay" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/large_mana_flask.json b/src/main/resources/assets/ebwizardry/models/item/large_mana_flask.json new file mode 100644 index 00000000..be926384 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/large_mana_flask.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/mana_flask_large" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/lightning_crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/lightning_crystal_block.json new file mode 100644 index 00000000..5b306ff5 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/lightning_crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "ebwizardry:block/lightning_crystal_block" +} diff --git a/src/main/resources/assets/ebwizardry/models/item/lightning_hammer.json b/src/main/resources/assets/ebwizardry/models/item/lightning_hammer.json new file mode 100644 index 00000000..6019ecf1 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/lightning_hammer.json @@ -0,0 +1,122 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "ebwizardry:entity/lightning_hammer", + "particle": "ebwizardry:entity/lightning_hammer" + }, + "elements": [ + { + "name": "hammer_head", + "from": [-2, 1, 2], + "to": [18, 13, 14], + "faces": { + "north": {"uv": [3, 3, 8, 6], "texture": "#0"}, + "east": {"uv": [0, 3, 3, 6], "texture": "#0"}, + "south": {"uv": [11, 3, 16, 6], "texture": "#0"}, + "west": {"uv": [8, 3, 11, 6], "texture": "#0"}, + "up": {"uv": [3, 0, 8, 3], "texture": "#0"}, + "down": {"uv": [8, 0, 13, 3], "texture": "#0"} + } + }, + { + "name": "handle", + "from": [6, 13, 6], + "to": [10, 27, 10], + "faces": { + "north": {"uv": [1, 7, 2, 10.5], "texture": "#0"}, + "east": {"uv": [0, 7, 1, 10.5], "texture": "#0"}, + "south": {"uv": [3, 7, 4, 10.5], "texture": "#0"}, + "west": {"uv": [2, 7, 3, 10.5], "texture": "#0"}, + "up": {"uv": [1, 6, 2, 7], "texture": "#0"}, + "down": {"uv": [2, 6, 3, 7], "texture": "#0"} + } + }, + { + "name": "handle_end", + "from": [5.5, 27, 5.5], + "to": [10.5, 32, 10.5], + "faces": { + "north": {"uv": [1.25, 13.5, 2.5, 14.75], "texture": "#0"}, + "east": {"uv": [0, 13.5, 1.25, 14.75], "texture": "#0"}, + "south": {"uv": [3.75, 13.5, 5, 14.75], "texture": "#0"}, + "west": {"uv": [2.5, 13.5, 3.75, 14.75], "texture": "#0"}, + "up": {"uv": [1.25, 12.25, 2.5, 13.5], "texture": "#0"}, + "down": {"uv": [2.5, 12.25, 3.75, 13.5], "texture": "#0"} + } + }, + { + "name": "handle_base", + "from": [5.5, 13, 5.5], + "to": [10.5, 15, 10.5], + "faces": { + "north": {"uv": [1.25, 11.75, 2.5, 12.25], "texture": "#0"}, + "east": {"uv": [0, 11.75, 1.25, 12.25], "texture": "#0"}, + "south": {"uv": [3.75, 11.75, 5, 12.25], "texture": "#0"}, + "west": {"uv": [2.5, 11.75, 3.75, 12.25], "texture": "#0"}, + "up": {"uv": [1.25, 10.5, 2.5, 11.75], "texture": "#0"}, + "down": {"uv": [2.5, 10.5, 3.75, 11.75], "texture": "#0"} + } + }, + { + "name": "ring1", + "from": [0, 0, 1], + "to": [2, 14, 15], + "faces": { + "north": {"uv": [8.5, 9.5, 9, 13], "texture": "#0"}, + "east": {"uv": [5, 9.5, 8.5, 13], "texture": "#0"}, + "south": {"uv": [12.5, 9.5, 13, 13], "texture": "#0"}, + "west": {"uv": [9, 9.5, 12.5, 13], "texture": "#0"}, + "up": {"uv": [8.5, 6, 9, 9.5], "texture": "#0"}, + "down": {"uv": [9, 6, 9.5, 9.5], "texture": "#0"} + } + }, + { + "name": "ring2", + "from": [14, 0, 1], + "to": [16, 14, 15], + "faces": { + "north": {"uv": [8.5, 9.5, 9, 13], "texture": "#0"}, + "east": {"uv": [5, 9.5, 8.5, 13], "texture": "#0"}, + "south": {"uv": [12.5, 9.5, 13, 13], "texture": "#0"}, + "west": {"uv": [9, 9.5, 12.5, 13], "texture": "#0"}, + "up": {"uv": [8.5, 6, 9, 9.5], "texture": "#0"}, + "down": {"uv": [9, 6, 9.5, 9.5], "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [90, 90, 90], + "translation": [0, 10, 2], + "scale": [0.75, 0.75, 0.75] + }, + "thirdperson_lefthand": { + "rotation": [90, 90, 90], + "translation": [0.1, 10, 2], + "scale": [0.75, 0.75, 0.75] + }, + "firstperson_righthand": { + "rotation": [90, 90, 90], + "translation": [0.1, 10, 2], + "scale": [0.75, 0.75, 0.75] + }, + "firstperson_lefthand": { + "rotation": [90, 90, 90], + "translation": [0, 10, 2], + "scale": [0.75, 0.75, 0.75] + }, + "ground": { + "scale": [0.75, 0.75, 0.75] + }, + "gui": { + "rotation": [0, -26, 135], + "translation": [1, 1.5, 0], + "scale": [0.45, 0.45, 0.45] + }, + "fixed": { + "rotation": [0, 0, -135], + "translation": [-2, 2, 0], + "scale": [0.6, 0.6, 0.6] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/lightning_runestone.json b/src/main/resources/assets/ebwizardry/models/item/lightning_runestone.json new file mode 100644 index 00000000..abdb1136 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/lightning_runestone.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:item/runestone_item", + "textures": { + "side": "ebwizardry:blocks/runestone_lightning_0", + "rune": "ebwizardry:blocks/runestone_lightning_1", + "overlay": "ebwizardry:blocks/runestone_lightning_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/lightning_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/item/lightning_runestone_pedestal.json new file mode 100644 index 00000000..bd76dcda --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/lightning_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:item/runestone_pedestal_item", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_lightning", + "top": "ebwizardry:blocks/runestone_lightning_0", + "bottom": "ebwizardry:blocks/runestone_lightning_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_lightning_overlay" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/magic_crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/magic_crystal_block.json new file mode 100644 index 00000000..d01cb6d3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/magic_crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "ebwizardry:block/magic_crystal_block" +} diff --git a/src/main/resources/assets/ebwizardry/models/item/magic_wand.json b/src/main/resources/assets/ebwizardry/models/item/magic_wand.json index 661d9e14..59387cf7 100644 --- a/src/main/resources/assets/ebwizardry/models/item/magic_wand.json +++ b/src/main/resources/assets/ebwizardry/models/item/magic_wand.json @@ -1,6 +1,6 @@ { "parent": "item/handheld", "textures": { - "layer0": "ebwizardry:items/wand_basic" + "layer0": "ebwizardry:items/wand_novice" } } diff --git a/src/main/resources/assets/ebwizardry/models/item/medium_mana_flask.json b/src/main/resources/assets/ebwizardry/models/item/medium_mana_flask.json new file mode 100644 index 00000000..6bda3fba --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/medium_mana_flask.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/mana_flask_medium" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/melee_upgrade.json b/src/main/resources/assets/ebwizardry/models/item/melee_upgrade.json new file mode 100644 index 00000000..1aa6fd77 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/melee_upgrade.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/upgrade_melee" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/necromancy_crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/necromancy_crystal_block.json new file mode 100644 index 00000000..b0c03762 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/necromancy_crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "ebwizardry:block/necromancy_crystal_block" +} diff --git a/src/main/resources/assets/ebwizardry/models/item/necromancy_runestone.json b/src/main/resources/assets/ebwizardry/models/item/necromancy_runestone.json new file mode 100644 index 00000000..48e70eb4 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/necromancy_runestone.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:item/runestone_item", + "textures": { + "side": "ebwizardry:blocks/runestone_necromancy_0", + "rune": "ebwizardry:blocks/runestone_necromancy_1", + "overlay": "ebwizardry:blocks/runestone_necromancy_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/necromancy_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/item/necromancy_runestone_pedestal.json new file mode 100644 index 00000000..9c980c83 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/necromancy_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:item/runestone_pedestal_item", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_necromancy", + "top": "ebwizardry:blocks/runestone_necromancy_0", + "bottom": "ebwizardry:blocks/runestone_necromancy_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_necromancy_overlay" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/basic_fire_wand.json b/src/main/resources/assets/ebwizardry/models/item/novice_earth_wand.json similarity index 51% rename from src/main/resources/assets/ebwizardry/models/item/basic_fire_wand.json rename to src/main/resources/assets/ebwizardry/models/item/novice_earth_wand.json index 3a01a02e..7431443b 100644 --- a/src/main/resources/assets/ebwizardry/models/item/basic_fire_wand.json +++ b/src/main/resources/assets/ebwizardry/models/item/novice_earth_wand.json @@ -1,6 +1,6 @@ { "parent": "item/handheld", "textures": { - "layer0": "ebwizardry:items/wand_basic_fire" + "layer0": "ebwizardry:items/wand_novice_earth" } } diff --git a/src/main/resources/assets/ebwizardry/models/item/basic_earth_wand.json b/src/main/resources/assets/ebwizardry/models/item/novice_fire_wand.json similarity index 52% rename from src/main/resources/assets/ebwizardry/models/item/basic_earth_wand.json rename to src/main/resources/assets/ebwizardry/models/item/novice_fire_wand.json index abf377f1..27055741 100644 --- a/src/main/resources/assets/ebwizardry/models/item/basic_earth_wand.json +++ b/src/main/resources/assets/ebwizardry/models/item/novice_fire_wand.json @@ -1,6 +1,6 @@ { "parent": "item/handheld", "textures": { - "layer0": "ebwizardry:items/wand_basic_earth" + "layer0": "ebwizardry:items/wand_novice_fire" } } diff --git a/src/main/resources/assets/ebwizardry/models/item/basic_healing_wand.json b/src/main/resources/assets/ebwizardry/models/item/novice_healing_wand.json similarity index 50% rename from src/main/resources/assets/ebwizardry/models/item/basic_healing_wand.json rename to src/main/resources/assets/ebwizardry/models/item/novice_healing_wand.json index 2dcb118d..e9095bf3 100644 --- a/src/main/resources/assets/ebwizardry/models/item/basic_healing_wand.json +++ b/src/main/resources/assets/ebwizardry/models/item/novice_healing_wand.json @@ -1,6 +1,6 @@ { "parent": "item/handheld", "textures": { - "layer0": "ebwizardry:items/wand_basic_healing" + "layer0": "ebwizardry:items/wand_novice_healing" } } diff --git a/src/main/resources/assets/ebwizardry/models/item/basic_ice_wand.json b/src/main/resources/assets/ebwizardry/models/item/novice_ice_wand.json similarity index 52% rename from src/main/resources/assets/ebwizardry/models/item/basic_ice_wand.json rename to src/main/resources/assets/ebwizardry/models/item/novice_ice_wand.json index 44181bcd..feb24c4c 100644 --- a/src/main/resources/assets/ebwizardry/models/item/basic_ice_wand.json +++ b/src/main/resources/assets/ebwizardry/models/item/novice_ice_wand.json @@ -1,6 +1,6 @@ { "parent": "item/handheld", "textures": { - "layer0": "ebwizardry:items/wand_basic_ice" + "layer0": "ebwizardry:items/wand_novice_ice" } } diff --git a/src/main/resources/assets/ebwizardry/models/item/novice_lightning_wand.json b/src/main/resources/assets/ebwizardry/models/item/novice_lightning_wand.json new file mode 100644 index 00000000..ce044666 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/novice_lightning_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/wand_novice_lightning" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/novice_necromancy_wand.json b/src/main/resources/assets/ebwizardry/models/item/novice_necromancy_wand.json new file mode 100644 index 00000000..ab64fb68 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/novice_necromancy_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/wand_novice_necromancy" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/novice_sorcery_wand.json b/src/main/resources/assets/ebwizardry/models/item/novice_sorcery_wand.json new file mode 100644 index 00000000..968ff38e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/novice_sorcery_wand.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/wand_novice_sorcery" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/purifying_elixir.json b/src/main/resources/assets/ebwizardry/models/item/purifying_elixir.json new file mode 100644 index 00000000..a213668e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/purifying_elixir.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/purifying_elixir" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_arcane_frost.json b/src/main/resources/assets/ebwizardry/models/item/ring_arcane_frost.json new file mode 100644 index 00000000..799e7483 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_arcane_frost.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_arcane_frost" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_battlemage.json b/src/main/resources/assets/ebwizardry/models/item/ring_battlemage.json new file mode 100644 index 00000000..af3c2e35 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_battlemage.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_battlemage" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_blockwrangler.json b/src/main/resources/assets/ebwizardry/models/item/ring_blockwrangler.json new file mode 100644 index 00000000..654f22b7 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_blockwrangler.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_blockwrangler" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_combustion.json b/src/main/resources/assets/ebwizardry/models/item/ring_combustion.json new file mode 100644 index 00000000..55f914e3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_combustion.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_combustion" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_condensing.json b/src/main/resources/assets/ebwizardry/models/item/ring_condensing.json new file mode 100644 index 00000000..442f589d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_condensing.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_condensing" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_conjurer.json b/src/main/resources/assets/ebwizardry/models/item/ring_conjurer.json new file mode 100644 index 00000000..8c8a26f5 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_conjurer.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_conjurer" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_defender.json b/src/main/resources/assets/ebwizardry/models/item/ring_defender.json new file mode 100644 index 00000000..3b5ad34d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_defender.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_defender" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_disintegration.json b/src/main/resources/assets/ebwizardry/models/item/ring_disintegration.json new file mode 100644 index 00000000..e8e3a131 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_disintegration.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_disintegration" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_earth_biome.json b/src/main/resources/assets/ebwizardry/models/item/ring_earth_biome.json new file mode 100644 index 00000000..7f5c46c9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_earth_biome.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_earth_biome" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_earth_melee.json b/src/main/resources/assets/ebwizardry/models/item/ring_earth_melee.json new file mode 100644 index 00000000..19213d66 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_earth_melee.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_earth_melee" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_extraction.json b/src/main/resources/assets/ebwizardry/models/item/ring_extraction.json new file mode 100644 index 00000000..49c344f2 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_extraction.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_extraction" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_fire_biome.json b/src/main/resources/assets/ebwizardry/models/item/ring_fire_biome.json new file mode 100644 index 00000000..fa30a48d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_fire_biome.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_fire_biome" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_fire_melee.json b/src/main/resources/assets/ebwizardry/models/item/ring_fire_melee.json new file mode 100644 index 00000000..4e89c680 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_fire_melee.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_fire_melee" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_full_moon.json b/src/main/resources/assets/ebwizardry/models/item/ring_full_moon.json new file mode 100644 index 00000000..565a90c0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_full_moon.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_full_moon" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_hammer.json b/src/main/resources/assets/ebwizardry/models/item/ring_hammer.json new file mode 100644 index 00000000..ca3a1586 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_hammer.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_hammer" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_ice_biome.json b/src/main/resources/assets/ebwizardry/models/item/ring_ice_biome.json new file mode 100644 index 00000000..821fa0b7 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_ice_biome.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_ice_biome" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_ice_melee.json b/src/main/resources/assets/ebwizardry/models/item/ring_ice_melee.json new file mode 100644 index 00000000..00951549 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_ice_melee.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_ice_melee" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_interdiction.json b/src/main/resources/assets/ebwizardry/models/item/ring_interdiction.json new file mode 100644 index 00000000..d956a49a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_interdiction.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_interdiction" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_leeching.json b/src/main/resources/assets/ebwizardry/models/item/ring_leeching.json new file mode 100644 index 00000000..add07d6e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_leeching.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_leeching" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_lightning_melee.json b/src/main/resources/assets/ebwizardry/models/item/ring_lightning_melee.json new file mode 100644 index 00000000..44b4ba59 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_lightning_melee.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_lightning_melee" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_mana_return.json b/src/main/resources/assets/ebwizardry/models/item/ring_mana_return.json new file mode 100644 index 00000000..07e9de7b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_mana_return.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_mana_return" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_mind_control.json b/src/main/resources/assets/ebwizardry/models/item/ring_mind_control.json new file mode 100644 index 00000000..d9657f06 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_mind_control.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_mind_control" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_necromancy_melee.json b/src/main/resources/assets/ebwizardry/models/item/ring_necromancy_melee.json new file mode 100644 index 00000000..14c32043 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_necromancy_melee.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_necromancy_melee" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_paladin.json b/src/main/resources/assets/ebwizardry/models/item/ring_paladin.json new file mode 100644 index 00000000..b41dc94a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_paladin.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_paladin" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_poison.json b/src/main/resources/assets/ebwizardry/models/item/ring_poison.json new file mode 100644 index 00000000..0273aad5 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_poison.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_poison" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_seeking.json b/src/main/resources/assets/ebwizardry/models/item/ring_seeking.json new file mode 100644 index 00000000..bb5759dc --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_seeking.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_seeking" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_shattering.json b/src/main/resources/assets/ebwizardry/models/item/ring_shattering.json new file mode 100644 index 00000000..509900bc --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_shattering.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_shattering" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_siphoning.json b/src/main/resources/assets/ebwizardry/models/item/ring_siphoning.json new file mode 100644 index 00000000..d94758d9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_siphoning.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_siphoning" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_soulbinding.json b/src/main/resources/assets/ebwizardry/models/item/ring_soulbinding.json new file mode 100644 index 00000000..23e710f4 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_soulbinding.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_soulbinding" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_spirit_animal.json b/src/main/resources/assets/ebwizardry/models/item/ring_spirit_animal.json new file mode 100644 index 00000000..838291be --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_spirit_animal.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_spirit_animal" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/ring_storm.json b/src/main/resources/assets/ebwizardry/models/item/ring_storm.json new file mode 100644 index 00000000..1227579e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/ring_storm.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/ring_storm" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/runestone_item.json b/src/main/resources/assets/ebwizardry/models/item/runestone_item.json new file mode 100644 index 00000000..77b8d431 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/runestone_item.json @@ -0,0 +1,28 @@ +{ + "parent": "block/block", + "textures": { + "particle": "#rune" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#rune", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "east" } + } + }, + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "shade": false, + "faces": { + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "north" } + } + } + ] +} diff --git a/src/main/resources/assets/ebwizardry/models/item/runestone_pedestal_item.json b/src/main/resources/assets/ebwizardry/models/item/runestone_pedestal_item.json new file mode 100644 index 00000000..66455ce8 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/runestone_pedestal_item.json @@ -0,0 +1,31 @@ +{ + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "east" } + } + }, + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "shade": false, + "faces": { + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "cullface": "east" } + } + } + ] +} diff --git a/src/main/resources/assets/ebwizardry/models/item/small_mana_flask.json b/src/main/resources/assets/ebwizardry/models/item/small_mana_flask.json new file mode 100644 index 00000000..8bbca59b --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/small_mana_flask.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:items/mana_flask_small" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/sorcery_crystal_block.json b/src/main/resources/assets/ebwizardry/models/item/sorcery_crystal_block.json new file mode 100644 index 00000000..ecc2f3df --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/sorcery_crystal_block.json @@ -0,0 +1,3 @@ +{ + "parent": "ebwizardry:block/sorcery_crystal_block" +} diff --git a/src/main/resources/assets/ebwizardry/models/item/sorcery_runestone.json b/src/main/resources/assets/ebwizardry/models/item/sorcery_runestone.json new file mode 100644 index 00000000..fb9805f3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/sorcery_runestone.json @@ -0,0 +1,8 @@ +{ + "parent": "ebwizardry:item/runestone_item", + "textures": { + "side": "ebwizardry:blocks/runestone_sorcery_0", + "rune": "ebwizardry:blocks/runestone_sorcery_1", + "overlay": "ebwizardry:blocks/runestone_sorcery_1_overlay" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/sorcery_runestone_pedestal.json b/src/main/resources/assets/ebwizardry/models/item/sorcery_runestone_pedestal.json new file mode 100644 index 00000000..7b87f885 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/sorcery_runestone_pedestal.json @@ -0,0 +1,9 @@ +{ + "parent": "ebwizardry:item/runestone_pedestal_item", + "textures": { + "side": "ebwizardry:blocks/runestone_pedestal_sorcery", + "top": "ebwizardry:blocks/runestone_sorcery_0", + "bottom": "ebwizardry:blocks/runestone_sorcery_0", + "overlay": "ebwizardry:blocks/runestone_pedestal_sorcery_overlay" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/mana_flask.json b/src/main/resources/assets/ebwizardry/models/item/spark_bomb.json similarity index 55% rename from src/main/resources/assets/ebwizardry/models/item/mana_flask.json rename to src/main/resources/assets/ebwizardry/models/item/spark_bomb.json index 278c497e..5e7423fa 100644 --- a/src/main/resources/assets/ebwizardry/models/item/mana_flask.json +++ b/src/main/resources/assets/ebwizardry/models/item/spark_bomb.json @@ -1,6 +1,6 @@ { "parent": "item/generated", "textures": { - "layer0": "ebwizardry:items/mana_flask" + "layer0": "ebwizardry:items/spark_bomb" } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow.json index e6e97ae8..befb8c49 100644 --- a/src/main/resources/assets/ebwizardry/models/item/spectral_bow.json +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow.json @@ -45,6 +45,61 @@ "pull": 0.9 }, "model": "ebwizardry:item/spectral_bow_pulling_2" + }, + { + "predicate": { + "conjuring": 1 + }, + "model": "ebwizardry:item/spectral_bow_conjuring_0" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.125 + }, + "model": "ebwizardry:item/spectral_bow_conjuring_1" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.25 + }, + "model": "ebwizardry:item/spectral_bow_conjuring_2" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.375 + }, + "model": "ebwizardry:item/spectral_bow_conjuring_3" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.5 + }, + "model": "ebwizardry:item/spectral_bow_conjuring_4" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.625 + }, + "model": "ebwizardry:item/spectral_bow_conjuring_5" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.75 + }, + "model": "ebwizardry:item/spectral_bow_conjuring_6" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.875 + }, + "model": "ebwizardry:item/spectral_bow_conjuring_7" } ] } diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_0.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_0.json new file mode 100644 index 00000000..96be3a05 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_0.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "ebwizardry:items/spectral_bow_conjuring_0" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_1.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_1.json new file mode 100644 index 00000000..1d515028 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_1.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "ebwizardry:items/spectral_bow_conjuring_1" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_2.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_2.json new file mode 100644 index 00000000..811e8bcb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "ebwizardry:items/spectral_bow_conjuring_2" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_3.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_3.json new file mode 100644 index 00000000..82a1134f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_3.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "ebwizardry:items/spectral_bow_conjuring_3" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_4.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_4.json new file mode 100644 index 00000000..53925e92 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_4.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "ebwizardry:items/spectral_bow_conjuring_4" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_5.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_5.json new file mode 100644 index 00000000..119c0e08 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_5.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "ebwizardry:items/spectral_bow_conjuring_5" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_6.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_6.json new file mode 100644 index 00000000..5db23b8c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_6.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "ebwizardry:items/spectral_bow_conjuring_6" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_7.json b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_7.json new file mode 100644 index 00000000..d4424975 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_bow_conjuring_7.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "ebwizardry:items/spectral_bow_conjuring_7" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe.json index 3f4b3eb2..84f23972 100644 --- a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe.json +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe.json @@ -2,5 +2,62 @@ "parent": "item/handheld", "textures": { "layer0": "ebwizardry:items/spectral_pickaxe" - } + }, + "overrides": [ + { + "predicate": { + "conjuring": 1 + }, + "model": "ebwizardry:item/spectral_pickaxe_conjuring_0" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.125 + }, + "model": "ebwizardry:item/spectral_pickaxe_conjuring_1" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.25 + }, + "model": "ebwizardry:item/spectral_pickaxe_conjuring_2" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.375 + }, + "model": "ebwizardry:item/spectral_pickaxe_conjuring_3" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.5 + }, + "model": "ebwizardry:item/spectral_pickaxe_conjuring_4" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.625 + }, + "model": "ebwizardry:item/spectral_pickaxe_conjuring_5" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.75 + }, + "model": "ebwizardry:item/spectral_pickaxe_conjuring_6" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.875 + }, + "model": "ebwizardry:item/spectral_pickaxe_conjuring_7" + } + ] } diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_0.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_0.json new file mode 100644 index 00000000..08b5ec38 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_0.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_pickaxe_conjuring_0" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_1.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_1.json new file mode 100644 index 00000000..e619f89f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_1.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_pickaxe_conjuring_1" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_2.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_2.json new file mode 100644 index 00000000..664b43c8 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_pickaxe_conjuring_2" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_3.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_3.json new file mode 100644 index 00000000..5f35d953 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_3.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_pickaxe_conjuring_3" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_4.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_4.json new file mode 100644 index 00000000..c9466a44 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_4.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_pickaxe_conjuring_4" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_5.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_5.json new file mode 100644 index 00000000..e848aef6 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_5.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_pickaxe_conjuring_5" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_6.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_6.json new file mode 100644 index 00000000..4b100b8a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_6.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_pickaxe_conjuring_6" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_7.json b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_7.json new file mode 100644 index 00000000..18b6c06c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_pickaxe_conjuring_7.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_pickaxe_conjuring_7" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword.json index c217987b..e812a899 100644 --- a/src/main/resources/assets/ebwizardry/models/item/spectral_sword.json +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword.json @@ -2,5 +2,62 @@ "parent": "item/handheld", "textures": { "layer0": "ebwizardry:items/spectral_sword" - } + }, + "overrides": [ + { + "predicate": { + "conjuring": 1 + }, + "model": "ebwizardry:item/spectral_sword_conjuring_0" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.125 + }, + "model": "ebwizardry:item/spectral_sword_conjuring_1" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.25 + }, + "model": "ebwizardry:item/spectral_sword_conjuring_2" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.375 + }, + "model": "ebwizardry:item/spectral_sword_conjuring_3" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.5 + }, + "model": "ebwizardry:item/spectral_sword_conjuring_4" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.625 + }, + "model": "ebwizardry:item/spectral_sword_conjuring_5" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.75 + }, + "model": "ebwizardry:item/spectral_sword_conjuring_6" + }, + { + "predicate": { + "conjuring": 1, + "conjure": 0.875 + }, + "model": "ebwizardry:item/spectral_sword_conjuring_7" + } + ] } diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_0.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_0.json new file mode 100644 index 00000000..89cae15a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_0.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_sword_conjuring_0" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_1.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_1.json new file mode 100644 index 00000000..5cf533e0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_1.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_sword_conjuring_1" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_2.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_2.json new file mode 100644 index 00000000..47d254b9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_sword_conjuring_2" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_3.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_3.json new file mode 100644 index 00000000..e4e22c97 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_3.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_sword_conjuring_3" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_4.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_4.json new file mode 100644 index 00000000..c4a0a651 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_4.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_sword_conjuring_4" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_5.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_5.json new file mode 100644 index 00000000..5d84cb34 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_5.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_sword_conjuring_5" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_6.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_6.json new file mode 100644 index 00000000..78b6502e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_6.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_sword_conjuring_6" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_7.json b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_7.json new file mode 100644 index 00000000..9ec91330 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/spectral_sword_conjuring_7.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "ebwizardry:items/spectral_sword_conjuring_7" + } +} diff --git a/src/main/resources/assets/ebwizardry/models/item/thorns.json b/src/main/resources/assets/ebwizardry/models/item/thorns.json new file mode 100644 index 00000000..4255e8bb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/models/item/thorns.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ebwizardry:blocks/thorns_upper_7" + } +} diff --git a/src/main/resources/assets/ebwizardry/recipes/arcane_workbench.json b/src/main/resources/assets/ebwizardry/recipes/arcane_workbench.json index 6727cb0c..735cacc0 100644 --- a/src/main/resources/assets/ebwizardry/recipes/arcane_workbench.json +++ b/src/main/resources/assets/ebwizardry/recipes/arcane_workbench.json @@ -14,9 +14,40 @@ "item": "minecraft:carpet", "data": 10 }, - "x": { - "item": "ebwizardry:magic_crystal" - }, + "x": [ + { + "item": "ebwizardry:magic_crystal", + "data": 0 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 1 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 2 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 4 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 5 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 6 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 7 + } + ], "y": { "type": "forge:ore_dict", "ore": "blockLapis" diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block.json index e70bb53c..2bf0ef30 100644 --- a/src/main/resources/assets/ebwizardry/recipes/crystal_block.json +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block.json @@ -7,10 +7,12 @@ ], "key": { "z": { - "item": "ebwizardry:magic_crystal" + "item": "ebwizardry:magic_crystal", + "data": 0 } }, "result": { - "item": "ebwizardry:crystal_block" + "item": "ebwizardry:crystal_block", + "data": 0 } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_earth.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_earth.json new file mode 100644 index 00000000..c24d9441 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_earth.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zzz", + "zzz" + ], + "key": { + "z": { + "item": "ebwizardry:magic_crystal", + "data": 5 + } + }, + "result": { + "item": "ebwizardry:crystal_block", + "data": 5 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_fire.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_fire.json new file mode 100644 index 00000000..fbb0b15a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_fire.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zzz", + "zzz" + ], + "key": { + "z": { + "item": "ebwizardry:magic_crystal", + "data": 1 + } + }, + "result": { + "item": "ebwizardry:crystal_block", + "data": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_healing.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_healing.json new file mode 100644 index 00000000..2cf4e092 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_healing.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zzz", + "zzz" + ], + "key": { + "z": { + "item": "ebwizardry:magic_crystal", + "data": 7 + } + }, + "result": { + "item": "ebwizardry:crystal_block", + "data": 7 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_ice.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_ice.json new file mode 100644 index 00000000..3e172395 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_ice.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zzz", + "zzz" + ], + "key": { + "z": { + "item": "ebwizardry:magic_crystal", + "data": 2 + } + }, + "result": { + "item": "ebwizardry:crystal_block", + "data": 2 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_lightning.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_lightning.json new file mode 100644 index 00000000..8f7417fc --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_lightning.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zzz", + "zzz" + ], + "key": { + "z": { + "item": "ebwizardry:magic_crystal", + "data": 3 + } + }, + "result": { + "item": "ebwizardry:crystal_block", + "data": 3 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_necromancy.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_necromancy.json new file mode 100644 index 00000000..4d76abdc --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_necromancy.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zzz", + "zzz" + ], + "key": { + "z": { + "item": "ebwizardry:magic_crystal", + "data": 4 + } + }, + "result": { + "item": "ebwizardry:crystal_block", + "data": 4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_sorcery.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_sorcery.json new file mode 100644 index 00000000..079793ad --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_sorcery.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zzz", + "zzz" + ], + "key": { + "z": { + "item": "ebwizardry:magic_crystal", + "data": 6 + } + }, + "result": { + "item": "ebwizardry:crystal_block", + "data": 6 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals.json index 488efbac..d2cb4435 100644 --- a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals.json +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals.json @@ -3,11 +3,13 @@ "group": "magic_crystal", "ingredients": [ { - "item": "ebwizardry:crystal_block" + "item": "ebwizardry:crystal_block", + "data": 0 } ], "result": { "item": "ebwizardry:magic_crystal", + "data": 0, "count": 9 } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_earth.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_earth.json new file mode 100644 index 00000000..81d77ff9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_earth.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "group": "magic_crystal", + "ingredients": [ + { + "item": "ebwizardry:crystal_block", + "data": 5 + } + ], + "result": { + "item": "ebwizardry:magic_crystal", + "data": 5, + "count": 9 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_fire.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_fire.json new file mode 100644 index 00000000..2760c161 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_fire.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "group": "magic_crystal", + "ingredients": [ + { + "item": "ebwizardry:crystal_block", + "data": 1 + } + ], + "result": { + "item": "ebwizardry:magic_crystal", + "data": 1, + "count": 9 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_healing.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_healing.json new file mode 100644 index 00000000..46f180de --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_healing.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "group": "magic_crystal", + "ingredients": [ + { + "item": "ebwizardry:crystal_block", + "data": 7 + } + ], + "result": { + "item": "ebwizardry:magic_crystal", + "data": 7, + "count": 9 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_ice.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_ice.json new file mode 100644 index 00000000..bc34ba01 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_ice.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "group": "magic_crystal", + "ingredients": [ + { + "item": "ebwizardry:crystal_block", + "data": 2 + } + ], + "result": { + "item": "ebwizardry:magic_crystal", + "data": 2, + "count": 9 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_lightning.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_lightning.json new file mode 100644 index 00000000..3bf151c0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_lightning.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "group": "magic_crystal", + "ingredients": [ + { + "item": "ebwizardry:crystal_block", + "data": 3 + } + ], + "result": { + "item": "ebwizardry:magic_crystal", + "data": 3, + "count": 9 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_necromancy.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_necromancy.json new file mode 100644 index 00000000..0de3b757 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_necromancy.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "group": "magic_crystal", + "ingredients": [ + { + "item": "ebwizardry:crystal_block", + "data": 4 + } + ], + "result": { + "item": "ebwizardry:magic_crystal", + "data": 4, + "count": 9 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_sorcery.json b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_sorcery.json new file mode 100644 index 00000000..cde5784c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_block_to_crystals_sorcery.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "group": "magic_crystal", + "ingredients": [ + { + "item": "ebwizardry:crystal_block", + "data": 6 + } + ], + "result": { + "item": "ebwizardry:magic_crystal", + "data": 6, + "count": 9 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_flower_to_crystals.json b/src/main/resources/assets/ebwizardry/recipes/crystal_flower_to_crystals.json index 2ba98699..4a86c790 100644 --- a/src/main/resources/assets/ebwizardry/recipes/crystal_flower_to_crystals.json +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_flower_to_crystals.json @@ -8,6 +8,7 @@ ], "result": { "item": "ebwizardry:magic_crystal", + "data": 0, "count": 2 } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/crystal_shard.json b/src/main/resources/assets/ebwizardry/recipes/crystal_shard.json new file mode 100644 index 00000000..8055c3cf --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/crystal_shard.json @@ -0,0 +1,13 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "ebwizardry:magic_crystal", + "data": 0 + } + ], + "result": { + "item": "ebwizardry:crystal_shard", + "count": 9 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/large_mana_flask.json b/src/main/resources/assets/ebwizardry/recipes/large_mana_flask.json new file mode 100644 index 00000000..ddd76bc0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/large_mana_flask.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " y ", + "yxy", + " y " + ], + "key": { + "x": { + "item": "minecraft:glass_bottle" + }, + "y": { + "item": "ebwizardry:grand_crystal" + } + }, + "result": { + "item": "ebwizardry:large_mana_flask" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/magic_missile_spell_book.json b/src/main/resources/assets/ebwizardry/recipes/magic_missile_spell_book.json index b366af36..f182d17b 100644 --- a/src/main/resources/assets/ebwizardry/recipes/magic_missile_spell_book.json +++ b/src/main/resources/assets/ebwizardry/recipes/magic_missile_spell_book.json @@ -7,7 +7,8 @@ ], "key": { "x": { - "item": "ebwizardry:magic_crystal" + "item": "ebwizardry:magic_crystal", + "data": 0 }, "y": { "item": "minecraft:book" diff --git a/src/main/resources/assets/ebwizardry/recipes/magic_silk.json b/src/main/resources/assets/ebwizardry/recipes/magic_silk.json index 7f2cad0c..033a85e4 100644 --- a/src/main/resources/assets/ebwizardry/recipes/magic_silk.json +++ b/src/main/resources/assets/ebwizardry/recipes/magic_silk.json @@ -9,9 +9,40 @@ "x": { "item": "minecraft:string" }, - "y": { - "item": "ebwizardry:magic_crystal" - } + "y": [ + { + "item": "ebwizardry:magic_crystal", + "data": 0 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 1 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 2 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 4 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 5 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 6 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 7 + } + ] }, "result": { "item": "ebwizardry:magic_silk", diff --git a/src/main/resources/assets/ebwizardry/recipes/magic_wand.json b/src/main/resources/assets/ebwizardry/recipes/magic_wand.json index ab8988a1..0326f1d3 100644 --- a/src/main/resources/assets/ebwizardry/recipes/magic_wand.json +++ b/src/main/resources/assets/ebwizardry/recipes/magic_wand.json @@ -15,7 +15,8 @@ "ore": "stickWood" }, "z": { - "item": "ebwizardry:magic_crystal" + "item": "ebwizardry:magic_crystal", + "data": 0 } }, "result": { diff --git a/src/main/resources/assets/ebwizardry/recipes/medium_mana_flask.json b/src/main/resources/assets/ebwizardry/recipes/medium_mana_flask.json new file mode 100644 index 00000000..05d32520 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/medium_mana_flask.json @@ -0,0 +1,50 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "yyy", + "yxy", + "yyy" + ], + "key": { + "x": { + "item": "minecraft:glass_bottle" + }, + "y": [ + { + "item": "ebwizardry:magic_crystal", + "data": 0 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 1 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 2 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 4 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 5 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 6 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 7 + } + ] + }, + "result": { + "item": "ebwizardry:medium_mana_flask" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_earth.json b/src/main/resources/assets/ebwizardry/recipes/runestone_earth.json new file mode 100644 index 00000000..e9c6525d --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_earth.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zyz", + "zzz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 5 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone", + "data": 5, + "count": 8 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_fire.json b/src/main/resources/assets/ebwizardry/recipes/runestone_fire.json new file mode 100644 index 00000000..bbad7ccb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_fire.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zyz", + "zzz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 1 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone", + "data": 1, + "count": 8 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_healing.json b/src/main/resources/assets/ebwizardry/recipes/runestone_healing.json new file mode 100644 index 00000000..91a51a69 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_healing.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zyz", + "zzz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 7 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone", + "data": 7, + "count": 8 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_ice.json b/src/main/resources/assets/ebwizardry/recipes/runestone_ice.json new file mode 100644 index 00000000..cce3b6de --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_ice.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zyz", + "zzz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 2 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone", + "data": 2, + "count": 8 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_lightning.json b/src/main/resources/assets/ebwizardry/recipes/runestone_lightning.json new file mode 100644 index 00000000..d18ed59c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_lightning.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zyz", + "zzz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone", + "data": 3, + "count": 8 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_necromancy.json b/src/main/resources/assets/ebwizardry/recipes/runestone_necromancy.json new file mode 100644 index 00000000..2c90d6e1 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_necromancy.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zyz", + "zzz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 4 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone", + "data": 4, + "count": 8 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_earth.json b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_earth.json new file mode 100644 index 00000000..740650c9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_earth.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "yyy", + "zyz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 5 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone_pedestal", + "data": 5, + "count": 2 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_fire.json b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_fire.json new file mode 100644 index 00000000..966acb1f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_fire.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "yyy", + "zyz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 1 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone_pedestal", + "data": 1, + "count": 2 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_healing.json b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_healing.json new file mode 100644 index 00000000..d61a20a3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_healing.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "yyy", + "zyz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 7 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone_pedestal", + "data": 7, + "count": 2 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_ice.json b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_ice.json new file mode 100644 index 00000000..c9bb2a29 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_ice.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "yyy", + "zyz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 2 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone_pedestal", + "data": 2, + "count": 2 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_lightning.json b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_lightning.json new file mode 100644 index 00000000..f04d08ae --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_lightning.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "yyy", + "zyz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone_pedestal", + "data": 3, + "count": 2 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_necromancy.json b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_necromancy.json new file mode 100644 index 00000000..5b55f0cb --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_necromancy.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "yyy", + "zyz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 4 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone_pedestal", + "data": 4, + "count": 2 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_sorcery.json b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_sorcery.json new file mode 100644 index 00000000..3de61998 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_pedestal_sorcery.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "yyy", + "zyz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 6 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone_pedestal", + "data": 6, + "count": 2 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/runestone_sorcery.json b/src/main/resources/assets/ebwizardry/recipes/runestone_sorcery.json new file mode 100644 index 00000000..b32ec980 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/runestone_sorcery.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "zzz", + "zyz", + "zzz" + ], + "key": { + "y": { + "item": "ebwizardry:magic_crystal", + "data": 6 + }, + "z": { + "type": "forge:ore_dict", + "ore": "stone" + } + }, + "result": { + "item": "ebwizardry:runestone", + "data": 6, + "count": 8 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/mana_flask.json b/src/main/resources/assets/ebwizardry/recipes/small_mana_flask.json similarity index 71% rename from src/main/resources/assets/ebwizardry/recipes/mana_flask.json rename to src/main/resources/assets/ebwizardry/recipes/small_mana_flask.json index af183c45..50bd84d3 100644 --- a/src/main/resources/assets/ebwizardry/recipes/mana_flask.json +++ b/src/main/resources/assets/ebwizardry/recipes/small_mana_flask.json @@ -10,10 +10,10 @@ "item": "minecraft:glass_bottle" }, "y": { - "item": "ebwizardry:magic_crystal" - } + "item": "ebwizardry:crystal_shard" + } }, "result": { - "item": "ebwizardry:mana_flask" + "item": "ebwizardry:small_mana_flask" } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/spark_bomb.json b/src/main/resources/assets/ebwizardry/recipes/spark_bomb.json new file mode 100644 index 00000000..84ce4135 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/spark_bomb.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + { + "item": "minecraft:glass_bottle" + }, + { + "item": "minecraft:gunpowder" + } + ], + "result": { + "item": "ebwizardry:spark_bomb", + "count": 3 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/transportation_stone.json b/src/main/resources/assets/ebwizardry/recipes/transportation_stone.json index f28c629b..f8f8bb27 100644 --- a/src/main/resources/assets/ebwizardry/recipes/transportation_stone.json +++ b/src/main/resources/assets/ebwizardry/recipes/transportation_stone.json @@ -10,9 +10,40 @@ "type": "forge:ore_dict", "ore": "stone" }, - "y": { - "item": "ebwizardry:magic_crystal" - } + "y": [ + { + "item": "ebwizardry:magic_crystal", + "data": 0 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 1 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 2 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 4 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 5 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 6 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 7 + } + ] }, "result": { "item": "ebwizardry:transportation_stone", diff --git a/src/main/resources/assets/ebwizardry/recipes/wand_earth.json b/src/main/resources/assets/ebwizardry/recipes/wand_earth.json new file mode 100644 index 00000000..efd14864 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/wand_earth.json @@ -0,0 +1,25 @@ +{ + "type": "forge:ore_shaped", + "pattern": [ + " z", + " y ", + "x " + ], + "key": { + "x": { + "type": "forge:ore_dict", + "ore": "nuggetGold" + }, + "y": { + "type": "forge:ore_dict", + "ore": "stickWood" + }, + "z": { + "item": "ebwizardry:magic_crystal", + "data": 5 + } + }, + "result": { + "item": "ebwizardry:novice_earth_wand" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/wand_fire.json b/src/main/resources/assets/ebwizardry/recipes/wand_fire.json new file mode 100644 index 00000000..fab82814 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/wand_fire.json @@ -0,0 +1,25 @@ +{ + "type": "forge:ore_shaped", + "pattern": [ + " z", + " y ", + "x " + ], + "key": { + "x": { + "type": "forge:ore_dict", + "ore": "nuggetGold" + }, + "y": { + "type": "forge:ore_dict", + "ore": "stickWood" + }, + "z": { + "item": "ebwizardry:magic_crystal", + "data": 1 + } + }, + "result": { + "item": "ebwizardry:novice_fire_wand" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/wand_healing.json b/src/main/resources/assets/ebwizardry/recipes/wand_healing.json new file mode 100644 index 00000000..4e5ec1e3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/wand_healing.json @@ -0,0 +1,25 @@ +{ + "type": "forge:ore_shaped", + "pattern": [ + " z", + " y ", + "x " + ], + "key": { + "x": { + "type": "forge:ore_dict", + "ore": "nuggetGold" + }, + "y": { + "type": "forge:ore_dict", + "ore": "stickWood" + }, + "z": { + "item": "ebwizardry:magic_crystal", + "data": 7 + } + }, + "result": { + "item": "ebwizardry:novice_healing_wand" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/wand_ice.json b/src/main/resources/assets/ebwizardry/recipes/wand_ice.json new file mode 100644 index 00000000..c7a8db84 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/wand_ice.json @@ -0,0 +1,25 @@ +{ + "type": "forge:ore_shaped", + "pattern": [ + " z", + " y ", + "x " + ], + "key": { + "x": { + "type": "forge:ore_dict", + "ore": "nuggetGold" + }, + "y": { + "type": "forge:ore_dict", + "ore": "stickWood" + }, + "z": { + "item": "ebwizardry:magic_crystal", + "data": 2 + } + }, + "result": { + "item": "ebwizardry:novice_ice_wand" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/wand_lightning.json b/src/main/resources/assets/ebwizardry/recipes/wand_lightning.json new file mode 100644 index 00000000..fd88205e --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/wand_lightning.json @@ -0,0 +1,25 @@ +{ + "type": "forge:ore_shaped", + "pattern": [ + " z", + " y ", + "x " + ], + "key": { + "x": { + "type": "forge:ore_dict", + "ore": "nuggetGold" + }, + "y": { + "type": "forge:ore_dict", + "ore": "stickWood" + }, + "z": { + "item": "ebwizardry:magic_crystal", + "data": 3 + } + }, + "result": { + "item": "ebwizardry:novice_lightning_wand" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/wand_necromancy.json b/src/main/resources/assets/ebwizardry/recipes/wand_necromancy.json new file mode 100644 index 00000000..8173afa3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/wand_necromancy.json @@ -0,0 +1,25 @@ +{ + "type": "forge:ore_shaped", + "pattern": [ + " z", + " y ", + "x " + ], + "key": { + "x": { + "type": "forge:ore_dict", + "ore": "nuggetGold" + }, + "y": { + "type": "forge:ore_dict", + "ore": "stickWood" + }, + "z": { + "item": "ebwizardry:magic_crystal", + "data": 4 + } + }, + "result": { + "item": "ebwizardry:novice_necromancy_wand" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/wand_sorcery.json b/src/main/resources/assets/ebwizardry/recipes/wand_sorcery.json new file mode 100644 index 00000000..d8cc12a3 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/recipes/wand_sorcery.json @@ -0,0 +1,25 @@ +{ + "type": "forge:ore_shaped", + "pattern": [ + " z", + " y ", + "x " + ], + "key": { + "x": { + "type": "forge:ore_dict", + "ore": "nuggetGold" + }, + "y": { + "type": "forge:ore_dict", + "ore": "stickWood" + }, + "z": { + "item": "ebwizardry:magic_crystal", + "data": 6 + } + }, + "result": { + "item": "ebwizardry:novice_sorcery_wand" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/recipes/wizard_handbook.json b/src/main/resources/assets/ebwizardry/recipes/wizard_handbook.json index f9bee5da..fa51a004 100644 --- a/src/main/resources/assets/ebwizardry/recipes/wizard_handbook.json +++ b/src/main/resources/assets/ebwizardry/recipes/wizard_handbook.json @@ -4,9 +4,40 @@ { "item": "minecraft:book" }, - { - "item": "ebwizardry:magic_crystal" - } + [ + { + "item": "ebwizardry:magic_crystal", + "data": 0 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 1 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 2 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 3 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 4 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 5 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 6 + }, + { + "item": "ebwizardry:magic_crystal", + "data": 7 + } + ] ], "result": { "item": "ebwizardry:wizard_handbook" diff --git a/src/main/resources/assets/ebwizardry/shaders/post/possession.json b/src/main/resources/assets/ebwizardry/shaders/post/possession.json new file mode 100644 index 00000000..04c52685 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/shaders/post/possession.json @@ -0,0 +1,73 @@ +{ + "targets": [ + "swap", + "previous", + "a", + "b", + "c" + ], + "passes": [ + { + "name": "color_convolve", + "intarget": "minecraft:main", + "outtarget": "a", + "uniforms": [ + { + "name": "Saturation", + "values": [ 0.2 ] + } + ] + }, + { + "name": "color_convolve", + "intarget": "a", + "outtarget": "b", + "uniforms": [ + { + "name": "RedMatrix", + "values": [ 0.2, 0.2, 0.1 ] + }, + { + "name": "GreenMatrix", + "values": [ 0.1, 0.1, 0.1 ] + }, + { + "name": "BlueMatrix", + "values": [ 0.2, 0.2, 0.3 ] + } + ] + }, + { + "name": "deconverge", + "intarget": "a", + "outtarget": "c" + }, + { + "name": "phosphor", + "intarget": "c", + "outtarget": "swap", + "auxtargets": [ + { + "name": "PrevSampler", + "id": "previous" + } + ], + "uniforms": [ + { + "name": "Phosphor", + "values": [ 0.8, 0.8, 0.8 ] + } + ] + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "previous" + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/ebwizardry/shaders/post/sixth_sense.json b/src/main/resources/assets/ebwizardry/shaders/post/sixth_sense.json new file mode 100644 index 00000000..0c66b6ae --- /dev/null +++ b/src/main/resources/assets/ebwizardry/shaders/post/sixth_sense.json @@ -0,0 +1,67 @@ +{ + "targets": [ + "swap", + "previous", + "a", + "b" + ], + "passes": [ + { + "name": "color_convolve", + "intarget": "minecraft:main", + "outtarget": "a", + "uniforms": [ + { + "name": "Saturation", + "values": [ 0.3 ] + } + ] + }, + { + "name": "color_convolve", + "intarget": "a", + "outtarget": "b", + "uniforms": [ + { + "name": "RedMatrix", + "values": [ 0.3, 0, 0 ] + }, + { + "name": "GreenMatrix", + "values": [ 0.3, 0.6, 0.3 ] + }, + { + "name": "BlueMatrix", + "values": [ 0.2, 0.2, 0.5 ] + } + ] + }, + { + "name": "phosphor", + "intarget": "b", + "outtarget": "swap", + "auxtargets": [ + { + "name": "PrevSampler", + "id": "previous" + } + ], + "uniforms": [ + { + "name": "Phosphor", + "values": [ 0.8, 0.8, 0.8 ] + } + ] + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "previous" + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/ebwizardry/shaders/post/slow_time.json b/src/main/resources/assets/ebwizardry/shaders/post/slow_time.json new file mode 100644 index 00000000..09f32ab1 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/shaders/post/slow_time.json @@ -0,0 +1,37 @@ +{ + "targets": [ + "a" + ], + "passes": [ + { + "name": "color_convolve", + "intarget": "minecraft:main", + "outtarget": "a", + "uniforms": [ + { + "name": "Saturation", + "values": [ 0.2 ] + } + ] + }, + { + "name": "color_convolve", + "intarget": "a", + "outtarget": "minecraft:main", + "uniforms": [ + { + "name": "RedMatrix", + "values": [ 0.6, 0, 0 ] + }, + { + "name": "GreenMatrix", + "values": [ 0, 0.7, 0 ] + }, + { + "name": "BlueMatrix", + "values": [ 0.1, 0.1, 1 ] + } + ] + } + ] +} diff --git a/src/main/resources/assets/ebwizardry/shaders/post/transience.json b/src/main/resources/assets/ebwizardry/shaders/post/transience.json new file mode 100644 index 00000000..9b30fe4f --- /dev/null +++ b/src/main/resources/assets/ebwizardry/shaders/post/transience.json @@ -0,0 +1,67 @@ +{ + "targets": [ + "swap", + "previous", + "a", + "b" + ], + "passes": [ + { + "name": "color_convolve", + "intarget": "minecraft:main", + "outtarget": "a", + "uniforms": [ + { + "name": "Saturation", + "values": [ 0.8 ] + } + ] + }, + { + "name": "color_convolve", + "intarget": "a", + "outtarget": "b", + "uniforms": [ + { + "name": "RedMatrix", + "values": [ 0.9, 0.9, 0.7 ] + }, + { + "name": "GreenMatrix", + "values": [ 0.9, 0.9, 0.7 ] + }, + { + "name": "BlueMatrix", + "values": [ 0.8, 0.8, 0.7 ] + } + ] + }, + { + "name": "phosphor", + "intarget": "b", + "outtarget": "swap", + "auxtargets": [ + { + "name": "PrevSampler", + "id": "previous" + } + ], + "uniforms": [ + { + "name": "Phosphor", + "values": [ 0.8, 0.8, 0.8 ] + } + ] + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "previous" + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/ebwizardry/sounds.json b/src/main/resources/assets/ebwizardry/sounds.json index 42258e4b..9ed093b0 100644 --- a/src/main/resources/assets/ebwizardry/sounds.json +++ b/src/main/resources/assets/ebwizardry/sounds.json @@ -1,41 +1,361 @@ { - "arc": {"category": "player","sounds": [ - {"name": "ebwizardry:arc1","stream": false}, - {"name": "ebwizardry:arc1","stream": false}, - {"name": "ebwizardry:arc3","stream": false} - ]}, - - "aura": {"category": "player","sounds": [{"name": "ebwizardry:aura","stream": false}]}, - "boom": {"category": "player","sounds": [{"name": "ebwizardry:boom","stream": false}]}, - "crackle": {"category": "player","sounds": [{"name": "ebwizardry:crackle","stream": false}]}, + "block.arcane_workbench.bind_spell": {"category": "blocks", "sounds": ["ebwizardry:spellbind"]}, + "block.pedestal.activate": {"category": "blocks", "sounds": ["mob/evocation_illager/prepare_summon"]}, + "block.pedestal.conquer": {"category": "blocks", "sounds": ["ui/toast/challenge_complete"]}, + + "item.wand.switch_spell": {"category": "player", "sounds": ["ebwizardry:select"]}, + "item.wand.levelup": {"category": "player", "sounds": ["random/levelup"]}, + "item.wand.melee": {"category": "player", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "item.armour.equip_silk": {"category": "player", "sounds": ["item/armor/equip_leather1", "item/armor/equip_leather2", "item/armor/equip_leather3", "item/armor/equip_leather4", "item/armor/equip_leather5", "item/armor/equip_leather6"]}, + "item.purifying_elixir.drink": {"category": "player", "sounds": ["ebwizardry:spellbind"]}, - "darkaura": {"category": "player","sounds": [ - {"name": "ebwizardry:darkaura1","stream": false}, - {"name": "ebwizardry:darkaura2","stream": false} - ]}, - - "effect": {"category": "player","sounds": [ - {"name": "ebwizardry:effect1","stream": false}, - {"name": "ebwizardry:effect2","stream": false} - ]}, - - "electricitya": {"category": "player","sounds": [{"name": "ebwizardry:electricitya","stream": false}]}, - "electricityb": {"category": "player","sounds": [{"name": "ebwizardry:electricityb","stream": false}]}, + "entity.black_hole.ambient": {"category": "spells", "sounds": ["portal/portal"]}, + "entity.black_hole.vanish": {"category": "spells", "sounds": ["portal/trigger"]}, + "entity.bubble.pop": {"category": "spells", "sounds": ["random/pop"]}, + "entity.blizzard.ambient": {"category": "spells", "sounds": ["ebwizardry:wind"]}, + "entity.decay.ambient": {"category": "spells", "sounds": ["liquid/lava"]}, + "entity.entrapment.ambient": {"category": "spells", "sounds": ["portal/portal"]}, + "entity.entrapment.vanish": {"category": "spells", "sounds": ["portal/trigger"]}, + "entity.fire_ring.ambient": {"category": "spells", "sounds": ["fire/fire"]}, + "entity.fire_sigil.trigger": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "entity.forcefield.deflect": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "entity.frost_sigil.trigger": {"category": "spells", "sounds": ["ebwizardry:freeze"]}, + "entity.hammer.attack": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "entity.hammer.explode": {"category": "spells", "sounds": ["random/explode1", "random/explode2", "random/explode3", "random/explode4"]}, + "entity.hammer.throw": {"category": "spells", "sounds": ["random/bow"]}, + "entity.hammer.land": {"category": "spells", "sounds": ["random/anvil_land"]}, + "entity.heal_aura.ambient": {"category": "spells", "sounds": ["ebwizardry:sparkle"]}, + "entity.ice_spike.extend": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "entity.lightning_sigil.trigger": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "entity.meteor.falling": {"category": "spells", "sounds": ["ebwizardry:flames_loop"]}, + "entity.shield.deflect": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "entity.tornado.ambient": {"category": "spells", "sounds": ["ebwizardry:wind"]}, - "flameray": {"category": "player","sounds": [{"name": "ebwizardry:flameray2","stream": false}]}, - "force": {"category": "player","sounds": [{"name": "ebwizardry:force","stream": false}]}, - - "freeze": {"category": "player","sounds": [{"name": "ebwizardry:freeze","stream": false}]}, - "frostray": {"category": "player","sounds": [{"name": "ebwizardry:frostray","stream": false}]}, - "heal": {"category": "player","sounds": [{"name": "ebwizardry:heal","stream": false}]}, - "ice": {"category": "player","sounds": [{"name": "ebwizardry:ice","stream": false}]}, - "largeaura": {"category": "player","sounds": [{"name": "ebwizardry:largeaura","stream": false}]}, + "entity.evil_wizard.ambient": {"category": "hostile", "sounds": ["mob/evocation_illager/idle1", "mob/evocation_illager/idle2", "mob/evocation_illager/idle3", "mob/evocation_illager/idle4"]}, + "entity.evil_wizard.hurt": {"category": "hostile", "sounds": ["mob/evocation_illager/hurt1", "mob/evocation_illager/hurt2"]}, + "entity.evil_wizard.death": {"category": "hostile", "sounds": ["mob/evocation_illager/death1", "mob/evocation_illager/death2"]}, + "entity.ice_giant.attack": {"category": "hostile", "sounds": ["mob/irongolem/throw"]}, + "entity.ice_giant.despawn": {"category": "hostile", "sounds": ["ebwizardry:freeze"]}, + "entity.ice_wraith.ambient": {"category": "hostile", "sounds": ["ebwizardry:wind"]}, + "entity.magic_slime.attack": {"category": "hostile", "sounds": ["mob/slime/attack1", "mob/slime/attack2"]}, + "entity.magic_slime.explode": {"category": "hostile", "sounds": ["fireworks/blast_far1"]}, + "entity.magic_slime.splat": {"category": "hostile", "sounds": ["mob/slime/attack1", "mob/slime/attack2"]}, + "entity.phoenix.ambient": {"category": "hostile", "sounds": ["mob/blaze/breathe1", "mob/blaze/breathe2", "mob/blaze/breathe3", "mob/blaze/breathe4"]}, + "entity.phoenix.burn": {"category": "hostile", "sounds": ["fire/fire"]}, + "entity.phoenix.flap": {"category": "hostile", "sounds": ["mob/enderdragon/wings1", "mob/enderdragon/wings2", "mob/enderdragon/wings3", "mob/enderdragon/wings4", "mob/enderdragon/wings5", "mob/enderdragon/wings6"]}, + "entity.phoenix.hurt": {"category": "hostile", "sounds": ["mob/blaze/hit1", "mob/blaze/hit2", "mob/blaze/hit3", "mob/blaze/hit4"]}, + "entity.phoenix.death": {"category": "hostile", "sounds": ["mob/blaze/death"]}, + "entity.shadow_wraith.ambient": {"category": "hostile", "sounds": ["mob/blaze/breathe1", "mob/blaze/breathe2", "mob/blaze/breathe3", "mob/blaze/breathe4"]}, + "entity.shadow_wraith.noise": {"category": "hostile", "sounds": ["portal/portal"]}, + "entity.shadow_wraith.hurt": {"category": "hostile", "sounds": ["mob/blaze/hit1", "mob/blaze/hit2", "mob/blaze/hit3", "mob/blaze/hit4"]}, + "entity.shadow_wraith.death": {"category": "hostile", "sounds": ["mob/blaze/death"]}, + "entity.spirit_horse.vanish": {"category": "neutral", "sounds": ["ebwizardry:conjure_large"]}, + "entity.spirit_wolf.vanish": {"category": "neutral", "sounds": ["ebwizardry:conjure_large"]}, + "entity.storm_elemental.ambient": {"category": "hostile", "sounds": ["mob/blaze/breathe1", "mob/blaze/breathe2", "mob/blaze/breathe3", "mob/blaze/breathe4"]}, + "entity.storm_elemental.burn": {"category": "hostile", "sounds": ["fire/fire"]}, + "entity.storm_elemental.wind": {"category": "hostile", "sounds": ["ebwizardry:wind"]}, + "entity.storm_elemental.hurt": {"category": "hostile", "sounds": ["mob/blaze/hit1", "mob/blaze/hit2", "mob/blaze/hit3", "mob/blaze/hit4"]}, + "entity.storm_elemental.death": {"category": "hostile", "sounds": ["mob/blaze/death"]}, + "entity.wizard.ambient": {"category": "neutral", "sounds": ["mob/villager/idle1", "mob/villager/idle2", "mob/villager/idle3"]}, + "entity.wizard.trading": {"category": "neutral", "sounds": ["mob/villager/haggle1", "mob/villager/haggle2", "mob/villager/haggle3"]}, + "entity.wizard.yes": {"category": "neutral", "sounds": ["mob/villager/yes1", "mob/villager/yes2", "mob/villager/yes3"]}, + "entity.wizard.no": {"category": "neutral", "sounds": ["mob/villager/no1", "mob/villager/no2", "mob/villager/no3"]}, + "entity.wizard.hurt": {"category": "neutral", "sounds": ["mob/villager/hit1", "mob/villager/hit2", "mob/villager/hit3", "mob/villager/hit4"]}, + "entity.wizard.death": {"category": "neutral", "sounds": ["mob/villager/death"]}, - "magic": {"category": "player","sounds": [{"name": "ebwizardry:magic1","stream": false}]}, - - "sparkle": {"category": "player","sounds": [{"name": "ebwizardry:sparkle","stream": false}]}, - "wind": {"category": "player","sounds": [{"name": "ebwizardry:wind","stream": false}]}, - "rumble": {"category": "player","sounds": [{"name": "ebwizardry:rumble","stream": false}]}, + "entity.darkness_orb.hit": {"category": "spells", "sounds": ["mob/wither/hurt1", "mob/wither/hurt2", "mob/wither/hurt3", "mob/wither/hurt4"]}, + "entity.dart.hit": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, + "entity.dart.hit_block": {"category": "spells", "sounds": ["random/bowhit1", "random/bowhit2", "random/bowhit3"]}, + "entity.firebolt.hit": {"category": "spells", "sounds": ["liquid/lavapop"]}, + "entity.firebomb.throw": {"category": "spells", "sounds": ["random/bow"]}, + "entity.firebomb.smash": {"category": "spells", "sounds": ["random/glass1", "random/glass2", "random/glass3"]}, + "entity.firebomb.fire": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "entity.force_arrow.hit": {"category": "spells", "sounds": ["fireworks/blast1"]}, + "entity.force_orb.hit": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, + "entity.force_orb.hit_block": {"category": "spells", "sounds": ["fireworks/blast1"]}, + "entity.iceball.hit": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, + "entity.ice_charge.smash": {"category": "spells", "sounds": ["random/glass1", "random/glass2", "random/glass3"]}, + "entity.ice_charge.ice": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "entity.ice_lance.smash": {"category": "spells", "sounds": ["random/glass1", "random/glass2", "random/glass3"]}, + "entity.ice_lance.hit": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, + "entity.ice_shard.smash": {"category": "spells", "sounds": ["random/glass1", "random/glass2", "random/glass3"]}, + "entity.ice_shard.hit": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, + "entity.lightning_arrow.hit": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "entity.lightning_disc.hit": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "entity.magic_missile.hit": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, + "entity.poison_bomb.throw": {"category": "spells", "sounds": ["random/bow"]}, + "entity.poison_bomb.smash": {"category": "spells", "sounds": ["random/glass1", "random/glass2", "random/glass3"]}, + "entity.poison_bomb.poison": {"category": "spells", "sounds": ["random/fizz"]}, + "entity.smoke_bomb.throw": {"category": "spells", "sounds": ["random/bow"]}, + "entity.smoke_bomb.smash": {"category": "spells", "sounds": ["random/glass1", "random/glass2", "random/glass3"]}, + "entity.smoke_bomb.smoke": {"category": "spells", "sounds": ["random/fizz"]}, + "entity.homing_spark.hit": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "entity.spark_bomb.throw": {"category": "spells", "sounds": ["random/bow"]}, + "entity.spark_bomb.hit": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, + "entity.spark_bomb.hit_block": {"category": "spells", "sounds": ["fireworks/blast_far1"]}, + "entity.spark_bomb.chain": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "entity.thunderbolt.hit": {"category": "spells", "sounds": ["fireworks/largeblast1"]}, - "select": {"category": "player","sounds": [{"name": "ebwizardry:select","stream": false}]} + "misc.discover_spell": {"category": "player", "sounds": ["random/levelup"]}, + "misc.page_turn": {"category": "player", "sounds": ["ebwizardry:page1", "ebwizardry:page2", "ebwizardry:page3"]}, + "misc.book_open": {"category": "player", "sounds": ["ebwizardry:book"]}, + + "misc.freeze": {"category": "spells", "sounds": ["ebwizardry:freeze"]}, + + "spell.agility": {"category": "spells", "sounds": ["ebwizardry:heal"]}, + "spell.arc": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "spell.arcane_jammer": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "spell.arcane_lock": {"category": "spells", "sounds": ["entity/endereye/dead1", "entity/endereye/dead2"]}, + "spell.arrow_rain": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]}, + "spell.banish": {"category": "spells", "sounds": ["mob/endermen/portal", "mob/endermen/portal2"]}, + "spell.black_hole": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_attack1", "mob/evocation_illager/prepare_attack2"]}, + "spell.blink": {"category": "spells", "sounds": ["mob/endermen/portal", "mob/endermen/portal2"]}, + "spell.blizzard": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.bubble.shoot": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.bubble.splash": {"category": "spells", "sounds": ["liquid/swim1", "liquid/swim2", "liquid/swim3", "liquid/swim4"], "volume": 2}, + "spell.chain_lightning": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "spell.charge": {"category": "spells", "sounds": ["ebwizardry:shockwave"]}, + "spell.clairvoyance": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.cobwebs": {"category": "spells", "sounds": ["random/fizz"]}, + "spell.combustion_rune": {"category": "spells", "sounds": ["fire/ignite"]}, + "spell.containment": {"category": "spells", "sounds": ["mob/guardian/curse"]}, + "spell.conjure_armour": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.conjure_block": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.conjure_bow": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.conjure_pickaxe": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.conjure_sword": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.cure_effects": {"category": "spells", "sounds": ["ebwizardry:heal"]}, + "spell.curse_of_enfeeblement": {"category": "spells", "sounds": ["mob/wither/spawn"]}, + "spell.curse_of_soulbinding": {"category": "spells", "sounds": ["mob/guardian/curse"]}, + "spell.curse_of_soulbinding.retaliate": {"category": "spells", "sounds": ["mob/wither/hurt1", "mob/wither/hurt2", "mob/wither/hurt3", "mob/wither/hurt4"]}, + "spell.curse_of_undeath": {"category": "spells", "sounds": ["mob/guardian/curse"]}, + "spell.darkness_orb": {"category": "spells", "sounds": ["mob/wither/shoot"]}, + "spell.darkvision": {"category": "spells", "sounds": ["ebwizardry:heal"]}, + "spell.dart": {"category": "spells", "sounds": ["random/bow"]}, + "spell.decay": {"category": "spells", "sounds": ["mob/wither/shoot"]}, + "spell.decoy": {"category": "spells", "sounds": ["mob/illusion_illager/mirror_move1", "mob/illusion_illager/mirror_move2"]}, + "spell.detonate": {"category": "spells", "sounds": ["random/explode1", "random/explode2", "random/explode3", "random/explode4"]}, + "spell.diamondflesh": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.disintegration": {"category": "spells", "sounds": ["ebwizardry:firebolt"]}, + "spell.divination": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.dragon_fireball": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "spell.earthquake": {"category": "spells", "sounds": ["ebwizardry:rumble"]}, + "spell.empowering_presence": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.entrapment": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_attack1", "mob/evocation_illager/prepare_attack2"]}, + "spell.evade": {"category": "spells", "sounds": ["random/bow"]}, + "spell.fireball": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "spell.firebolt": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "spell.firebomb": {"category": "spells", "sounds": ["random/bow"]}, + "spell.fire_resistance": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.fire_sigil": {"category": "spells", "sounds": ["fire/ignite"]}, + "spell.fireskin": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.fire_breath.start": {"category": "spells", "sounds": ["ebwizardry:flames_start"]}, + "spell.fire_breath.loop": {"category": "spells", "sounds": ["ebwizardry:flames_loop"]}, + "spell.fire_breath.end": {"category": "spells", "sounds": ["ebwizardry:flames_end"]}, + "spell.flame_ray.start": {"category": "spells", "sounds": ["ebwizardry:flames_start"]}, + "spell.flame_ray.loop": {"category": "spells", "sounds": ["ebwizardry:flames_loop"]}, + "spell.flame_ray.end": {"category": "spells", "sounds": ["ebwizardry:flames_end"]}, + "spell.flaming_axe": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.flaming_weapon": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.flight": {"category": "spells", "sounds": ["mob/enderdragon/wings1", "mob/enderdragon/wings2", "mob/enderdragon/wings3", "mob/enderdragon/wings4", "mob/enderdragon/wings5", "mob/enderdragon/wings6"]}, + "spell.font_of_mana": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, + "spell.font_of_vitality": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, + "spell.force_arrow": {"category": "spells", "sounds": ["ebwizardry:force"]}, + "spell.forcefield": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]}, + "spell.force_orb": {"category": "spells", "sounds": ["random/bow"]}, + "spell.forests_curse": {"category": "spells", "sounds": ["mob/wither/spawn"]}, + "spell.forest_of_thorns": {"category": "spells", "sounds": ["ebwizardry:grow"]}, + "spell.freeze": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.freezing_weapon": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.frost_axe": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.frost_ray.start": {"category": "spells", "sounds": ["ebwizardry:frostray"]}, + "spell.frost_ray.loop": {"category": "spells", "sounds": ["ebwizardry:frostray"]}, + "spell.frost_ray.end": {"category": "spells", "sounds": ["ebwizardry:frostray"]}, + "spell.frost_sigil": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.frost_step": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.glide": {"category": "spells", "sounds": [{"name": "item/elytra/elytra_loop", "volume": 0.6}]}, + "spell.grapple.shoot": {"category": "spells", "sounds": ["random/bow"]}, + "spell.grapple.attach": {"category": "spells", "sounds": ["dig/grass1", "dig/grass2", "dig/grass3", "dig/grass4"]}, + "spell.grapple.pull": {"category": "spells", "sounds": ["ebwizardry:pull1", "ebwizardry:pull2"]}, + "spell.grapple.release": {"category": "spells", "sounds": ["random/bowhit1", "random/bowhit2", "random/bowhit3"]}, + "spell.greater_fireball": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "spell.greater_heal": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, + "spell.greater_telekinesis.start": {"category": "spells", "sounds": ["ebwizardry:aura_start"]}, + "spell.greater_telekinesis.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]}, + "spell.greater_telekinesis.end": {"category": "spells", "sounds": ["ebwizardry:aura_end"]}, + "spell.greater_ward": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, + "spell.group_heal": {"category": "spells", "sounds": ["ebwizardry:heal"]}, + "spell.growth_aura": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]}, + "spell.hailstorm": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]}, + "spell.heal": {"category": "spells", "sounds": ["ebwizardry:heal"]}, + "spell.heal_ally": {"category": "spells", "sounds": ["ebwizardry:heal"]}, + "spell.healing_aura": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]}, + "spell.homing_spark": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.iceball": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.ice_age": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.ice_charge": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.ice_lance": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.ice_shard": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.ice_shroud": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.ice_spikes": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.ice_statue.shoot": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.ice_statue.freeze": {"category": "spells", "sounds": ["ebwizardry:freeze"]}, + "spell.ignite": {"category": "spells", "sounds": ["fire/ignite"]}, + "spell.imbue_weapon": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.intimidate": {"category": "spells", "sounds": ["mob/enderdragon/growl1", "mob/enderdragon/growl2", "mob/enderdragon/growl3", "mob/enderdragon/growl4"]}, + "spell.invigorating_presence": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.invisibility": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.invoke_weather": {"category": "spells", "sounds": ["ambient/weather/thunder1", "ambient/weather/thunder2", "ambient/weather/thunder3"]}, + "spell.ironflesh": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.leap": {"category": "spells", "sounds": ["mob/enderdragon/wings1", "mob/enderdragon/wings2", "mob/enderdragon/wings3", "mob/enderdragon/wings4", "mob/enderdragon/wings5", "mob/enderdragon/wings6"]}, + "spell.levitation.start": {"category": "spells", "sounds": ["ebwizardry:aura_start"]}, + "spell.levitation.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]}, + "spell.levitation.end": {"category": "spells", "sounds": ["ebwizardry:aura_end"]}, + "spell.life_drain.start": {"category": "spells", "sounds": ["ebwizardry:dark_aura_start"]}, + "spell.life_drain.loop": {"category": "spells", "sounds": ["ebwizardry:dark_aura_loop"]}, + "spell.life_drain.end": {"category": "spells", "sounds": ["ebwizardry:dark_aura_end"]}, + "spell.light": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.lightning_arrow": {"category": "spells", "sounds": ["mob/evocation_illager/cast1", "mob/evocation_illager/cast2"]}, + "spell.lightning_bolt": {"category": "spells", "sounds": []}, + "spell.lightning_disc": {"category": "spells", "sounds": ["ebwizardry:lightning_ray_start"]}, + "spell.lightning_hammer": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]}, + "spell.lightning_pulse.spark": {"category": "spells", "sounds": ["ebwizardry:lightning_ray_start"]}, + "spell.lightning_pulse.explosion": {"category": "spells", "sounds": ["ebwizardry:shockwave"]}, + "spell.lightning_ray.start": {"category": "spells", "sounds": ["ebwizardry:lightning_ray_start"]}, + "spell.lightning_ray.loop": {"category": "spells", "sounds": ["ebwizardry:lightning_ray_loop"]}, + "spell.lightning_ray.end": {"category": "spells", "sounds": ["ebwizardry:lightning_ray_end"]}, + "spell.lightning_sigil": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.lightning_web.start": {"category": "spells", "sounds": ["ebwizardry:lightning_ray_start"]}, + "spell.lightning_web.loop": {"category": "spells", "sounds": ["ebwizardry:lightning_ray_loop"]}, + "spell.lightning_web.end": {"category": "spells", "sounds": ["ebwizardry:lightning_ray_end"]}, + "spell.magic_missile": {"category": "spells", "sounds": ["ebwizardry:magic1"]}, + "spell.metamorphosis": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_mirror"]}, + "spell.meteor": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]}, + "spell.mind_control": {"category": "spells", "sounds": ["mob/guardian/elder_death"]}, + "spell.mind_trick": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "spell.mine": {"category": "spells", "sounds": []}, + "spell.muffle": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.none": {"category": "spells", "sounds": []}, + "spell.oakflesh": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.paralysis": {"category": "spells", "sounds": ["ebwizardry:shockwave"]}, + "spell.petrify": {"category": "spells", "sounds": ["mob/wither/spawn"]}, + "spell.phase_step": {"category": "spells", "sounds": ["mob/endermen/portal", "mob/endermen/portal2"]}, + "spell.plague_of_darkness": {"category": "spells", "sounds": ["mob/wither/death"]}, + "spell.pocket_furnace": {"category": "spells", "sounds": ["block/furnace/fire_crackle1", "block/furnace/fire_crackle2", "block/furnace/fire_crackle3", "block/furnace/fire_crackle4", "block/furnace/fire_crackle5"]}, + "spell.pocket_workbench": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.poison": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.poison_bomb": {"category": "spells", "sounds": ["random/bow"]}, + "spell.possession.possess": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_attack1", "mob/evocation_illager/prepare_attack2"]}, + "spell.possession.end": {"category": "spells", "sounds": ["mob/guardian/elder_idle1", "mob/guardian/elder_idle2", "mob/guardian/elder_idle3", "mob/guardian/elder_idle4"]}, + "spell.ray_of_purification.start": {"category": "spells", "sounds": ["ebwizardry:aura_start"]}, + "spell.ray_of_purification.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]}, + "spell.ray_of_purification.end": {"category": "spells", "sounds": ["ebwizardry:aura_end"]}, + "spell.remove_curse": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, + "spell.replenish_hunger": {"category": "spells", "sounds": ["ebwizardry:heal"]}, + "spell.resurrection": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, + "spell.reversal": {"category": "spells", "sounds": ["mob/wither/hurt1", "mob/wither/hurt2", "mob/wither/hurt3", "mob/wither/hurt4"]}, + "spell.ring_of_fire": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "spell.satiety": {"category": "spells", "sounds": ["ebwizardry:spellbind"]}, + "spell.shadow_ward.start": {"category": "spells", "sounds": ["ebwizardry:dark_aura_start"]}, + "spell.shadow_ward.loop": {"category": "spells", "sounds": ["ebwizardry:dark_aura_loop"]}, + "spell.shadow_ward.end": {"category": "spells", "sounds": ["ebwizardry:dark_aura_end"]}, + "spell.shield.start": {"category": "spells", "sounds": ["ebwizardry:small_aura_start"]}, + "spell.shield.loop": {"category": "spells", "sounds": ["ebwizardry:small_aura_loop"]}, + "spell.shield.end": {"category": "spells", "sounds": ["ebwizardry:small_aura_end"]}, + "spell.shulker_bullet": {"category": "spells", "sounds": ["entity/shulker/shoot1", "entity/shulker/shoot2", "entity/shulker/shoot3", "entity/shulker/shoot4"]}, + "spell.shockwave": {"category": "spells", "sounds": ["ebwizardry:shockwave"]}, + "spell.silverfish_swarm": {"category": "spells", "sounds": ["random/fizz"]}, + "spell.sixth_sense": {"category": "spells", "sounds": ["mob/wither/shoot"]}, + "spell.slime": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.slime.squelch": {"category": "spells", "sounds": ["mob/slime/attack1", "mob/slime/attack2"], "pitch": 0.5}, + "spell.slow_time": {"category": "spells", "sounds": ["portal/travel"]}, + "spell.smoke_bomb": {"category": "spells", "sounds": ["random/bow"]}, + "spell.snare": {"category": "spells", "sounds": ["dig/grass1", "dig/grass2", "dig/grass3", "dig/grass4"]}, + "spell.snowball": {"category": "spells", "sounds": ["random/bow"]}, + "spell.spark_bomb": {"category": "spells", "sounds": ["random/bow"]}, + "spell.spectral_pathway": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]}, + "spell.speed_time.start": {"category": "spells", "sounds": ["ebwizardry:aura_start"]}, + "spell.speed_time.loop": {"category": "spells", "sounds": ["ebwizardry:aura_loop"]}, + "spell.speed_time.end": {"category": "spells", "sounds": ["ebwizardry:aura_end"]}, + "spell.spider_swarm": {"category": "spells", "sounds": ["random/fizz"]}, + "spell.static_aura": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.static_aura.retaliate": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "spell.summon_blaze": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "spell.summon_ice_giant": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_summon"]}, + "spell.summon_ice_wraith": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "spell.summon_iron_golem": {"category": "spells", "sounds": ["mob/wither/spawn"]}, + "spell.summon_lightning_wraith": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "spell.summon_phoenix": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "spell.summon_shadow_wraith": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "spell.summon_skeleton": {"category": "spells", "sounds": ["ebwizardry:summon1", "ebwizardry:summon2"]}, + "spell.summon_skeleton_legion": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_summon"]}, + "spell.summon_snow_golem": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.summon_spirit_horse": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]}, + "spell.summon_spirit_wolf": {"category": "spells", "sounds": ["ebwizardry:conjure_large"]}, + "spell.summon_storm_elemental": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "spell.summon_wither_skeleton": {"category": "spells", "sounds": ["ebwizardry:summon1", "ebwizardry:summon2"]}, + "spell.summon_zombie": {"category": "spells", "sounds": ["ebwizardry:summon1", "ebwizardry:summon2"]}, + "spell.telekinesis": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "spell.thunderbolt": {"category": "spells", "sounds": ["mob/evocation_illager/cast1", "mob/evocation_illager/cast2"]}, + "spell.thunderstorm": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, + "spell.tornado": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.transience": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.transportation": {"category": "spells", "sounds": ["portal/trigger"]}, + "spell.transportation.travel": {"category": "spells", "sounds": ["portal/travel"]}, + "spell.vanishing_box": {"category": "spells", "sounds": ["block/enderchest/open"]}, + "spell.vex_swarm": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_summon"]}, + "spell.wall_of_frost.start": {"category": "spells", "sounds": ["ebwizardry:frostray"]}, + "spell.wall_of_frost.loop": {"category": "spells", "sounds": ["ebwizardry:frostray"]}, + "spell.wall_of_frost.end": {"category": "spells", "sounds": ["ebwizardry:frostray"]}, + "spell.ward": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.water_breathing": {"category": "spells", "sounds": ["ebwizardry:buff"]}, + "spell.whirlwind": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "spell.wither": {"category": "spells", "sounds": ["mob/wither/hurt1", "mob/wither/hurt2", "mob/wither/hurt3", "mob/wither/hurt4"]}, + "spell.wither_skull": {"category": "spells", "sounds": ["mob/wither/shoot"]}, + + "forfeit.burn_self": {"category": "spells", "sounds": ["fire/ignite"]}, + "forfeit.fireball": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "forfeit.firebomb": {"category": "spells", "sounds": ["mob/ghast/fireball4"]}, + "forfeit.explode": {"category": "spells", "sounds": ["random/explode1", "random/explode2", "random/explode3", "random/explode4"]}, + "forfeit.blazes": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "forfeit.burn_surroundings": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_attack1", "mob/evocation_illager/prepare_attack2"]}, + "forfeit.meteors": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]}, + "forfeit.freeze_self": {"category": "spells", "sounds": ["ebwizardry:freeze"]}, + "forfeit.freeze_self_2": {"category": "spells", "sounds": ["ebwizardry:freeze"]}, + "forfeit.ice_spikes": {"category": "spells", "sounds": []}, + "forfeit.blizzard": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "forfeit.ice_wraiths": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "forfeit.hailstorm": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]}, + "forfeit.ice_giant": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_summon"]}, + "forfeit.thunder": {"category": "spells", "sounds": ["fireworks/largeblast1"]}, + "forfeit.storm": {"category": "spells", "sounds": ["ambient/weather/thunder1", "ambient/weather/thunder2", "ambient/weather/thunder3"]}, + "forfeit.lightning_sigils": {"category": "spells", "sounds": ["ebwizardry:conjure"]}, + "forfeit.lightning": {"category": "spells", "sounds": []}, + "forfeit.paralyse_self": {"category": "spells", "sounds": ["ebwizardry:shockwave"]}, + "forfeit.lightning_wraiths": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "forfeit.storm_elementals": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "forfeit.nausea": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "forfeit.zombie_horde": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_summon"]}, + "forfeit.wither_self": {"category": "spells", "sounds": ["mob/wither/hurt1", "mob/wither/hurt2", "mob/wither/hurt3", "mob/wither/hurt4"]}, + "forfeit.cripple_self": {"category": "spells", "sounds": ["mob/wither/death"]}, + "forfeit.shadow_wraiths": {"category": "spells", "sounds": ["mob/wither/idle1", "mob/wither/idle2", "mob/wither/idle3", "mob/wither/idle4"]}, + "forfeit.snares": {"category": "spells", "sounds": ["dig/grass1", "dig/grass2", "dig/grass3", "dig/grass4"]}, + "forfeit.squid": {"category": "spells", "sounds": ["liquid/swim1", "liquid/swim2", "liquid/swim3", "liquid/swim4"], "volume": 2}, + "forfeit.uproot_plants": {"category": "spells", "sounds": []}, + "forfeit.poison_self": {"category": "spells", "sounds": ["ebwizardry:ice"]}, + "forfeit.flood": {"category": "spells", "sounds": ["item/bucket/empty1", "item/bucket/empty2", "item/bucket/empty3"]}, + "forfeit.bury_self": {"category": "spells", "sounds": ["ebwizardry:rumble"]}, + "forfeit.spill_inventory": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "forfeit.teleport_self": {"category": "spells", "sounds": ["mob/endermen/portal", "mob/endermen/portal2"]}, + "forfeit.levitate_self": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "forfeit.vex_horde": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_summon"]}, + "forfeit.black_hole": {"category": "spells", "sounds": ["mob/evocation_illager/prepare_attack1", "mob/evocation_illager/prepare_attack2"]}, + "forfeit.arrow_rain": {"category": "spells", "sounds": ["mob/illusion_illager/prepare_blind"]}, + "forfeit.damage_self": {"category": "spells", "sounds": ["damage/hit1", "damage/hit2", "damage/hit3"]}, + "forfeit.spill_armour": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "forfeit.hunger": {"category": "spells", "sounds": ["mob/guardian/curse"]}, + "forfeit.blind_self": {"category": "spells", "sounds": ["mob/guardian/curse"]}, + "forfeit.weaken_self": {"category": "spells", "sounds": ["mob/guardian/curse"]}, + "forfeit.jam_self": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]}, + "forfeit.curse_self": {"category": "spells", "sounds": ["mob/guardian/curse"]} } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/sounds/aura_end.ogg b/src/main/resources/assets/ebwizardry/sounds/aura_end.ogg new file mode 100644 index 0000000000000000000000000000000000000000..89170073a3d36083545f4ad16811a5342b6b750b GIT binary patch literal 51608 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∈6Bs*8B|w$x@u$k3AK4Z*89ugHJO9HGu7yqV3A~(WY5z+SYEI7hZnk z{Q4XJ?!IuhZg-no`t$DnPmks6%3mZ2TIJTPI(f8xudA%tmL$EuX~O?rEPp4(^{kE6 zZnmY*x%n@RPa5ZRWmfHKoGj=XSDRYY@MdmkdEoxt&(=;(vtriEsjaDLxL5uyX!^4W z%+5{Sy!jK4b2k3`bTjFDD&PGzt4^OZx$gIu^|4lP%H>MuNmJLg{NBxPfAsfL`FC<( zw7&~1t8R;%$-8pL%f`>l`k~Iv=byd3b;a?!CFg$gx4CcMrV6DMuAdVhi^i-nBJ=Q8i}I6u(ewL$*&Qy1I-E3QQB$ zNY~!eyO+A=@h{VfpHvc9l8@cH&L5~EpjF{_#$!)~^B#7F8=no+UT3e3T;X+c%4r6M zJ9cM-6Q{4Y_!1}1a6rE3x7q60b=S9grtGk}m3IH;>DlrBZg+32314>FT}=Pa$Db$j z_iJ=F{1jTXT5jI#xy}VUPVTN}EcB3ZTK)5!f};Ailiyw}G*_Q|>)M8|YDay%eCrtf zx8GcP@a4P{Ec+T6+6pIW%3j)7FKc!%?bpd$X=M{X?)OvO#ck%fa20#oyBsBtXE!6a z&+)Qa|8HjIth-M(s~F~d{WSZWT-srt1>y{bnj0^~9Ns=z{<^GmLQKWJ@LdmmpT1nQ z@XM7YRpnuKoYm?-Ir@Gt2ocR*_2k=jg9NuX>$N|pfA4WJvbpdhA!g#ru5Wg_#TjC= z?5@V%Z##1?+E#z^<43b1-&}pZ>xH&;aVhWXYq38fORrp;J6l@WZ)MKZfYh%ZR@pKh zwMzvub5HNv|L*&(4Gl*fSZ^lmWnySxVL#RPr%cE$E$8>IgTg*evTX**^S{Tst>|=F zpzLm%xr%iIqh7w-*|hNbahs9sYcV{vspW5exA5gIL_`x{=d9Q z39BMR>@@$Z{Pq37jMX=GKWw*~khLj&MRr8s+o$vP{ZXCPR?yyCe<(A_BQ3uu?(p5O z$_qZutLjU-$?mxT~UY?!Hc_l5cOlH}vm{skMR#k0~da-Bo8S!^f%d;+9 zZ=Ut$iIOz)6;oH0St>8*<@mD+Td%j?TySFM9p<;Il024OcTGYYd_OZysd$b(iEeczyPKJn)D;~EpM_q$1NH4E7^#V447 zfg$0+q!9m~oBJ!Yw!D6rYZGbpo;}RzXbBYl8*d_hoI;ef;tE3g=r^`{ovP zs_J{yJkb{N^6`0+UM*i$WK;FvRv)6-_pIim-#bspAC**6%fgK+1u`I!ll;OAzid$PUp?vMy4g%>Nq&ykvmE~H7d|n$ zdDE(yMUz#Yr@f8`k0r3qxrrD{;A3E5uw0n^k~#N(!}WXC+nKJ)KRKi${c_i?%~rzq zCLegW*YfPbldBW{uH@DVJZEca%J5cou7jHMtR{9ohIr${y;ZNjwYNTrU3>q1Sl+e6 z;vzP`Wcb@!zySke7Ot1It+r51Ar!$}R&UyW+y_UMuN9_6Kodx;w_HkyrBP$-C zoBCdmIVEL-{r`P=du^v)K6C#6^Z17kAAT;W{P*zRmWX>kN8hXsI(N1He}3M+_&Uoo zH}7jts}2{7cxO5P{r~jdcjw>#fBa&f*Jb9*kAG;K4gK>weqDOZ-2eaT=TEGzn!oVV zzd3g&Pc62)fBt5!q)zi<3!|>)0Ja66-WYE^`|0=^!)mz`rxq0{g8fo7#e51X-dj8#%x05GqJt<=2e&*`AXFGQ>+1c6I$&^@{ADG&H|NsAZ o#vPieQ@-B2JL@*n-@s`Ha#YP0OT3-b!`Pt~wJTfQfnhNN0E#=C-T(jq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/aura_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/aura_loop.ogg new file mode 100644 index 0000000000000000000000000000000000000000..616ed77c19821ed9ec11d24d5e405627b4865e56 GIT binary patch literal 216380 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/aura_start.ogg b/src/main/resources/assets/ebwizardry/sounds/aura_start.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1736c3bb0b4868f59eaad9ee0325284a7bcb3b7c GIT binary patch literal 18824 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 z z0Rv<6#r&ofD}p9oQffHCG+~n9?Q9VB_;h@qKhJT$Ru1hZc=X^S8&p|GkSy!emz4Tx6R;zwQrn%!1ma_HR zwKQL1TK6XYWH5%>pwi@u6upoq?;X^XU~!>IJ0uIQIV;|3$dA-9w@xrlQeTd zgk-4Og0ixSiaNO=%)#QF9~GF46PzzKCNT)72e$G?waj-h^0Wd>EJYO@5Vxn9s$0kMvcjg$%3x=+-&Y)O1GUdg;%I9>{)VU z^&;kywW8cgQC^D;c)S>fy1H&2z$B;DR;*R4y7FUl@z-^eP+5Y5-5#8BlTv*i?n%L5lP z4(=7l0_qpqXSpzAGO_A7|oa%B35gL2)L|fQaIhs#dAX=Kr~QP zU?t0hh7K`lmIg+Kf0ZJ>$2R{L4w_nXwQJ3h#qQT#s{YkGMX2PfH&6W`bZANKk13^H z#&cEbd=w!Qmn%+Ltd+ccQloBf?bg>qr+&@bW~R0M%ml@aA2x3GH;US5o;=0!meFcg zH?6?Um$$9)d8g489jO`C!MY)rTa?|kii6EZU!aoHQ7K`q;JhVDiy4?6d2u+fY0dld zyhVd&MdCs(Wi!4Vt{qGVm;@M-uUc(Y@^BMYTC|a2mV$O?hZ3u+)0&Khi^Z%b7UkA@ zN2xHlGAf4@CP{HcUHM@m;It-U6DwDTL(?tWuZbSKoC_Hk7^ZOT;@UgIbM*-mHV=Vb z9R`&Hj(3(M^)fPS5WScw7`nCh^xaoSCae{ByDTdyMwVTMfni^!2(SB$|JJPY684-? zeruBY&p-KKFl%z%#EBQh0`J@0+|(ssoa5J1W>m`sE=V#sGXK1qvub;9nqiO4>7L|i z)4pjROE`W1-HbfTYd4mi`WmybOUL8xi%s`mvrDaZ+8g$=YE7sh!{s=ylUS%(FQdvcB zZv(>)#sgZREKZT_N2VM+vrLa^r67-yW?O=q)JZonvCy{$N>Wt@VjP)~GN$Vo6FPZr z9r8%gFko!3sE-m;%n%XKWnhppQIfi-wTMYvw1US%z>%ZjqGFS)i(m;?gtmYc&uvi# zyR0|dJ@J3%Pmo)*T-~7Sx5+ZW_U`|}LN>Nq2_oN}B2)6-#?2Gh$gf|w_FRYy_ZQ2e zM@LG*VbZYV_Q%}m(X}Rd#~8Y$R;ZtUo00WRwoK>nSZpYHn zulB6D8`pfJFV$DldDB~-+uJTD#Rg7cjj*2}X6<#lt$?Z8TrEaRL?K1+^&&OiRXQA& zTni4|5bM!mVGt2L?4Xi8O-)emfDxO+g98=;kq$Tbq&Zl=3ePNf81`kF@E$w<|MHeNt$I6wbnSJYUs(0^{a=2;^Xd8E zn6+EXm6{9JSL zx(+O^4vXf?9h-ai+3eolRMmJ%o$7+AS2qQfWL#gkW+T_>Ag7S_MrT&0E`tRHfgIee zTeTWF9Qv;(UF=>V#?rY#g&}3n-|e1VcQv}LR-KTVoA>lmk7Gy1hEpvPi5!=lB$yaI zTs+KrC%sXe;CzYib3*rqN&R9X0fC~N2LinndR#B&ZZK?e4g3;zL`gxyp~1i*r6J

    z_dj@WR} zP;lCLQ#1LU9)(;%)lSQL)ENY)?^?w!#mFEaI5~L>tJb1^5rZa$ZCM*K1an*+Hu5>J z9265=dWL~vUS^5lvbO)iYJVE1p7UAkZDIKDJ7ayq(a%mV$~W~c$qw#x%X@Xinhl&D z%C4zg%Pha#(=W}>t1v72#*E(9)~AmB9xpDPuuFKN;Qf2gTBD#H{d=Pp&klON`_|=4vq zb!)h#D8@NWhk-@(qDNzd10(B!UupLpjDXb9?FSsSaZeW9UYV}~dcb4enPSOi1S z^HmzWTD@8lCqA93x;V>eYv>dfMI#|IAq6oury~*viX@aO1sJ#RF@!8@-XUVPfnhV# zTB+sJwH%}ad6_R=N)s^n#Khzv>Sea=%>jnYw@fS=0)C9F8mrtxHe6#^^`ffMF0+Ky zwf(>FDb?xgna>~ON?#JFBH{aA-QoAaiK;(0DO+t^>%3?2%(I${=KgpH4jcxhzOdIN zw{!E;y{;O}j`Dr`J=Y?~J1(mFRMqK!IpU9x`c$dE@eTg$5)!EObWVxRYCAsHooy|l zi@GmO5IA^FAUvUg(P7P#U#>yhk8r9BtT4Et@K8u;D(6xM0jnt?-!v!Xf8}CkXwYid zI747_SgI;(MlOr8)*?oR4GBIo7tHSMX<(8tzUH>}RZwW`!v(Kbwj3>6Q=Y&aF`wT z_}fcaT^WI3le;Z^;b%bIXoiLvuktcd9~k_cbE|Dbp8{K#h7fmJ%KeEyVy7steP?x@A@?Jt_Mbo%5Dsgj9YSSXdIcz5nF&fSIvw}_g z+dj9})=*lX_AdCK|9Yv_nTqzC)5a=;#kn(b#&je3?Age~$lB{{{X_ z{pbD92p%aB{V)1o;=lNRq5rb~#TOoBTA&aWI6;)@UIxqNnTh|aFEm<2d|YF4%GE99 zzwHZ$IcqBR2~K2PC$pXDOG5PPCoCrvYrWoi1YdjvwoGBs(=`j(=k4D-m2qYI&GIj6 z-q`2Z`C6|NSjmtjb#F;tM6!9cx^c=8nJZRJv*M;ymF->RczxDn`v+@UCYbm-_^326 z9aTy25lPe2b&U{P`*oFoID?bY9$qgehWRP)f-+-7S`Kk0Gh9ErAZ%Gr10Uzo0H#^j z7UfJ}O_4KWQJ8j4qeNVa*XiPd2o{#B*SM4E6}LMl=2|^m{_FMYH@}6LxE85Nths5Ea;?X{{%DG2k*z{-n6Hf6 zrk4fM2TgQ)H*p_bvq6GM!sUTTLSn?xl~Wd(E|AD@((YJ%)QmwbK!t&O0k2NS#E4Wa z4v7V)R_JVAk-6rE0z(HwZuE+^8KG>6t&P_{#Xm@o2Psaz*z?{e)uGQOk5(ITJ zdOCU|0!&vmY;@EX=t@l4&?Ipnf#r#nL!ipjtEF!J7NX`yPBml;pP1Nr;sbYR!zt+v z2@DPl5(gB7oRY7JFeS$sbJJ0sL)f>vapSI;*+E}+O>)A8Y*_F$gltPpg zi+FP`Z%v=IEcBR6+{P^zY%Yof=cJ!tKH0>x?2vU<-Rd<#ZFLM{jN6VdZAeSE>^j)> zXvG)5$obqGIUaE(6|4|+bINisa9AiVa?tOhikS+Fgyx|@O;PrU4jzUBl?DeIoN^dg zCwNRNWH!*gnzfQCsr__|!4|D!iX8{GNr!lylxy9_+rY6vBGKsC^D~PZ1RDf&%ye!z zF|xU)@~>++uz`!SVS@JwwuV)j+$>q%d;6MLxDpguOE>BWGK9QLXJD7hoN_ny*8jGB z6Rq_&P2G9vh5KBu|Gmqm=9p;D&sPd|nfTZxb*ABl>hyl*h8brJ_gb8D==L}o4Gx+G zvo?F5IPHJk^NsEO>zn2FZ_hVbwO9FXxS=c4%@om@*Uc3i1z0!ke|T?m-ml}kiazXG zeC&Hl?Cz7M1@WbGH-Fw-p0&}+bN6C}us;(x#09v*PEMQJAa;IA!;KxOI;TBc9ZeZD z4BT3KRT+G$IvG8hFSsx{Gh}3!v?#4yvB35LM~||MQiowxvOq|Q=&GX~ZWpJCHEMRm zHKh5k4_M)#x#-ry{zjcS*=`yPE{8gKr<4RP;uPDsD0ayP-319prfrzOHmB;KGfRWO z3ZL$*Pn`-oTPEI7`|u?pktw2sSDs;C#+1P2y#IT*iIi7`Xy;wjSnMbLPdYX8iQkU2 z*4Sw|?Q0h+3s;u0Rat56gM`M7%s&n_&*djy-dq^Qa@JKqRi^s7ghcYKc}Dv;2EI9F zr1blmY~)Fsmw7Y9%x1AiuhF`^=3~$e=S7A``P}$IM=>;S59@C zn4RCW?SJpbjAvy*i!Zny;ihuu50#01uC zneKCUV$kK^ou~RbUa*Dv@A(qP`N+iQNg9s;gQFS8ZNBSQBzTm>xYbI2oJ^S~lpJtW zLCUq~vdasD$%d{|cfCKTVIZ86Av~#3W81YR4kl3!&xN8AFaGYA=PfdbvYOH{`R?s$ zax(-ux)^kwI*yc0+yDKBpkGnf=@g^Wwd>{#YP%tu>Ad4kS_#3bfy+dB+!_xtF*3EAF)}qUeK9e+D(a!T z#_aTq4GStFIa9f!SY#c9xfvPc92HI_O1PEZ<}zh9UbTWXb(&PF)8ZRay&V%08*cDT z-bJuS6%(nQ^mwhL}8E2cEO_h~RR zblSn-)SMyUpa7a&kjqH%JZJMe-)F7brm268FDa>?|0iuS>qOY6-VkW^CIj5i=&5YScd!3 zT{j{`l%)in-W*cAq3EW;`gCK7!ZZQb&}J3^ftmjQj>yJNSk+`Ls{GbVgpE;SgJUa0 zGmp}Sf@@8woGd@g8wv!RqZlTNr=LG<)Owqjp)TXfRh72?8;YBYA_Sv%+AHg(i5;$= zvDLHuMnbB-@|UWe%RhY)$!< z!KCC7HL*9Zg1a&$W`61SoxSPH+IeSR`gFNF{_Bz7vqI*j*-6IpWa+)}`COAXmvg4{ zuOfxcKGiU$K)(qNYG({L^|)y>H6^?|DknU_w83p-YwME@;sy!UDGdh{)+;h8GdMO+ z=ah-swX4UlDOaF3%Tq_UnKee#Wx@o9gH6vaI$um$%)!BQqsvsINrCB()w^X2niLq$ z*qBEhlU&ZQK*u8C;nb~+f9fR92B;)7C!J(k_-mobnJ0%BgdX$=Xi4TM6fnrDbaXH= zq}XMoTs5`*+rDwjj09Eo-W^M}-LB8c-6^~v>|0Y^{hPzbIcL27|6CctNb!wMc%-Xa1?`O?iTW@r&uQI9n z!)K3qy-}vW)T|eto^fe?xL(q|8Qq25q3z{HOATjj5;0tol_DeImbUh!0#kNc%EUYU zficNPEEGHZ^Ike5`;Y7FO10AtjqqiMt@o30(T)~nU#QwnGfQ4>K2gB@_ zCuYSlN;e#EU}+FM-Eo0WlF{jqb4G$F0|Udobd{J~zi<7^l>K6S3o6|%ExCE-pJ8dV zz|S}rp_MZ%Y>nR}mn1UI+MW`goElmd_Blo03J7*7sT65hX~1mM#$z_ogW>c8EyE)xHI}CO?B?=fXIi&@ zE0bc$*5#(sQYQj zroQr0hYXe< zC~#yv^s3RZka5L|nGsv_x7(H7yvTG+g41BB%S8|MV^?0}9_e5x>R4FOdP}fV z^i*P*+Qez@8W_;=3U}EEGiP$K+Wb+IGMh#wu1B?e6bGtbWBPJSN zsy|-Z*tLttx`H7{yP;>HH&g!`c>t9KQ6xqT{vF`g0s9TGv0g zuk4-Hyx|^8wQ{EajqCHGy~-4~_iYSyP?%~wBh;AN37ljE)YmOf{q}JBms3X;_)g=z zePc@QrS<1H7@D}wWnNd-Is3Wo>ZT1Jd-g8BvSQP!Z>RN7zcLEWT)KX9*#@tLvO7;Q zxGy8NL%B>Gx;N>vS9v z8gC0jCu8CPt}6!Op-xf)9ASwOQ?_?&C^!pCMm|M{zD)3Pf+4&O?#w7SXin~mYXgmcys*KQiVQV&eHb;SITA$V|r zfpM?P`IpnxnJ+tbMYXdnvhjK)Gj~$5SslasU=bf-txl=9Yny_kPlzY2w+g!acay;X z*4$){IqU1Uu01fz^lVL0aq_|oSzRHmGUc98*%}ftoZTtTi7%42t!7bO86pz2CP_Du zK}(vOrDJKHO>RI=py(Q1vCESddU`bI1@>fU9?I->WO8)iV(BtuO5uz=^nKO|4h;_0 zrY|2=l(JTTZBBCR>3CJtCg_l?<7T47@Sy*`afGHaGoPa%gZ6zdE?xio;>SO%7S?qY1%*JZBX_rI} z%ll5g>t=Rg8`mzDy6iRHu*b{^JioW9X&S#~jOQVtk5VF{rK$DStIt?o zH$B-{zUkSt>T}a>$a&^%P zYVF0Qg!Nnp7}zH0GPF9}40HkIZ6O9D2MYtC3nIczEJ8~TF*V%T z!ki!_w}F8HJf6UCKp*U3@ZJ)31_p*VTifzv|BLHot275_{Am;0~! zU-7@vf7So{(o+nVrvG1XG*4aoy=3d^mxtwjyOS47J!qZa8vj&dndipy59c+!Oy|4T z`IsSKyVGG$XI8Ks7hc?XSF<@kS!e>IkFKeG?P~+U5XQ2V+K#@Gryng9^cCtp^Zn+x z$k^+8C;3lLDBX5H%}~I_SGHW)?B%Sf&o-Rj9UZQ_N}^?=Npg&@!vfZeBHIKvIK0T4 zwjz@=QE-jXg3JjO>mzhLB6SoPG9E{{@q4ZHYQLzfl=$hVNs8N>Y=xEuMXjrfHBI$4 za5HqfY9#tBJ9ug`&!n}gyORy?&Rz1Tr$u36PsXJO<&4b-`*_%tE}T=mqyn%{N4h7@Dt{uwiVa0P6|Rj62^Q)}r;olkV`Di#WjF73o1ccZRo9Pw{g8Be z`9rbpYfD@w?NVY2%Pr`*b&Tym;sGiDQw&0hp% z6Fd$q55hKDm9BmD)g|HRF{URD`bvtER^13v=+0D4)YvHX`{vmxR$NE7-AKG0;343# z(UEad@&bWR8zzZ$G9C31Gg4u4Gc3F`gC*^RTBJjBg8*Mb>(aMoN{3gi?Rpf&B>iIQ z*2bh$r^{tjx{ot@dt36HUL?l$Vq<;)%lW3%2c88)mA_M8cdgA5)2K9ah20Vd!+-TySM9p-xn`}%S}p#M zLSY+Kou`;GEjSm$cC;hn>MmpDu*s9JyguP~IV`*H_6DZT9LF|>>GK0G{$pzX66-0n zbc^O%C9~C{oHvD*I3G`AWzb{2(N_4F)wAlOZRQfkhJt`at2lc(dDL9)vPC=eifSI+ zwm`6T0xts(hjRNa^{r=^86?~v2~1#QaA`xlxhUO#G*pQdK|#IDxAA){;l zIfwbv*Me8gJM@;MFT3^Q-HzMR6DRXq#upxu*kkSO?&uKWC~*Bz#`;H1lB}PuEfc)@ zP{!X^zsN(*J5T3(maBBkJGGl(b-{On&fK{Acj@}#J=uF!u38i&=_;dH#jvP*s;1Y& zBKiG84Lmpb2sXmG%-pwWo%g|`qhg;C5?yS^rk3=m{zHP z4^Q%rGOSiU&h1uKF=s=poUX)~S)b$_8JYuK4+;eehW5lYGUI6?Sa^IkwL*_ z{UQ&B2$pG`3=Ev&3=B6F6B?OU&SK(ZR^;5$AT@ohgHr-S1Jhv%8v_Q0xHOk5%hUgF znDY2X%CjD&qg(#S?-D!ya&o2m#^f#OYYT6s>h&Cu73nQn6^P=+A zeE~Mxl(sJ2rI7T|(jX~8%vpos$d(>P7Y2_T6FN3nPZ3?!>w46vWowfu!=liyVZWO; z8oH=5oc&?U8W3FaY!SnYRg0uqx|ZeM-obi6>$K;B0H%zSNremyv6{iBx=%W>X*sio zu2%?4RuaA1p2FQ-YI=6p;WaOH%?;{qYWI{sX86F#5SR9(AoJP}!>wCAuk15b7Fhar zcK^a$pGDv9iK&a*=Hz4tr>;F=-Te0RsoUYk9rMpscD|HqE?D z%;(v1M@B`hBfrkJCWieh{91PYUd^4Dv^J&2UHdC5g6F+@`_5Wo-V?T2x*014v<#w_ zKVdqWuz5*!j?DV3X*bSrB{ndAX%TehP7taO5nK@HC~z_BP~S6wE0)MWnQh1Zt^6F>iD1*gI`arBy*C>xWBFo z*x`#W;(J@S>wc! z&fJWt#YY*~qQkiR7Pqa)c=4ldZ=m3pJ}XI zqM2Gh<(61^FZ)7sC##q#`99N%9!|S_|M&~e3-XKj)<>DLfPUeDbxisXgpo!RL> zBl!sDjdOY%#npQ|>x{lG)B>-T)bc1P5c2h{t=s(dOx>a%AyeM$?&`W&Xeq*IsJ<+@ zvn)8$aH3(k%xRn5=?0s^udUMEe?Pi!ug!~M*W)KVoyxkyv=)ATzgKI^%BviUpNY9~ zhIUEhM9g7J2wPzF#j}6mY@X%@xsD9i49!Tji4%poUTy9)X6#Y^z;Wq)$}xe0b_-kW zxy37YFUYl)TJUmmLh`yrSsQYXGX2nT-9JTknOxlEwXq8r4|y(jQDG}zlXiUOEkZ__2& z`5E@5U9sAx{dY$HrYQ^0zNpEG{$?1Ly6Qk{Rn(l{0wsOPj1E^GmK4fZ7P3jNk_9(! z8o0KJ{WrQMyZzw>hdF!iK2AD1f9cC--OnyZ8Gm2S)xhHDdh9)8f$3#m6}8U9{Fh&| zW?ENYnp^c|--cxFtn%#BPS=;XZOl-#=3wFo2$&)HjN!}1?Vp9WuJB;%Qkwo;b&=73 zn>I78CPx=$vkOd#EeZ_}vliC~c5O_!k-luwtA@-58@21V88>K#Y@WilX@}VCFl_|FiR*0Sl@N%?7g7Ye^l zlU(Vy@{6N$%mL}1Go2?(eWM)C*{SVKQz|rCxS(Le-mJxtgwxgAbM-{|O~dz{>$ay^ z-w6M8eCx_Di)P`mz7yk-9LYQKv26k4%LcboH&s^N@7bhfWAZbu;c|n_0*OYClnk{wV`z|5WmqO4+i<)^=%E7B7AA%ezbUS&9;{D9{dQys@gAPDWaZu6-z($4 zaLSmlE>}wHd!^K^lD_uHy=A}u+eq}(zHgUjVAz*dqPp}`|F=~JvhkY&B8{NU9xXPgZ*Oq73im$z>kEs@$`_y~R>r=;_Z$Fh?b~wFvMtF%q+DS7W ziQJiG(>a)aevDS)VO`BT^|4Hwdv*cy`dubh^-j<1x-_?>K~Q#?V^3?NBSVn}kJjnB zDyxkhZ(YN6SW7ib7dkm8NT$p5bn+y)2uyR*IkIMhs7kpety8yTIrPHRo&O4`7< zKxMZ7-KC4Xa~T*I1lmOJ3m#y~;LZ@!Vrb}KWN46FWcip)Imz)717pK;xeW~Fr>@LM zwD3;b?7H#rb@^#W88$G)rHSY*eX8u6JTr{PDD8^cw5^hv{g-6Ld!_fjogyLnZEI|{ zSxb}ciI8Yf&?x{6msjV`GLy0T_eTD=N^i8(*>h#@u72HbaeT+-FWM7d4Dz2U+z%ynfm-xE`QI96AIhE_oeaQRGrtJaeJw!R&x+f>z^MyvnxU=3fB_A=IVenqNY-L*kOHZ_e0;`#hgIjf++AG^h40=a1j&ZTFOg?qI zQis30<-jVD11}Gt>8ug4GV7KAIJCNX?dMv$@AO?Jc-3~lcfVyw^t%KTxqP$z&fC8CDVy#UbBJ}h zDt)dcMnOUA*uhUff32K(AJnqNV!`#)xFJ(b&pVygzL4Gj@oSZt}ZQ+9PXvLq2SiBlvB3)*FBfku3g*} zVDh+qqbaZ9)|{Vz6h1mf|9}e z)7tw?jrEjPuW+06rmIT3Xi{DTL(7xD=Yql=Zz-*7hzxb(GcXfmoIBw~p&FawB|)7w z5tSoc+^2s^^&MK$%jnSa-RnSG!%92P+!Gq+2h{|ZGn*!?I?U-E8`Z-)flH)zd8m-s ziWXG|0VV^<3>O1~mt{=LpPZ|fH=d_fp2r}-IOV9w*6Aj!l{cC!XT~!3OU`;(Cvl@3 zJgC9Szy+CO0xgmN)zJ>Telqq7{{#Me{&)Cq_21~f>3{407SNMJiKHH@y!_nwa%KMh z>fjf5`8PA3`7rhsIy^UkV`YMND zr91R^v>9LUJ-kJ0=1dj_hJdXNO835mJiFt{%E7Ye;^F(JR%8d>UR{5r?W1vSrezZM z?$X}V2M_n}yL{th#pYZ0mc9S~>g-=2JRkF4IRu*K&u z?_R#uFm8d9`Zq-fk>zvvmg=#{l{GRHNO*`S-)5N5>zhQpaUC)=1B+DGRiBYpFAy4h)=rJvxhzIk(!J%f?d3V5Pq5T8RS< z8>Ag3ES@2^u(fecj>d^qf}L-UPnd8)bP|K-&4aQ5DvQtVYFs!u)Zy`|JM-?{nVDo! zRwlGeTJ)^SPZ0?-9X75TyXRhC8?G<@dftJE?RmD1(^q>$zI+~8I8SuYU}j@|Vph`KMTRzoIPi#m>6++sEJV zn2NS;;{`A9x$ySWf$vv0Gl$QA@6P=9+QFCeYWMrv-PjxZ$9&)4|Es^U*4zEKdHins zRr|V!Z*9LFJQbZ)-aB`B+WFI=-yWZ?JZq^ZDb`*i?wNmd6{pUH43%Z-LTk)}!qjgk z9b9xRWuu;Pk-zb#o;fM9txA`B93tH2>|JGa>Q+|YqEkN7DHAF^H}4O)8F$>+?Z4Db zy~kgF{64g6@iO^8&n3R)FaGaudH>w*TD^MNw)BI=ho9`5z`gJD?E~*TzKM8ezh0uP z{m?j8WzO6FnG*l*o!c?D|EqOy(zSQ#Z)SYYh&;(3_vw`X^$T0S*80U+E6tqKqWF0B z&5J>o{cFC@E?2cL-6!lQ|Gqdp^tqk=)md53PJTb5)_y*~U-alc_haJs))?wEF#Sul zS^rTzgXs_ZzMkKE|9xn43fSk!ellV1?RNRa*DkL39ts|6VL0*jMES3^F;AIJXQ zpLqM5+T>^Vrk{QGt=m3bcxLa1KSg`;yzZ~5EZMr*XZmwf$&!5!FVsh+%l0?q{&nH; zdAc!q*3z_F`e!fwZunDj@pqO{FPEcvU|9{ngJ1d&XMex-{6{Xl+hl0*t3v!%f5zH$ zk2TtDOfe;kWB)rvr&y{7$2#BmZ*1HD=uRl-q#IA?=7r$G?XR*koVt^+!0>1048vdPjg#Nm-{ku+XPwN8ZzW|yQ(p&M zS=&-+Vc7b)_S2WR-8*al7#YW3h`wa`VomXaU-hfn-!H9R9bDEX$Hw-vaDVzLo8Pnk zzr4Hm&&`^;U)*JLjMELz9Z2S7*q3@|`&VYxuKI)qoyUbMzxOOUU~lk%`@pOHYYxWU z=ZlxWwgS>?WDrm&&flq(P!z$Emw-dmhP66IFAoSIE0zdAW`!#dZ55{}B5#PtTQnkkL6g$H=HL=;Ggsx+$UD z?331=TV)r!h}q)aWmRQ$=d_;5%al)Dcw)HxvBk!@n_ca{essJ%HS$VHdD!n&+W9k| zCG{M$miJLzx$E4^nM^RST!J z=qziuo@rCPPj6fNI-a~$m(Q4NmOpj(RJj@NdBe{;zQ{2!+)J&Ad3-&Usjflq@#jbT zebw}88sAzqEjDb=57~Mx3_KwGwSTYOE%99Myl-ch$uThe^Yu0>oN2vn`P1!xw0}RE z@F|#Q@69~1+5F2tPq)+kB=PB>&FR)7?@H|MhRiH+n_#W@JAbSBw6Y(E++()iJw9X7 z`FU~`b?ig2iXEe`$Kdsj_v2O0Ug>U{wvu$hC)eE2g;9rd2qkHnc&%WQ; zeroIIJCT2rs?)!oO8nKcx%uTQZS~*5?dR@&Fp{2>aV~RG!_9xmar*asMSXY6&bY;Q zXz%=8x9>lEViICqYG`>Tq}WwNbJ@z9(`I$EA9*{|O8(p%jhmMp{I9f6&dae#SW>Yn&V z(Wy;u_^0gZIq&_Gjj_pm!+Y7@ZP!-)3;^}O85jc25RC ze{Geo7|*^T#A--@czed-q)9`Jd0c zRVsYyul9HGokIIRpTp(qzCAhD^enz|+N)*1OJ>N<{kXe*W*%R8`ujKX>p!owyWghs zsy@Pev;FM{d;hD*Xs^uVn=tdv(PvT1U)Wk+u}Bwx@#UdqY;naei-j-W`JFG934X7? z%uf8@_m@9ssV?7dUjKW#deNlqD@~4+7izxWK0|WSGoPIE0y4@geCJwMfAi~Vd;Yqh zP4iFk!=w!jtou^;#Qc%I8NhKW`q=NKd%RgV_8nlA*|2_bboA+h3 zorcL%{>=IrJ@fF{^z-)ntY5!4vu5}G*&nYQ5RvQHJiqhn|FX(Di*WP#YgfN6+8bA0 zytB-IMV?*kM<27>KLXNH=I&y@G3Cd8>+EM*vl`VZ=f`#Rx#a7qU4Iq*xQKDiyHhsC zdtZBHrEN>UCl&PN$+Oq>_n%gJ=000cdg*}V+aY6{G$?Z(tsh@;O>OqM%P6+zb>`jzuV(P(hr~Xr{@-WuiN>^csI*|yUwz_rgJx| z6`ReyC%x&l?1J~Zq>LUc-zc&{zM-6*-3FXJZ=3rtJY{!36?^Rd^B<+k307rXKWbuY zSIhFQU8Mj?aW68T&0ObE`0>*prT+i>et%l=`E&B;uYXr3^Iz|`S{8XGr}*Q;=lt$> zE$e3{ZM6CF;@#}u?XPui`(EE<=j=cE`RB7jqF--4Yu0&hUsGdIRXFea%r$FRHl*1G!};LH`}&!peDd#ND$UHz^BEFq>{(-evh$Gy03PO%TmS$7 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/aura.ogg b/src/main/resources/assets/ebwizardry/sounds/conjure.ogg similarity index 100% rename from src/main/resources/assets/ebwizardry/sounds/aura.ogg rename to src/main/resources/assets/ebwizardry/sounds/conjure.ogg diff --git a/src/main/resources/assets/ebwizardry/sounds/largeaura.ogg b/src/main/resources/assets/ebwizardry/sounds/conjure_large.ogg similarity index 100% rename from src/main/resources/assets/ebwizardry/sounds/largeaura.ogg rename to src/main/resources/assets/ebwizardry/sounds/conjure_large.ogg diff --git a/src/main/resources/assets/ebwizardry/sounds/dark_aura_end.ogg b/src/main/resources/assets/ebwizardry/sounds/dark_aura_end.ogg new file mode 100644 index 0000000000000000000000000000000000000000..3e3093c18261d2ad9ae9c91a41e19f40df2c99d6 GIT binary patch literal 63140 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 ZSlI5)#}8r+&vt3VGM;mtc5vcERsaX*K(+t? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/dark_aura_start.ogg b/src/main/resources/assets/ebwizardry/sounds/dark_aura_start.ogg new file mode 100644 index 0000000000000000000000000000000000000000..04fd8be5f0cbc971a49d7e4ff9e38c502cca7b69 GIT binary patch literal 30358 zcmeZIPY-5bVt|562@uAs&3pDT$}yJZ7bRsDgM^q|)_^Dm28Ke2;vI}&olrpr29Qoh z1_p*(q4x@ftpB5diOdkAv>6x}A~Fjy^!$s`6>>6@!oU_Ncq$kf7#bNE85k>Q_~+(j z78Ioxr{o;;9y{2F!WJ4+Hhe)CVPtB!M7HU+^ znBoCq9X05jF{SgUL~@VeF&Lp>k|N5$z{1d=!P&R?nP=8H%XA6#zM=(|nSK__71+B1 zA6Rl8`l^Ta86RvoV3_;Sz6Y*%-P#AR&UEay-DZvCLXX721W)J zkZTwgWX@WKfzl$Ur4mLC87H(D9GDm!ju*-tFH~_2QaN6v!wwGN6ATO-3=Tm$M~h6{ zi%pIf+Z->paW8Q>ImPGf7axAG5(Xx4v@^!fD9pMr>+@MlzFAKf ztQ47j`Cw)DE(BD0InbxxVBzIA5^#5}N}#phPW%{h0_ z^5LA~bDg(lXYb^Uol|`7XUd#+XE{M)=*h={fq^CQhQzVCO$xPrY)K-D%M>TemGtvX zUSN1abBSDUpPSdp=71nc^`#|EV4o{6FtiAOQ!$JHCuK+~UNWgm>y*akGe)O%K*XBE z=d50DI4t1IW4Ps#myYSxu;kvY&*l}cv-HSby7gL=_R=XqUYbk6;Rnhf3MmsD*(AZ4 zq-{pgDb3{znz$gr35mE5D(3}dFCwAyA7uiCR0D-nFB<6v8{3A4goc;pMouriy}dQ| zM(O?QwfC?0#*4S1CoFi*VQ}J5Yys!VDM>ws$LBQrIdMWF7?yJiMUGFDIXO|qdy|Uq zC7rXMO#DBaToiTSA$Hi2I+=|*y7JIp`oEyO?)q#G+vl6 zm4QK$f#J!LWml^Bgpwv$b~vo^KU{&j_$=opHglRpiQ} zs4UsyknY~KDISix+l~b(K3&1?M83FSCp{Gq_M;VDP-m;48v-Rv1)y zFfcG2xM<=aZ0jKG3YDgalJR9W31l$|gcM*5Ad4=BFkUo)+T|eZdcfG#!6cL-OQ4#u z*cE8X=#ONVgNd(0h%Z$6C^Z@avwq!BcTyDucWRkcFq#hGDFfcSQvNJR=2%mC*yJ@k95Cen7 zq?AYoh6NszQW+T2IcwFaLY>o}T>?dXgF|DdKaQC8ymOJptYxcq>7Bl0avoeog_g!<%z_J>_=@;m zHVF+4jTN8utP^Cys#WW_&kMU=Ht`KDjlIsgC}Y;Lm8;gh-sJ#Rc(pWEyaOb*YS+5g zOdv&}vDc@jHe{|^wQAQo9p;cwFkf=Ps#ULctkxE3b*IC&_h1O;hnF6DC4Qk@#) z=&^K3kdc?}(rH1gic=?ftyEYN6r{<@&>(BU&>$PZ(b~3#h2awe14r_dq%)S!Rh+yG zpUo*2Qd}xge9m&ENHVC2JY|yM^Et(SUMFW1pR-h7nsUbS`JBl?R?p`Y^Lc45EjefT ze94p`rx$aIgS<577N4_ZWN?6lc2|y{flvrIxJ4NbJOD-4JoT<+nVyrDRnAkNwJbAh z(vnQD$Sj-l(9o}(2Myz**g#Oo`G%^V2F20JRjarzoA_Q12@P!pwRcyodVOdcDEzON zCf;7P3KY@@N@K5=rb_MrRo^)1hFYD z5peR*Y@L9b{23bx7#JD^pgk0`oQiA!w~V&LFpVCZq|FnpmhWs;Yds8f%nhU(O5QC(}DIt)3MF1ZqwV<>jsl6~Ql zDN$XT+a6gyU$W#%RFC1Ys2Fa=rBkB1b+<{(&QV-4B`DkQSX8pH*VZXf-G;{`vUR+6 zP6^81cvK?0*HvS7G)Ojkt*PeIV(*PtqmtKbRa@LM$?#ZI_L{BNl%@n39TN#&v-R4n z7K3BoC6d<|K98C#bm)g%u@V6(k74AOpNWszDf}VhX4U zJ{8Og@&Z{D3r=LAVSI3z$KrpR$(j z5kKQ~Hcaj!Mm`SUJbQwHL4bYZmTOU~dx}nZdaiYLlX|vb$qi3-#jO$EsS1v#JiX>N zacHuwZ0*rnI%D!Qr_(cnc#^aYOL`35EuV%s9hYEWU}$1sU=}nI<`8jcY~*3EaPXMG z#K6VPBYW7@!9h=P@qq;eJ{Ib8%@`OQJI)Anb{thOTqvcXwT!vpC~I2{!-)$wJa+GB z&|{9da5R?PiNi^tDMH49k<-HBVVnBB4=vJj76ga9asXEkatsd`85C|ZC@C$P`S`_$ z9}Jv=l8Ty!mX3m8X={cb3=AGY4ILdB&n&EL>>Qk2+&sK|`~sL57#P7dp#uXW2M1`J z0n|5UVBp|@40Jdcf%St2IzZLpN413)rCt9={PctUjJ?WyZm?jAMjuK zzuXbl^Jyy&FaEU0{DGuSplX%r7XF5*8`T&#G0ZeGVbnXkP*F*3(%hCp?eZ`SgJ}P^ z-ez~ClBYeLVp|fbFLc>y<7P9faMoSd|LnMWuRxmN+bsF-*QC>!512DJtiS&HYn7t> zVXLgPuNOI{Yu{TslZ9c+URQ3$2@?aIMBFo)Ut6W5-?DytRP|`2qt{WzQ-b0~f`N;! zFSpvIyxF59tRyS-cAo5;;@^Fj0)@n4R<52_;J&jVGu-cBh(vhN##N6J9fGFn@;(UZ z$a-<~mC>!qo`FWM0$fESrcO}Y*>q4T#3#Mi=%CZ9=_|Ls=)F_M@-iZs!N^(EgjtWn zkYTUaMZHg&GcL_|BhlCpusefKd`a-K2wTI4FOKydPEknx(8{j!uq}~MBA{x5tYVPG zQ$LR>92}FTd4xnpx-rZNnSA8IE0-H*PlhlZ(>UP4dgQ8>&~&Z^xibabxO1)vyda68%%baex_TK0_cg^RS*>wwT$&J@Gr%t}^Rvdhxe7&vi zRj~kpoQY8}PK#VcF3o4n==Ip`x+{p&OzLP4%a*em*EiXesH+s!s8<9Wy_(?1zO9b6 zEk^G^Tf#DjYaSC^*EoNgs&sqd)M7S6fvvMWJ<7MSy*hV^Q|PGWH@WFW$7bGT>Ag~7 z=w15tYM|StCn>#J*R92Ncm$ux>IqCt51m-FO(KYC`stY)mc3YB@H$~;jkEOhMQN;$ z+~0mEjn>+6_LhOCliPw%F4ugP^*WZv*6qFO=Pbq)G;^**)+1Jl80}tFhsSsBZTS7_ z{VT4sy?Z))1T4gKdp~I{o{rpuzn(6bDv~yKSM~n8I z6$yO0BPyWp$cb$tyOtK8-5HR&`NyrlY)MsRtnJD%*TU|z5)IrGHr}x| zOFuYGRVPubr$O+8xP{l{kdUP53v~4!s4~Pw{(YXV?`Z4DSf2W|eqU6xfq#im()VzN zhTJV*7w4YYV4xW}Q-zTs;|dppN@ZlRg=5Te#heA#1@3J0*}Z1dJ&T;`udh`mH-TDNbvpB`0Q`J{37;cJ3nwKn@pzHiB0sekW^<*Dl$tG92S5fC^ z`|nBierumZo19@O|6sHJ{Oj*o=k6sam_N4(n0)v5xy^I9XW3kzdUH7sd)wdcKSq(Q z2@+|+wRJNT%Xj{eOLLzb`P^i|%ssPaS(g5~f6nmlwrzjTUOB&f=8U!9ALk#G)iSAG zzWQMgC*#HGM#8(&6Y3Als1%>Q`Oek-)0@_WZOi^1S1ulF@cxG?_m9r`^|ij72X{3) z@81070w+^lPyRnit-$oE+EOhI#Why{isSqH-L5cg3@l$T&EzCgPa_jgUFO|C$y|x^ z799L|>DT+?G6DGk4}OR;Bz!)+JvUl@;aVeO1_p=OLJSU5w6#tIBuP#aa!l-Nm@9gH z+v%zVu}P-##wllxZOF}BytFm&aoF)B8@ELoo|~6>IJwOdNITBgRG71*zj0BYQ%I;% zJDWFus9KFl#>}pW>z{7f>OQkGt&E=1;Vrs6_*X=ZMffJ`m#OYYf8TO8*V!Azz1hU| zs+E1mvCH>g^W&9@4hY!0c&F*R+80aGmsa?mU1;@{$Nb43AIImKLG#L^ z9nOpNs%=|PB-9ucyZ(q(&m%o1PJE7M$`?F8lyE3Q1yPYpq zu`Kgg@a?kSCQakwhesqBx?MBkRxQhLR@!%3@UTN)fTaP0$2`x!_V;ZQ%s3wG@%&r= zcS^&}7mUx>Gce4af7nV&c~6wKCZ8H3g9EoJ!-KyZ-oFn%j}~j1^7!kIw_38&H}~E# zQM_fIn{ur=-!yf))S)Tg`%^^KkIXB_qWfdDyIbRODo>wTsFh? zTg>B4>%^SyDW#nLAk*1mGQ}>s#Jy_&jQ?_WZ(r7?F8z5XByOkN_VT~0&wI`Y|6JZQ zdvjdL$MX9X>*p7KPRzzpRdRHJiqp&NwHj(t?GHD!u?-qFL}yj zW`CT1n=vou$J+D8tC@Ejp50ft{PyzM^G_vBO5%F9T*&DDvdd?-p49XWxf_)je0I)E z8{70v#a8dm8BMQiD&^$4RKos2bFPl;)fJ+g_ay{oOfucOe5$yGLn4dZs=xc~j|*Lq z&+uFj^85b}DdtD~A`iS78VrwR)XvCvu2q{klZAod#8V~4gokmbGx(OBd%SgN_vW67 z`_7bR30&%WB(OGc_0l6c4;KaoP1q9QHq*3)S5z^3Yw}dB71M6LjZ@2$x2uin`~GeD z6it1X-GBW3&A#V{yC3n$%XepP_s|d3d+$=Rk~=1UQuLpjI}M`mPTUvD=DqG#>9d>@ zTe~O!o_&UQ|Ef1zi>}*=*Pf^{T426pf7={6(ek&e7QQ!mW54CZjQ-cJy2|CAS66+X zuxibs@H#$~z0zyCJo{LF&*7gLb7yAlubLQfYwzH~d!g#z=U5rLZoDk=c~#kSc@2xZ zEAMRdlD1eWEWOLj?eFH#zgBvGzU*Fede8Q!bE0qm=}-Lh=Hr{R6E73g87FkrEu7q; zl5EBD_*L0E`S%vaa-0<&EG>--4fq!@aWVW``FFqFa)#f`tb69)`v2LI^#;GjgTF!y z3FiVgM=jnekUD8569a?8wi65tnU8`V)%0Du6cEK1;<3(Z-Hb_*k5-`? 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 Q?$MdVoBNFR|4$b`7cW!Ye`i_Gruo*J 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

    7msS5s-n8cW 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 QYLm|COAH@1x)yN&0J>Rs$^ZZW diff --git a/src/main/resources/assets/ebwizardry/sounds/flames_end.ogg b/src/main/resources/assets/ebwizardry/sounds/flames_end.ogg new file mode 100644 index 0000000000000000000000000000000000000000..b3488b59a1aa96af874997ec807699b90cfcdc0e GIT binary patch literal 37073 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 A1poj5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/flames_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/flames_loop.ogg new file mode 100644 index 0000000000000000000000000000000000000000..634727f6c1ed524dd41d15223ae7933084f66dc7 GIT binary patch literal 285773 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%0Dt9jV^+I!2&r`=qbvP*vRnOV0C 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 GSpWde({bPc literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/small_aura_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/small_aura_loop.ogg new file mode 100644 index 0000000000000000000000000000000000000000..77c76ac2c5644e3f8df9c0eae8f616d21636bf75 GIT binary patch literal 209049 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

    9X>UE2g8wy|3Ag* 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/small_aura_start.ogg b/src/main/resources/assets/ebwizardry/sounds/small_aura_start.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9004f213ce7a7d196bb34e8825dff446dd3f79bd GIT binary patch literal 87860 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/spellbind.ogg b/src/main/resources/assets/ebwizardry/sounds/spellbind.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d14bdcdeacc182cc8d20d7bcd1b082448118c21c GIT binary patch literal 78949 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 z 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/obelisk_1.nbt b/src/main/resources/assets/ebwizardry/structures/obelisk_1.nbt new file mode 100644 index 0000000000000000000000000000000000000000..6fd0cde26cce23fa36df49e30b782891ebf1b306 GIT binary patch literal 615 zcmb2|=3sz;-f8EvZySglpP#F`(RSOr4c`B|rW$hHUMg~HuGckZ$y|NszIdU)Xs$_4 z*XDg&?*FOZqmG{&4%1Y?R!eSmcqC7v+1D;s%L_^HflUvA|{kR>wNC+xlFqY%TFJC@?I=(OX-Yj8I>n>+dCsa_PWeH zv_mXPn>XiIah2>r_Kg#~9+#F+b`|sq%W9VL78gjnaQ1G&vYOoK=S+65{bBs-bAI}{ z*06JH12&2JH0)fyJHIk)wNPVh?7i4+ulfH@-u3&-zO(D&>sr*d%$y)59(Ch+_x^t( z!ka^+^|pjh+T*7GGP(GdlyvgfsVGeIng5r+y~*xlRBP1fpcAeO|G88@ zlHh$LA)ipD-G4M4DSMo< zFV<^sl=&3BHf%*L>oS9bT-o0;wC;$0jLp5bIp*H~ O8LacJG9+^`FaQAGX&`j~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/obelisk_2.nbt b/src/main/resources/assets/ebwizardry/structures/obelisk_2.nbt new file mode 100644 index 0000000000000000000000000000000000000000..0b2ec08ffd6225bf4f89dc2b59be49d66d450d63 GIT binary patch literal 601 zcmb2|=3sz;-f52cvkgR!%Rf*#u%)y;_Lt_iuLhaBL#E!EyJ}5)R#x>)p9;@4O|m!p zBC2k=&zCju%oO_VDR|`1z5fS4-=86)z`W=Nw;IEPx|z0V6O^v|7>6+2K3Evod2{or zv-8(Ws%S5aagyiknX*i3cTcSvSHdF(wmH+>j~{PX{ruub!v}ry(!U!PG9)*%y!as@ zy_i8({;?9*jLX42uODiHR6EED9q3`2QOID-nQ*D$-;ECDYu7c^_!1Ue{`B&P#0!i0 zef@>^KG^Q=?_`#cR&h9f{DuVUi#@4D9u*6NPvo^;_`YR@z`2bXH@K%Rz4K>=ZeZru zNRbG`uXCKvcv-BLJU(+t@!dGT#yhjVe+g`UBdz<2dzoogRFH4tqOdIwHG(Cs`*ZUUX>ZNd3RS{K;7?uN2g3UG$plZ zdlRQXaXG)Pe^#KBxpUsjtw-!{=dPJtm$P*HbN{tp&#wtnytXH$Ca`1w#YQ`~X1inV zGyYCbFKUp?({pCyyCP*&$iUpky+b~Jt-#!eryoYFy?*ALS!VX^?(Q=cJz*4 Jo$ELm7yuoSBh>%^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/obelisk_3.nbt b/src/main/resources/assets/ebwizardry/structures/obelisk_3.nbt new file mode 100644 index 0000000000000000000000000000000000000000..8da474085603e27fb68b055f66a7ff07417a03fc GIT binary patch literal 609 zcmb2|=3sz;-f6!1w+(pOG`&4@_@m2jEZv{v%+7N|&$Y2^xzg)}61QU6EYpM*ZWHm~ z+Vo}1e7lqKp0iA+u}JtWY1h~EQklb?a-gTejf>%*`R6<@yk_3hXv_3)w_s_=Qcgw#rBWeG7! z{_Yo?ifTXmPd1)9v~0p%t-*Eiek((O5Vhh#sM_5aX1_waA|Qt^tnDRqm?)}`;@c`I?9Q7_i&o{Wxp P@P7t(zgJq{I2jlK%5)iN literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/obelisk_4.nbt b/src/main/resources/assets/ebwizardry/structures/obelisk_4.nbt new file mode 100644 index 0000000000000000000000000000000000000000..8353302767cdc5875b706cad9ccd3e6fa757ba5b GIT binary patch literal 660 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/shrine_6.nbt b/src/main/resources/assets/ebwizardry/structures/shrine_6.nbt new file mode 100644 index 0000000000000000000000000000000000000000..d699d08c485a46f9e0bde301bc5e0de835d953f2 GIT binary patch literal 745 zcmb2|=3sz;-s}GUw+$rNKA3mDHJkhG`G&*aG`B63Rnz0(EOY8%p4D)A%CnKF6BY4^E;ffmK}T_0v%4hUaYvUFYNEa|L0 zCX?@fJ@Mb@wB~N}(wr%Q*ua}eS6#MXU}(kyILXrOKNth zsqX5ZH~x6WRR|tddG~Lj+HKD>`aOl$k5;UF*({fT>i8kQw}(HbEX)qCUnPExJ!|vc z+Edr=e7&e&vq3!mPf7lsF9#02%e!>5@lLH9lUkn3orpOT8*cU;?>Q>TIb%!px1N)S zK|v+KI%A9V&NFi$A?TT`mvDFInK|IleBZ`!uh$M7$k*qdJ}k*8!8&8dvKYB@90xoO zXdF0VI`zP;Z%{LKyo*VLiI+E@J_8Ycc2i%7e{J>ri4C2_M|wdPzm;M5e5Uv79UJZ6 z`|9jY)lQ7i*;;J%XTH9h$*xV$;%)~x@?|cVUbR%)Jt-_ocGdRN0ekn}UpeQ^u1`lN zt~7bO^{v;jWeL5!{MW00uf4iv#*bfpM~;2pm%BfHa&G>fx?O^&&Is=Po%beY{?CK; iS<$~2UGu+q?FXmT$IlxsLcpT6;@MM7}!(=y~6a5UIE~m33s3eFa98zq&e>L6c07QX_JJYc>4KsfC zu=w!JVlmK6*wn#!ek0=tneLe;Nlta2Iy}FfnXoDANzp0sH>W&bdI=>bTdHrpa81hl z(XZoQQ=Rg^Z29zDfA?Jl&x{WlVL6qL)B~=(x$n%gu^sC|J&=gx?5)&basEf{rT%p>sN9o>-@9M{`yk8TV>^isgGA)efRQB{O8GR zU(c-Z%AGxLRnbA;=_}`5INrLhBIh)Fd6e~TncYjD-hcb;YH98Ecf0=9?2kK_KYO2B zTBL7@sqD=CCmWC6QYrl1=5OYyv#zIb`_qhbUmD%D|Hj%Kw%*>Ig_GbT0!Hh4P69N2R_sZWwqf_26QGnNfzzj|1Dn0#h@kFYUR zW?al5{LDnm{|qF^TP&v@nDb4NQ39mc;QhuK$!-j8Om2*7YkDKj7%DR;GcG<*QPzDV z`SZPWl?120q~xPLEN9f%9p)t`zn#5z)BD%YCm#~;d^%_D<7fYw43|9YHSN!t&1JNl z@qFdMsmdQ0=$c=>T^hW1@BLMC-fa4GbmGbxWw**ylcP7ZwH<%G_wKb<3uS))>N|4k z`@YQm(UWua_SEgXFlDB5)%UwMG~<69tlzY@Ht==u7DGG7bUXR=+w`_C|HsU6A*DK9 HkbwaJDt3cs literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/wizard_tower_0.nbt b/src/main/resources/assets/ebwizardry/structures/wizard_tower_0.nbt new file mode 100644 index 0000000000000000000000000000000000000000..903225608a14de846effba73dd71ec4452baaa76 GIT binary patch literal 2188 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/wizard_tower_2.nbt b/src/main/resources/assets/ebwizardry/structures/wizard_tower_2.nbt new file mode 100644 index 0000000000000000000000000000000000000000..b19b6de4fef4f0f3b200fdb122e0a50fb54301bd GIT binary patch literal 2422 zcmb2|=3sz;t+##iAD<9pdob-pme;4}Hy-<#Sw1mWslI(WsqrpD^~^Vl9GiAZOmVs0 zlzM5wi_$c|pDz-nsW|`PxV5RrV z(8_4Bhh7SZ-5GO&BeA4Lp-54=Me_agN|t9gXGPea;7GKIJa1|MQa|&y?Xd^9CJG)( zx&8hjNcEvxi$N6MPX~|@?YkVo)NA&g69f;nTxUDg+9TlR?)b#Xjbm}L6NnNvGo8XM zso2veIT1_=D~TI9NysjD0co^4*8wuEWR5UM|BK&GSp)k`A0N4y2697S|Fs&=D>=T? zER=aA6?@cQU7TevU>YsFS`xym{e4QJT20d3=gqD)ov|QO{jUU1xL(TJqu$fkf8a@r zpwT(r!q{IY4pc=7SMOC;Zu#h9`}pr(ixiv0W4{|8DH!v8W_hGweDAz+SM!+)`|BEf zMvnu`JDPirX?9qg$e6<^$Ubx9?YR>JWKvAd^?<}J6(1=qF7)dJ$r>y18A&~#)6v|s zuTQ@t=Gu+#(|Qc%8L)z#9kbiC?7vor#jMxN2CRu+3R8RT>bnU}zUAM3rsYg2uaBd| zUUNI9$DE5Fvq>oS^xbEiEbMl|Vt&WZi|&4N7(X>$clDD1d71OKwNY}yp?kePeovBm z1a{g8vd`S`T*+9m$S}?8$t=Ob37plcM$29Fj?EF=d9KsqM2juo(@knyk1xEgX#{di z@eTHieo!vMVKNc2bm)twQ z-hW1Z$IpxH0>2kDT!)0LupKwQr2mW$krGE8)!r=E;4?}*?^-y4bAD@}Ov<5sJ&zQG zzom+>&)iVH*y2RX`9mND_3nieIDcDrHTzgFFMx?YoYU|~LHHb}#&pw_#Y|Q5&c}q8 zDP-|IXECwAw&WbA#&z}tu0vqARx&?zN^^R)i*1>Lk3~L@q`!o$`2mi^LzT%Vz>%xI zNUrurTyExeklu8#TyMd|4Ehj)J__!t{u^K}X>vI>7F%QqQz1pZ&D(AdYukm9Gr!9{L zpV7mflANGgRt<3@)|s!RB>W|0GoE;VD0fzynFx55*+B|B%$JpHQDym0dJRoc^2!>#`B`W3b9bmwRP z)!TBTrq}E1Q>U%e}8%hTBJcb8?y zi{15(zMJ=d@gch}>vvzcy?*;f_jgXoXJ=2Z+PUie^RxSd^*27Qzjd1b@`}j+5ogPT zZ`A!UN*qdDw zCU$hLou2!o3#4}OVYBL^MIdPr_x4|q&G6pTx1k``e$rDVkvx9(a34Wg((f7W_JAj+;GRcJBNNxs;L{ZFjFoNRdXK=do!@)cuH5`>(k08*Rp?z0y&k%2d)%2jZ>DdnTo?8B>r9JC zlh^aa{h!u`mM=BCRdda4w!LimjVXVxpT6C`DK_la(M9~V4d(d;7tcI@opsr?^r_FR zN82~WPAz@DX<3bp&G%1lcbm2T!s zS<(Hx;oQAP8NVl<{S)x*>5t0GrDua*J?c|?w)Lg<+I;iZMS0FYcNcA3^*;9BE&n?Y zcZ%nqe>-d2dhL%oH%d%pIajNN%J z-S(B=?PWZ6=gcarT z`s}lBi+}zTEsD4ld!SKu@1N|;_rmSJZU1Y(s%&%Ct24g*tLnf1*jL|dVfpLhx9I<@ NZI{B@zJxO{005tFth4|C literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/wizard_tower_3.nbt b/src/main/resources/assets/ebwizardry/structures/wizard_tower_3.nbt new file mode 100644 index 0000000000000000000000000000000000000000..1022822af7973055c5fbc444e9cd88494f228f79 GIT binary patch literal 1927 zcmb2|=3sz;t+#yhZ@USwJ(#+~x%TMB-=!K=FY+_0PpfK75P6|`cA>_sI3BO4+byX< z3NLq@TUo#K|CSg}=grxA_r*1|8ak3~=Sb?El#M*S)Q~&*^`FV!J%)ABTW&x9cfWP! z?nNhO-?@5B=AOs(-9^RG`n@y%>@_&KZ%wKCe%-SV*;me9Q@Gsr*D)bCj>p?0cl%bQ z8BO4pRP4F`%tbGy#lY%^2A|R8%MyMEB-+wm?3f^UXi18#c7je~i$SO5zGV+?OcXq% z(tiJ;#fcY{u7wj`CN(CzyKyYu7y#0I_hYlgi5FkHvfSJ_9-qJ3vqIhE@`)Jpv=#%+ z!2b1>d_G3^7 z2FgXPYJ1Ft4n-W|NDMl3rsMIa<96!D3`|Zs=!qPE9wo5T$#@F)(U0p>6AtZ6HA+bO zY`lv7=*-Dq*EGx&JQlxNAM6O@gcgIkYR(?jo(YBLIzN8Y_x>Wn{Vp{H?1yht3?~b@ zRdaPU_k0r(VV8WXsljJ-D>y(VWy|sf7AG?N9j`}ZB>iQIwLfvDqiT!zf@FT*HR1~_ zxRv}el0NT|-FaV~Sti)$zb-o`I5$8HBPW-5T z-efRe@bTk#r!U-$-;Io%W=vV({`=?*PtL`EnT|TT{bmKZfg9uoagZDIL2ig&V6m|C z>}QSZb54lPx?$5_q}vg*u=8uvMvH%2d3@H0FQ{@7e$AR(_zV=KX)PDy4AO!Q{dmhG zq1f}S$uOByIb}}qBDw!w?&qef_6WG0*FM$SBd~0CvjaGCOIaQ%EH+&@Yog$x70x>+ z2p%dawms3>BjC2b-|1_M+PCjVX9ylz;$r(t)^3%h$-_I@oXRbpomC}!6V5DYxw!AL z`NpqIQ@CeJ&dg@@@silTm*JR@+X;(w7u)vp4iDs9+&C6r*8*9nW*M8T!Dm#}dloYd zR=p{nz%40h;yqd9bz0uCpVw+0U*rF|e9f(}{`H%(CX2rNv~W${^>sJy=$v`<{Ly0V zS(~a%CUPChznv>yTlaic&TP|}p8b-~)b^fUy=qNQ?f28Ww+nwZ+OK!&)LvWLRO6X5 zZtklon0k9#V$R!J_5SP2uD{v0GqXH)&;8W?b-&)VzrW2BdNb|p=|>U%PhNsk?1##7emSK9u>H&h{U28 zpE(~EuBc4m`Q3e|`^3iYXN^87mRe2nmcAr%rKd;0O*-iQ8l}h0MGGygG#5Vx8E}^E zDTw->;B==MWc+spkon7QS3PrmBKKzY<`cFZMXmfYJhI|OMhS;z?Vbfr5S^9(9vlMa z`(N#ntJo#~CUYKj1eGg`<;wzXPk?gamwvqvexqpyPBW&gQLhO|SRt3v(j#o=BQV=o zx1$-9#3Jvv6i<;g*k~#I)T`sMlN;Na(;$%-2} zN&ID6mw%{Eky%Yfes1-}Ld9fG<(7-Av-fe@r~9${a^^&CHJ6d;0RG zQ(f85!^Q6XoZ6cI+nX!$_vde))K+gh_kTmCa`}hV>N_;Azn;5#_ND^06Gp#hgjR-` zsA+D#op--`dF}VzYj&*NUB0iPDm`}E_OHFSV@vb<*7CJ>`fKa8i^|`%-xqUf;%4n|)`#$L`{A-`$UWul3D&^M~u&pG;Nn%YS}*MBO{4d1%Yt z;6DM|4oAl1o&I!l0nf9&_uv12zbAIZCIlYr#p7RdF>VDH>)f{E=~FU zU(CJ#NyWRH%rC!L#l$LC$NmWkyZ+9%TK&(nRaW}lM|7;N`dO{NU732d`uB&`^$hFQ L&J^i(U|;|M{#doA literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/wizard_tower_chest_0.nbt b/src/main/resources/assets/ebwizardry/structures/wizard_tower_chest_0.nbt new file mode 100644 index 0000000000000000000000000000000000000000..d5591b4d9f48454d5f35f4f6aca806e17962ce47 GIT binary patch literal 2249 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 H!N33j*2K`c literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/structures/wizard_tower_chest_3.nbt b/src/main/resources/assets/ebwizardry/structures/wizard_tower_chest_3.nbt new file mode 100644 index 0000000000000000000000000000000000000000..2fbe59525f63de20cb869a019e07fee70d2f1dba GIT binary patch literal 1986 zcmb2|=3sz;t+USNJ$4go^$v=Cwf^oq731!M3@4RYJj-sHFsU#yvCP$JI+$X{raD#k zkde2-%d%bJpS3;5~i8}5n=JkufA#93^r{-|?irqcCZ zLni}CLH~|Q#u+^cP3I~)5%I4!{uy8L^kE(=X>AH@( z)?~J8S!a0Gh92QKnBrn{`SdS|WTU2;aZ;BY&x9Q3e4&t5CF#DTdB)4sH6Zs&nO|`9 znbB_fP}KP2tr>zKQ)cueJagIabYJ|4#IZ9u2e@CdtXF*~YU~{6p)Rw!qqF#QN`vRq zdxmL_RcjfI)n{zri)U0*o^fFvgEEWot?UC4O@cwsXGzR2h*%UCQ7~5t6b_FrRv8{k zVOji@>7|0(Yt~DSJ=eIGG)t@%_h2`S(x1SWv?XqVshIJ~sD^9&NzYttW<3wQpR6|Z z`NVURE_BWe;oGi!{dY=(=iTJR6%)=i^`!I8usoPCPd?eGiPI{)g)hnEe7~WS!NOQ! zs}9cV=cJo{wn)q`;0V-bi8`77!AHwMRgiSna0R{Xe}3_dWVLg9rzNx`7%9o!9=GH@2BmXHK1+mbmQbxj%Pv=XLd0Ze49xGdukDo)UBaeY@`ODB2xA>#6_K>Tt7t zzY>H5kL+J^+pqTHgIP7x&38ub{(kh~vz*NaH=P4R_ZfY=tN*@k#*FJnV_#~2Km62i z*2yDh`v08_&AXm;^VZgSefR3De>dLT4xYYW?i2sIU$17bkDh&M`?Xg6^G(Ldw>kb- zK6~4I-!ggs|99KppZovc_DpTZwjVG2&iuUp-)Q;9D6!PX?^Z4P`Qh9B#NIQn_tu~4 z*3y{zvzdER;+cQn0;c3eKiz(Idugz3-t6P2?#`L_d#A_$x@mTM?K1t(lwP>?<9Jc{ zlyd3+?yp|G?q6Dxyz|e^-_N$!6c;@Ee6J<<`?|bW`sd&0&oan)&ar;JvW;ObdtKh) zYQyGT?|!d~e01;Jml>6h?&b9eHeGB3McLx71x#Q%`9``}r=d%n$MV%;wXMMd#z`#+Tg1N24DbBt80X>sn(-B=pxAOwQU3_X z!55|$%Igjqx^cLzcZ3uHUuUd7VtOMzPJNx@6H)u)23PctoL~?>e&;9)*xs+4m5Od0 zZu^B7RR}D;e|Z95lFmVngD+~$y4Vdt>E+9BIVj7>Xxjh*cE8#{lW`7!R_g}=pTmb^MA zae1T5UB|eNmqoULE@z?32 z0;qKDxuzz<4-v}65K2k0`DiS>@>a{E#F9tPwSs1UQ)iY_m5OfH**-b-OtAVGcdMvCIVJPi@jnk{9c%qzA35{t`lB;%K z@ThV8)2DN}e@nhURCi4LZ*R|@+P%APKEHadRs43?PUio&Zu@_jefHqhUj4b9G0)zA zUUlO1u`@Mw_vik8_VdnTMg8}$-%UP0&;Djbef;~o54Zg;$Vt{R+xO=49JAS9{(MpM zttl&;o!|ZG+>PbiqVN9vDCYJ3;MLFUiTN6eYD?G8`a2=&@#;po9ecJ;xcw(!ciFD2 z`{&+&zP)+cKHKA!b=M{TJiYng-Gu93&l=WSI&RWG^yPN*Zr*68-+N^9E$3|S-4$!T z_2>I}TPjuuAKSLK_2ZM~%+U;qG7d)>wW literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json b/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json index 8eddb4be..3b1dd848 100644 --- a/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json +++ b/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.json @@ -1,11 +1,12 @@ { - "ruler_text": "--------------------", + "bookmark_start_section": "introduction", "colours": { "text": "#000000", "caption": "#666666", "hyperlink": "#601ba0", - "highlight": "#dd4c1d" + "highlight": "#dd4c1d", + "new_section": "#ee88f7" }, "images": { @@ -33,74 +34,196 @@ "width": 36, "height": 33, "texture_width": 48, - "texture_height": 48 + "texture_height": 48, + "border": false }, "magic_wand": { - "location": "ebwizardry:textures/items/wand_basic.png", + "location": "ebwizardry:textures/items/wand_novice.png", "caption": "A Magic Wand", "u": 0, "v": 0, "width": 64, - "height": 64 + "height": 64, + "border": false }, "crystal_flower": { "location": "ebwizardry:textures/gui/flower_picture.png", "caption": "A Crystal Flower", "u": 0, "v": 0, - "width": 64, - "height": 64 + "width": 48, + "height": 48 + }, + "wizard_tower": { + "location": "ebwizardry:textures/gui/tower_picture.png", + "caption": "A Wizard's Tower", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "wizard_armour": { + "location": "ebwizardry:textures/gui/armour_picture.png", + "caption": "A Set Of Wizard Armour", + "u": 0, + "v": 0, + "width": 90, + "height": 90 + }, + "obelisk": { + "location": "ebwizardry:textures/gui/obelisk_picture.png", + "caption": "An Obelisk", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "shrine": { + "location": "ebwizardry:textures/gui/shrine_picture.png", + "caption": "An Earth Shrine", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "tiers": { + "location": "ebwizardry:textures/gui/tiers_picture.png", + "caption": "The 4 Tiers Of Wand", + "u": 0, + "v": 0, + "width": 96, + "height": 24, + "border": false + }, + "elements": { + "location": "ebwizardry:textures/gui/elements_picture.png", + "caption": "The 7 Arcane Elements", + "u": 0, + "v": 0, + "width": 106, + "height": 20, + "border": false } }, "recipes": { "arcane_workbench": { - "location": "ebwizardry:arcane_workbench" + "locations": [ "ebwizardry:arcane_workbench" ] }, "magic_wand": { - "location": "ebwizardry:magic_wand" + "locations": [ "ebwizardry:magic_wand" ] + }, + "novice_wands": { + "locations": [ + "ebwizardry:magic_wand", + "ebwizardry:wand_fire", + "ebwizardry:wand_ice", + "ebwizardry:wand_lightning", + "ebwizardry:wand_necromancy", + "ebwizardry:wand_earth", + "ebwizardry:wand_sorcery", + "ebwizardry:wand_healing" + ] }, "magic_missile_spell_book": { - "location": "ebwizardry:magic_missile_spell_book" + "locations": [ "ebwizardry:magic_missile_spell_book" ] }, "wizard_handbook": { - "location": "ebwizardry:wizard_handbook" + "locations": [ "ebwizardry:wizard_handbook" ] }, "crystal_flower_to_crystals": { - "location": "ebwizardry:crystal_flower_to_crystals" + "locations": [ "ebwizardry:crystal_flower_to_crystals" ] }, - "mana_flask": { - "location": "ebwizardry:mana_flask" + "crystal_blocks": { + "locations": [ + "ebwizardry:crystal_block", + "ebwizardry:crystal_block_fire", + "ebwizardry:crystal_block_ice", + "ebwizardry:crystal_block_lightning", + "ebwizardry:crystal_block_necromancy", + "ebwizardry:crystal_block_earth", + "ebwizardry:crystal_block_sorcery", + "ebwizardry:crystal_block_healing" + ] + }, + "crystal_blocks_to_crystals": { + "locations": [ + "ebwizardry:crystal_block_to_crystals", + "ebwizardry:crystal_block_to_crystals_fire", + "ebwizardry:crystal_block_to_crystals_ice", + "ebwizardry:crystal_block_to_crystals_lightning", + "ebwizardry:crystal_block_to_crystals_necromancy", + "ebwizardry:crystal_block_to_crystals_earth", + "ebwizardry:crystal_block_to_crystals_sorcery", + "ebwizardry:crystal_block_to_crystals_healing" + ] + }, + "crystal_shard": { + "locations": [ "ebwizardry:crystal_shard" ] + }, + "small_mana_flask": { + "locations": [ "ebwizardry:small_mana_flask" ] + }, + "medium_mana_flask": { + "locations": [ "ebwizardry:medium_mana_flask" ] + }, + "large_mana_flask": { + "locations": [ "ebwizardry:large_mana_flask" ] + }, + "runestone": { + "locations": [ + "ebwizardry:runestone_fire", + "ebwizardry:runestone_ice", + "ebwizardry:runestone_lightning", + "ebwizardry:runestone_necromancy", + "ebwizardry:runestone_earth", + "ebwizardry:runestone_sorcery", + "ebwizardry:runestone_healing" + ] + }, + "runestone_pedestal": { + "locations": [ + "ebwizardry:runestone_pedestal_fire", + "ebwizardry:runestone_pedestal_ice", + "ebwizardry:runestone_pedestal_lightning", + "ebwizardry:runestone_pedestal_necromancy", + "ebwizardry:runestone_pedestal_earth", + "ebwizardry:runestone_pedestal_sorcery", + "ebwizardry:runestone_pedestal_healing" + ] }, "transportation_stone": { - "location": "ebwizardry:transportation_stone" + "locations": [ "ebwizardry:transportation_stone" ] }, "magic_silk": { - "location": "ebwizardry:magic_silk" + "locations": [ "ebwizardry:magic_silk" ] }, "wizard_hat": { - "location": "ebwizardry:wizard_hat" + "locations": [ "ebwizardry:wizard_hat" ] }, "wizard_robe": { - "location": "ebwizardry:wizard_robe" + "locations": [ "ebwizardry:wizard_robe" ] }, "wizard_leggings": { - "location": "ebwizardry:wizard_leggings" + "locations": [ "ebwizardry:wizard_leggings" ] }, "wizard_boots": { - "location": "ebwizardry:wizard_boots" + "locations": [ "ebwizardry:wizard_boots" ] }, "blank_scroll": { - "location": "ebwizardry:blank_scroll" + "locations": [ "ebwizardry:blank_scroll" ] }, "firebomb": { - "location": "ebwizardry:firebomb" + "locations": [ "ebwizardry:firebomb" ] }, "poison_bomb": { - "location": "ebwizardry:poison_bomb" + "locations": [ "ebwizardry:poison_bomb" ] }, "smoke_bomb": { - "location": "ebwizardry:smoke_bomb" + "locations": [ "ebwizardry:smoke_bomb" ] + }, + "spark_bomb": { + "locations": [ "ebwizardry:spark_bomb" ] } }, @@ -146,13 +269,19 @@ "include_in_contents": "main_contents", "text": [ - "To get started with wizardry, you will need a few things:", + "To get started with wizardry, you will need:", - "- A magic wand, crafted with a gold nugget, a stick, and a magic crystal.", + "- A magic wand, crafted as shown:", + + "#recipe magic_wand", - "- An @arcane_workbench arcane workbench@, crafted with 3 stone, 1 lapis lazuli block, 2 magic crystals, 2 gold nuggets and 1 purple carpet.", + "- An @arcane_workbench arcane workbench@, crafted like so:", + + "#recipe arcane_workbench", - "- A @spells spell@ book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, with a book and 4 magic crystals.", + "- A @spells spell@ book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, as shown:", + + "#recipe magic_missile_spell_book", "You will also need a bunch more magic crystals to supply your wand with @mana@." ] @@ -172,7 +301,7 @@ "#image magic_crystal", - "It is widely accepted that mana cannot be created or destroyed, and that when a spell is cast, the mana it channels is simply dissipated into the surroundings. Indeed, this is how the vast majority of mana exists - spread thinly throughout the world. However, to be of any use, it must be concentrated, either naturally over thousands of years, as is the case with crystals underground, or artificially - an advanced subject covered later in this book. There also exist various ways of making spells more mana-efficient and recovering some of the mana dissipated during spellcasting." + "It is widely accepted that mana cannot be created or destroyed, and that when a spell is cast, the mana it channels is simply dissipated into the surroundings. Indeed, this is how the vast majority of mana exists - spread thinly throughout the world. However, to be of any use, it must be concentrated, either naturally over thousands of years, as is the case with crystals underground, or artificially - an advanced subject not covered in this book. There also exist various ways of making spells more mana-efficient and recovering some of the mana dissipated during spellcasting." ] }, @@ -190,7 +319,7 @@ "Most wands begin their life as a simple arrangement of a magic crystal of some sort attached to a wooden stick, with a gold nugget affixed to the other end. The crystal is, of course, the source of the wand's power, as it provides the focus necessary to channel @spells@. The rest of the wand is important too though, as it provides not only a means with which to hold the wand, but also a path through which @mana@ can be channelled and directed.", - "As more spells are cast with a wand, it grows more effective at channelling @spells@, and can therefore cast spells of greater power. This effect can be discerned from subtle changes that occur in the shape and appearance of the wand itself: as a wand grows more powerful, its crystal will become more vibrant, it may change in colour depending on its element, and after a while, the wood from which it is made will start to grow and twist into more complex shapes.", + "As more spells are cast with a wand, it grows more effective at channelling @spells@, and can therefore cast spells of greater power. This effect can be discerned from subtle changes that occur in the shape and appearance of the wand itself: as a wand grows more powerful, its crystal will become more vibrant, its colour may change depending on its @elements element@, and after a while, the wood from which it is made will start to grow and twist into more complex shapes.", "When holding a wand, a small heads-up display will show in the corner of the screen. This indicates the spell that is currently selected along with a pictorial representation of it, and, if the spell has been cast, a cooldown bar indicating the time until that spell can be cast again. It also shows the names of the next and previous spells bound to the wand. To switch between spells, use the #next_spell_key and #previous_spell_key keys (these can be changed in options -> controls). You can also switch spells by scrolling the mouse wheel while sneaking.", @@ -205,14 +334,16 @@ "ebwizardry:handbook/spells" ], "text": [ - + "A @wands wand@ is useless without spells to cast with it. Spells are recorded in two forms: in books, which are permanent, and in scrolls, which are temporary.", - "Spell books are of little use on their own; instead they are used to bind the spell they contain to @wands@. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more detailed information about the spell.", + "Spell books are of little use on their own; instead they are used to bind the spell they contain to @wands@. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more about it.", - "Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself by crafting a blank scroll from a piece of paper and some string. You can then bind a spell to the scroll using the @arcane_workbench arcane workbench@, but only if you have knowledge of that spell (see @enchanting_scrolls Enchanting Scrolls@). Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your @wands wand@. It should be noted, however, that scrolls are at best an inefficient method of casting spells.", + "Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself (see @enchanting_scrolls Enchanting Scrolls@).", - "To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right-clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification in the process." + "Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your @wands wand@. It should be noted, however, that they are an inefficient method of casting spells compared to using a wand.", + + "To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. Futhermore, there is always a chance of misreading an unknown spell when casting, with potentially dangerous consequences depending on how powerful the spell is. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right-clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification in the process." ] }, @@ -230,7 +361,11 @@ ], "text": [ - "The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind @spells@ to your @wands wand@. Simply place it anywhere and right click, and you will see something like this:", + "The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind @spells@ to your @wands wand@. It may be crafted as follows:", + + "#recipe arcane_workbench", + + "The following pages explain the various actions that may be performed in the arcane workbench.", "#image workbench" ], @@ -238,25 +373,34 @@ "binding_spells": { "title": "Binding Spells", "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], "text": [ - "To bind a spell to your wand, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press apply. You will notice that the spell book is left untouched during this process - this is because the act of spell binding does not 'take' the spell from the spell book; rather, it attunes the wand to the spell. As such, you may change the spells bound to your wand as much as you wish by simply repeating the spell binding process. You can bind up to five spells to a wand at one time, though this number may be increased with attunement upgrades." + "To bind a @spells spell@ to your @wands wand@, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press confirm. You will notice that the spell book is left untouched during this process - this is because the act of spell binding does not 'take' the spell from the spell book; rather, it attunes the wand to the spell. As such, you may change the spells bound to your wand as much as you wish by simply repeating the spell binding process. You can bind up to five spells to a wand at one time, though this number may be increased with attunement upgrades." ] }, "charging_wands": { "title": "Charging Wands", "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], "text": [ - "To charge your wand, place the wand in the central slot of the arcane workbench and place some magic crystals in the upper of the two slots on the left, and then press apply. Each crystal is worth #mana_per_crystal mana, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals so if the wand needs, for example, 30 more mana, #mana_per_crystal_minus_30 mana will be lost when charging it." + "To charge your @wands wand@, place the wand in the central slot of the arcane workbench and place some magic crystals in the bottom-left slot, and then press confirm. Each crystal is worth #mana_per_crystal @mana@, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals, so if the wand needs, for example, 30 more mana, #example_charging_loss mana will be lost when charging it." ] }, "upgrading_wands": { "title": "Upgrading Wands", "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], "text": [ - "To upgrade your wand, you will need a tome of arcana of the appropriate tier (see @tiers Tiers@) or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the lower of the two slots on the left, then press apply.", + "To upgrade your @wands wand@, you will need a tome of arcana of the appropriate @tiers tier@ or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the top-right slot, then press confirm.", "Special wand upgrades improve a particular aspect of a wand. Each type of upgrade can stack up to three times, and the total number of upgrades that a wand can take depends on its tier. Upgrades cannot be removed." ] @@ -264,9 +408,16 @@ "enchanting_scrolls": { "title": "Enchanting Scrolls", "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/scrolls" + ], "text": [ - "The arcane workbench can also be used to enchant spell scrolls. To do so, you will require a blank scroll, crafted from a piece of paper and some string, a spell book for your chosen spell, and enough magic crystals to provide mana to cast it. Place the crystals in the upper left-hand slot, the blank scroll in the central slot, and the spell book in the single slot that appears above it, then press apply to enchant the scroll." + "The arcane workbench can also be used to enchant @spells spell@ scrolls. To do so, you will require a blank scroll, crafted from a piece of paper and some string, a spell book for your chosen spell, and enough magic crystals to provide @mana@ to cast it.", + + "#recipe blank_scroll", + + "Place the crystals in the bottom-left slot, the blank scroll in the central slot, and the spell book in the single slot above it, then press confirm to enchant the scroll." ] } } @@ -275,11 +426,24 @@ "wizard_armour": { "title": "Wizard Armour", "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], "text": [ - "As a wizard, you will need something to protect you from the creatures you fight. No ordinary armour will do though. To make the most of your spells, you will need wizard armour: hat, robes, leggings and boots. Unlike ordinary armour, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much mana. Charge them as you would a wand in the arcane workbench or with a mana flask, but be careful - if they run out of mana, you will find yourself defenceless.", + "As a wizard, you will need something to protect you from the creatures you fight. No ordinary armour will do though. To make the most of your spells, you will need wizard armour: hat, robes, leggings and boots. Unlike ordinary armour, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much @mana@. Charge them as you would a wand in the @arcane_workbench arcane workbench@ or with a @mana_flasks mana flask@, but be careful - if they run out of mana, you will find yourself defenceless.", - "You can obtain wizard armour by crafting it from magical silk, obtained by crafting string with a magic crystal.", + "#image wizard_armour", + + "You can obtain wizard armour by crafting it from magical silk:", + + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + + "One may enchant wizard armour using a normal enchantment table, and due to the inherent properties of magical silk, it tends to be quite effective at holding enchantments. Of particular utility to a wizard are the Magic, Frost and Shock Protection enchantments, which may prove useful defending against other wielders of magic.", "Those wizards who devote themselves to the practice of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find.", @@ -296,6 +460,9 @@ "page_numbers": true, "separator": "." }, + "triggers": [ + "ebwizardry:handbook/on_subsection_unlock" + ], "text": [ "One cannot master the arcane just by staying at home - there is a world full of magic out there to explore! Ancient ruins, relics and mysterious beings good and bad await discovery - if you know where to look. The greatest wizards are also the most curious, and gain much of their knowledge and power through exploration of the environment around them, and experimenting with what they find.", @@ -311,57 +478,83 @@ ], "text": [ - "During your travels, you will probably come across curious glowing flowers growing in the wild from time to time. These distinctive blooms are known as crystal flowers, and they are strangely effective at concentrating mana - to this day, nobody is quite sure why. We do know, however, that they can be harvested and crafted to extract the mana as crystals, making them a rather useful above-ground source of mana. The amount of mana obtainable this way is limited, though, by the small size of the flowers and due to them only growing in small patches.", + "During your travels, you will probably come across curious glowing flowers growing in the wild from time to time. These distinctive blooms are known as crystal flowers, and they are strangely effective at concentrating @mana@ - to this day, nobody is quite sure why. We do know, however, that they can be harvested and crafted to extract the mana as crystals, making them a rather useful above-ground source of mana. The amount of mana obtainable this way is limited, though, by the small size of the flowers and due to them only growing in small patches.", - "#image crystal_flower" + "#image crystal_flower", + "#recipe crystal_flower_to_crystals" ] }, "wizard_towers": { "title": "Wizard Towers", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:wizard_tower" + ], "text": [ - "Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter a tall tower or two with a distinctive pointed roof. This is the residence of a fellow wizard. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder. If, however, it is a master spell you seek, you will need to speak to a specialist.", + "Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter a tall tower or two with a distinctive pointed roof. This is the residence of a fellow wizard. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder.", + + "If, however, it is a @tiers master@ spell you seek, you will need to speak to a specialist.", + + "#image wizard_tower", "Unfortunately, there are a few wizards out there who do not welcome visitors. These wizards are typically outcasts, and are hostile to anyone crossing their path. Approach these individuals with caution, and be prepared to defend yourself against powerful magic. Defeat them however, and their knowledge is yours for the taking.", - "It should also be noted that no wizard will take kindly to being attacked or stolen from - and will readily take the law into their own hands." + "It should also be noted that no wizard will take kindly to being attacked or stolen from - and they will readily take the law into their own hands." ] }, "obelisks": { "title": "Obelisks", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/obelisks" + ], "text": [ "Vestiges of ancient magic are scattered throughout the world, the most notable of which are carved stone structures which bear a great many symbols and runes. These ruins are all that remain of what appears to have been some kind of ancient civilisation. Whoever, or whatever, built them, they clearly had a considerable knowledge of magic, and used it to place protective enchantments over such locations that still persist to this day.", - "These stuctures fit broadly into two types. The first, and more common, of these are obelisks: tall spikes of carved stone, known as runestone, with an open structure at the bottom that usually contains minor arcane relics from the forgotten past. These structures are typically protected by an enchantment that summons hostile magical creatures should any human stray too close. Fend off these creatures and destroy their source, and the relics are yours." + "These stuctures fit broadly into two types. The first, and more common, of these are obelisks: tall spikes of carved stone, known as runestone, with an open structure at the bottom containing minor arcane relics from the forgotten past.", + + "#image obelisk", + + "These structures are typically protected by an enchantment that summons hostile @creatures magical creatures@ should any human stray too close. Fend off these creatures and destroy their source, and the relics are yours." ] }, "shrines": { "title": "Shrines", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:visit_shrine" + ], "text": [ - "The second, and rarer, kind of structure is known as a shrine. These structures consist of a circle of runestone pillars surrounding a central platform, upon which sits a chest filled with ancient artefacts. This chest is typically protected by an arcane lock enchantment, preventing anyone except the owner from opening it. The entire structure is also protected by a containment field, which prevents anything that strays too close from escaping.", - + "The second, and rarer, kind of structure is known as a shrine. These structures consist of a circle of runestone pillars surrounding a central pedestal, upon which sits a chest filled with ancient @artefacts@. This chest is typically protected by an arcane lock enchantment, preventing anyone except the owner from opening it. The entire structure is also protected by a containment field, which prevents anything that strays too close from escaping.", + + "#image shrine", + "Due to their great arcane power and significance, not to mention the riches within, these structures are particularly attractive to any aspiring wizard - but be cautious. There are numerous reports of wizards becoming trapped within containment fields and slowly being driven insane, perhaps by claustrophobia. A growing number, however, believe such occurences to be a deliberate part of the shrine's protective magic, and that the wizards trapped within are in fact being controlled to protect the structure. A chilling prospect, surely, for anyone who dares to venture near..." ] }, "creatures": { "title": "Magical Creatures", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/magical_creatures" + ], "text": [ - "Besides wizards, a multitude of other creatures also use magic. Many of these creatures are arcane in origin, and most can be summoned using certain magical spells. One may encounter these creatures guarding an obelisk, or perhaps a powerful summoner. Lesser arcane beings are even found occasionally in the wilderness." + "Besides wizards, a multitude of other creatures also use magic. Many of these creatures are arcane in origin, and most can be summoned using certain magical @spells spells@. One may encounter these creatures guarding an @obelisks obelisk@, or perhaps a powerful summoner. Lesser arcane beings are even found occasionally in the wilderness." ] }, "artefacts": { "title": "Artefacts", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:artefact" + ], "text": [ - "When exploring a shrine, you may be lucky enough to uncover some kind of ancient magical artefact - an object capable of granting its wearer unique and powerful buffs and special powers. Three types are known to have been found: rings, which grant bonuses and effects to spells, amulets, which improve defensive abilities, and trinkets, which give utility effects. These artefacts appear to function only when worn appropriately; simply having them on one's person is insufficient." + "When exploring a @shrines shrine@, you may be lucky enough to uncover some kind of ancient magical artefact - an object capable of granting its wearer unique and powerful buffs and special powers. Three types are known to have been found: rings, which grant bonuses and effects to spells, amulets, which improve defensive abilities, and charms, which give utility effects. These artefacts appear to function only when worn appropriately; simply having them on one's person is insufficient." ] } } @@ -370,26 +563,40 @@ "tiers": { "title": "Tiers", "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], "text":[ - "Wands and spells come in four tiers: #colour_novicenovice#colour_reset, #colour_apprenticeapprentice#colour_reset, #colour_advancedadvanced #colour_resetand #colour_mastermaster#colour_reset. Each tier is more powerful than the last.", + "@wands Wands@ and @spells@ come in four tiers: #colour_novicenovice#colour_reset, #colour_apprenticeapprentice#colour_reset, #colour_advancedadvanced #colour_resetand #colour_mastermaster#colour_reset. Each tier is more powerful than the last.", + + "#image tiers", "#colour_noviceNovice #colour_resetwands are the ones that can be crafted. They hold up to #novice_max_charge mana, and can only cast novice spells. Novice spells are simple enough to be cast by anyone and they do not usually cost much mana. This does not necessarily mean that they are useless at higher tiers however; their low cost makes some novice spells useful even when you have access to master spells.", "#colour_apprenticeApprentice #colour_resetwands are the next tier up from novice wands. They hold up to #apprentice_max_charge mana and can cast novice and apprentice spells. Apprentice spells are a little more impressive than novice spells but usually cost more.", - "#colour_advancedAdvanced #colour_resetwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold #advanced_max_charge mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on enemies.", + "#colour_advancedAdvanced #colour_resetwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold #advanced_max_charge mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on foes.", - "#colour_masterMaster #colour_resetwands are the most powerful wands in existence. They hold up to #master_max_charge mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution." + "#colour_masterMaster #colour_resetwands are the most powerful wands in existence. They hold up to #master_max_charge mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution.", + + "To be upgraded to a higher tier, a wand must first become powerful enough to channel spells of that tier. Wands gain power as spells are cast with them. Spell variety, spell power, elemental effects and other external factors may all have an effect on how quickly a wand matures.", + + "Once a wand is sufficiently powerful, a tome of arcana provides the final catalyst needed to elevate the wand to the next tier (see @upgrading_wands Upgrading Wands@), and once this has happened, the maturing process can begin again for the next tier." ] }, "elements": { "title": "Elements", "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/elements" + ], "text": [ - "Spells belong to different elements, which describe the nature of the spell and also have perks when used with certain wands.", + "@spells Spells@ belong to different elements, which determine the nature of the spell and also grant perks when used with certain @wands@.", + + "#image elements", "#colour_fireFire#colour_reset \nPerhaps the most destructive element, fire concerns burning, lava, and explosions. A powerful pyromancer will unleash hell upon their enemies and probably set the world alight in the process. Most fire attack spells set fire to their target, causing ongoing damage over time. However, be wary that fire spells may have no effect on nether mobs.", @@ -397,7 +604,7 @@ "#colour_lightningLightning#colour_reset \nThis element concerns lightning, storms, and the weather. A powerful storm mage is a force to be reckoned with, and some posess the ability to call down lightning at will. Lightning spells often damage multiple enemies at once and usually seek their target, making them an effective attack against any mob... but beware of creepers.", - "#colour_necromancyNecromancy#colour_reset \nNecromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon creatures to fight for you or even bend the will of your enemies.", + "#colour_necromancyNecromancy#colour_reset \nNecromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon @creatures@ to fight for you or even bend the will of your enemies.", "#colour_earthEarth#colour_reset \nThe element of earth is focused on the natural world: animals, plants, the wind, and such like. Earth magic is diverse and takes a wide variety of forms, from poisoning enemies to unleashing the fury of the weather. Earth spells are a mixture of attack, defence and utility.", @@ -407,25 +614,10 @@ "The boundaries between the different elements are not always distinct, and some spells bear traits of elements other than their own.", - "If you are lucky, you may happen upon an elemental wand. These wands will allow you to cast spells of the right element for more potency than usual." + "If you are lucky, you may happen upon an elemental crystal. Elemental crystals are magic crystals that have absorbed elemental properties as they have grown - though the exact conditions required and mechanism by which this happens remain a mystery. We do know, however, that such crystals may be used to create elemental wands, which allow spells of the right element to be cast with more potency than usual." ] }, - - "growing_crystals": { - "title": "Growing Crystals", - "include_in_contents": "main_contents", - "text": [ - - "Magic crystals normally form naturally underground over thousands of years, by gradually drawing latent mana from the surrounding rock as they grow. Crystalline structures are very good at absorbing and holding mana, hence the mana is naturally drawn towards them. Given the right conditions, however, it is possible to greatly speed up this process. This has given rise to the advanced technique of crystal growing, which requires both great patience and attention to detail.", - - "In order to encourage crystal growth, one must begin with a crystal seed. The most effective seeds have proven to be crystal shards, obtained by simply shattering a magic crystal into pieces. A crystal seed must then be planted into some kind of substrate, usually rock, although other materials are also viable. Left alone, this would produce a sizeable crystal in hundreds of years, depending on the conditions.", - - "To reduce this length of time, several things can be done. Immersing the seed and substrate in mineral-rich water helps with crystal growth, but not with concentrating mana. To concentrate mana more quickly, two techniques can be employed: firstly, surrounding the growth site with lesser mana-gathering objects allows the crystal to draw from them, meaning the surrounding environment is constantly replenished with mana. Too many, however, and they begin to draw mana away from the growing crystal. Secondly, mana can be drawn through some materials better than others: air is very poor at this, whereas dense materials tend to be much better. Some wizards have taken to experimentation with exotic, magical, or even otherworldy materials to try and improve crystal growth. Some even claim to have altered the type of crystal that is formed in this way.", - - "If conditions are exactly right, it is even possible for crystals to grow far beyond their natural size. Such crystals are known as grand magic crystals, and besides containing a great quantity of mana, they have a few specific uses." - ] - }, - + "miscellaneous": { "title": "Miscellaneous", "include_in_contents": "main_contents", @@ -435,37 +627,57 @@ "page_numbers": true, "separator": "." }, + "triggers": [ + "ebwizardry:on_subsection_unlock" + ], "sections": { "mana_flasks": { "title": "Mana Flasks", "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/mana_flasks" + ], "text": [ "Arkendur's Arcane Supplies Co. - magical items for your every need!", - "Need to recharge your wand on the go? No problem! Mana can now be bottled.** Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge.*", + "Need to recharge your @wands wand@ on the go? No problem! @mana Mana@ can now be bottled. Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge. *", + + "#recipe medium_mana_flask", - "NEW! Introducing the brand-new large*** and small mana flasks - now you can choose a size of mana flask to meet your needs!", + "NEW! Introducing the brand-new small and large mana flasks - now you can choose a size of mana flask to meet your needs!", + + "#recipe small_mana_flask", + "#recipe large_mana_flask", - "* This process will consume the bottle.", - "** Some mana is lost during bottling.", - "*** Large mana flask requires grand magic crystals." + "* This process will destroy the bottle. Some mana is lost during bottling." ] }, "throwable_items": { "title": "Throwable Items", "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/throwables" + ], "text": [ - "Various spells conjure physical items, some of which can also be crafted directly. Firebombs, poison bombs, spark bombs and smoke bombs can all be crafted." + "Various @spells@ conjure physical items, some of which can also be crafted directly. Firebombs, poison bombs, spark bombs and smoke bombs can all be crafted:", + + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb", + "#recipe spark_bomb" ] }, "automated_casting": { "title": "Automated Casting", "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:enchant_scroll" + ], "text": [ - "Recent experimentation has revealed that it is possible to automate spell casting, to a degree, using nothing more than a simple dispenser. Nobody is quite sure why, but it would appear that the strange properties of redstone even extend to triggering the activation of spell scrolls. Placing a few into a dispenser and powering it ought to do the trick..." + "Recent experimentation has revealed that it is possible to automate @spells spell@ casting, to a degree, using nothing more than a simple dispenser. Nobody is quite sure why, but it would appear that the strange properties of redstone even extend to triggering the activation of spell scrolls. Placing a few into a dispenser and powering it ought to do the trick..." ] } } @@ -477,11 +689,18 @@ "text": [ "#recipe arcane_workbench", - "#recipe magic_wand", + "#recipe novice_wands", "#recipe magic_missile_spell_book", "#recipe wizard_handbook", "#recipe crystal_flower_to_crystals", - "#recipe mana_flask", + "#recipe crystal_blocks", + "#recipe crystal_blocks_to_crystals", + "#recipe crystal_shard", + "#recipe small_mana_flask", + "#recipe medium_mana_flask", + "#recipe large_mana_flask", + "#recipe runestone", + "#recipe runestone_pedestal", "#recipe transportation_stone", "#recipe magic_silk", "#recipe wizard_hat", @@ -491,7 +710,8 @@ "#recipe blank_scroll", "#recipe firebomb", "#recipe poison_bomb", - "#recipe smoke_bomb" + "#recipe smoke_bomb", + "#recipe spark_bomb" ] }, @@ -502,8 +722,6 @@ "Electroblob's Wizardry \nVersion #version \nFor Minecraft #mcversion", - "For more information, check out the @https://github.com/Electroblob77/Wizardry/wiki wiki@.", - "Designed, coded and textured by Electroblob", "Thanks to Minecraft Forge and MCP, without which this mod would not have been possible.", @@ -514,13 +732,17 @@ "Code:", - "- Corail31 \n- 12foo \n- Shadows-of-Fire", + "- Corail31 \n- 12foo \n- Shadows-of-Fire \n- Tora-B \n- Avatair \n- Aeronica", "Translations:", - "- Russian: VilagVil \n- Spanish and Mexican Spanish: MadWrist \n- Chinese: ZHENGLOC", + "- Spanish and Mexican Spanish: MadWrist \n- Russian: VilagVil, kellixon \n- French: Hahdrim \n- Brazilian Portuguese: lorrampi \n- Chinese: ZHENGLOC, dragon-evol \n-Korean: shejery, rewi_wire", - "Lightning ray sound effect from OhhWowProductions" + "Lightning ray sound effect from OhhWowProductions", + + "For more information, check out the @https://github.com/Electroblob77/Wizardry/wiki wiki@.", + + "Can't get enough wizardry? Join the @https://discord.gg/MTmMzMv Discord server@ for the latest news, discussions and extras!" ] } diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.txt b/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.txt deleted file mode 100644 index b96617ab..00000000 --- a/src/main/resources/assets/ebwizardry/texts/handbook_en_gb.txt +++ /dev/null @@ -1,225 +0,0 @@ -PAGEBREAK -LINEBREAK - - - - -The Wizard's Handbook - - - -By Electroblob -PAGEBREAK -Introduction --------------------- - -Greetings, wizard! This book explains the many ways of the arcane and how to use them. - -Should you ever lose this book, you can get a new one by crafting a book with a magic crystal. -PAGEBREAK -Contents --------------------- -PAGEBREAK -SECTION Setting up -Setting up --------------------- -To get started with wizardry, you will need a few things: - -- A magic wand, crafted with a gold nugget, a stick, and a magic crystal. - -- An arcane workbench, crafted with 3 stone, 1 lapis lazuli block, 2 magic crystals, 2 gold nuggets and 1 purple carpet. - -- A spell book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, with a book and 4 magic crystals. - -You will also need a bunch more magic crystals to supply your wand with mana. -PAGEBREAK -SECTION Mana -Mana --------------------- -Mana is the arcane energy that gives wizards their powers. It manifests itself in naturally occurring crystals, which can be found embedded in rocks underground. Wands can store mana within them, and this mana is channeled into the spells that you cast. Different spells cost different amounts of mana, depending on how powerful they are and how long they last. - -Mouse over a wand to see how much mana is stored in it. -IMAGE CRYSTAL -LINEBREAK - - - - - - - Magic - Crystal Ore Crystal -PAGEBREAK -SECTION Wands -Wands --------------------- -The wand is the implement of choice for a wizard. With it, you can cast any spell provided the wand can contain its power (see Tiers for a more in-depth explanation). Wands come in -various different varieties but you will almost certainly start with a basic magic wand. - -When holding a wand, a small heads-up display will show in the corner of the screen. This indicates the spell that is currently selected along with a pictorial representation of it, and, if the spell has been cast, a cooldown bar indicating the time until that spell can be cast again. -PAGEBREAK -SECTION Spells -Spells --------------------- -A wand is useless without spells to cast with it. Spells are recorded in two forms: in books, which are permanent, and in scrolls, which are temporary. - -Spell books are of little use on their own; instead they are used to bind the spell they contain to wands. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more detailed information about the spell. - -Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself by crafting a blank scroll from a piece of paper and some string. You can then bind a spell to the scroll using the arcane workbench, but only if you have knowledge of that spell. Doing so will consume a number of magic crystals equal to the mana cost of the spell (rounded up to the nearest MANA_PER_CRYSTAL). - -To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right- -clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification. - -Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your wand. It should be noted, however, that scrolls are at best an inefficient method of casting spells. -PAGEBREAK -SECTION Arcane Workbench -The Arcane Workbench --------------------- -The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind spells to your wand. Simply place it anywhere and right click, and you will see a gui appear like the one to the right. -PAGEBREAK -IMAGE WORKBENCH -LINEBREAK - - - - - - - - - - - - - - The Arcane Workbench -PAGEBREAK -SECTION Binding Spells -Binding Spells --------------------- -To bind a spell to your wand, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press apply. You can bind up to five spells to a wand at one time, though this may be increased with attunement upgrades. When holding a wand, you can switch between spells with the NEXT_SPELL_KEY and PREVIOUS_SPELL_KEY keys (these can be changed in options -> controls). You can also switch spells by scrolling the mouse wheel while sneaking. - -SECTION Charging Wands -Charging your wand --------------------- -To charge your wand, place the wand in the central slot of the arcane workbench and place some magic crystals in the upper of the two slots on the left, and then press apply. Each crystal is worth MANA_PER_CRYSTAL mana, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals so if the wand needs, for example, 30 more mana, MANA_PER_CRYSTAL_MINUS_30 mana will be lost when charging it. All wands will take an exact number of crystals to charge if they are empty, unless they have a storage upgrade applied. - -SECTION Upgrading Wands -Upgrading your wand --------------------- -To upgrade your wand, you will need a tome of arcana of the appropriate tier (see Tiers) or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the lower of the two slots on the left, then press apply. - -Special wand upgrades improve a particular aspect of a wand. Each type of upgrade can stack up to three times, and the total number of upgrades that a wand can take depends on its tier. Upgrades cannot be removed. -PAGEBREAK -SECTION Flowers and Flasks -Flowers and Flasks --------------------- -You will probably come across curious glowing flowers growing in the wild from time to time. These are crystal flowers, a naturally occurring source of mana. They can be harvested and crafted to extract the mana as crystals. - -Need to recharge your wand on the go? No problem! Mana can now be bottled. Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge. This process will consume the bottle. Some mana is lost during bottling. -PAGEBREAK -SECTION Tiers -Tiers --------------------- -Wands and spells come in four tiers: BASIC_COLOURnoviceRESET_COLOUR, APPRENTICE_COLOURapprenticeRESET_COLOUR, ADVANCED_COLOURadvanced RESET_COLOURand MASTER_COLOURmasterRESET_COLOUR. Each tier is more powerful than the last. - -BASIC_COLOURNovice RESET_COLOURwands are the ones that can be crafted. They hold up to BASIC_MAX_CHARGE mana, and can only cast novice spells. Novice spells are simple enough to be cast by anyone and they do not usually cost much mana. This does not necessarily mean that they are useless at higher tiers however; their low cost makes some novice spells useful even when you have access to master spells. - -APPRENTICE_COLOURApprentice RESET_COLOURwands are the next tier up from novice wands. They hold up to APPRENTICE_MAX_CHARGE mana and can cast novice and apprentice spells. Apprentice spells are a little more impressive than novice spells but usually cost more. - -ADVANCED_COLOURAdvanced RESET_COLOURwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold ADVANCED_MAX_CHARGE mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on enemies. - -MASTER_COLOURMaster RESET_COLOURwands are the most powerful wands in existence. They hold up to MASTER_MAX_CHARGE mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution. -PAGEBREAK -SECTION Elements -Elements --------------------- -Spells belong to different elements, which describe the nature of the spell and also have perks when used with certain wands. - -FIRE_COLOURFire -Perhaps the most destructive element, fire concerns burning, lava, and explosions. A powerful pyromancer will unleash hell upon their enemies and probably set the world alight in the process. Most fire attack spells set fire to their target, causing ongoing damage over time. However, be wary that fire spells may have no effect on nether mobs. - -ICE_COLOURIce -The element of ice is made of all that is cold. Frost spells often slow enemies down or freeze them completely, and are especially effective on creatures of fire. Frost magic can prove equally useful outside of combat, such as freezing water to cross a river. - -LIGHTNING_COLOURLightning -This element concerns lightning, storms, and the weather. A powerful storm mage is a force to be reckoned with, and some posess the ability to call down lightning at will. Lightning spells often damage multiple enemies at once and usually seek their target, making them an effective attack against any mob... but beware of creepers. - -NECROMANCY_COLOURNecromancy -Necromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon creatures to fight for you or even bend the will of your enemies. - -EARTH_COLOUREarth -The element of earth is focused on the natural world: animals, plants, the wind, and such like. Earth magic is diverse and takes a wide variety of forms, from poisoning enemies to unleashing the fury of the weather. Earth spells are a mixture of attack, defence and utility. - -SORCERY_COLOURSorcery -Sorcery is the element of force and change. Sorcerers manipulate light, gravity and even reality itself to fit their needs. Sorcery spells can be used, among other things, to grant their caster magical powers or move objects to their will. - -HEALING_COLOURHealing -The element of healing is concerned with defence and regeneration. Healers seek to protect themselves and their allies as much as possible and as such can be very difficult opponents. Though generally not used as an attack, the purifying light of some healing spells will do considerable damage to the undead. Healing spells are indispensable when in combat. - -The boundaries between the different elements are not always distinct, and some spells bear traits of elements other than their own. - -If you are lucky, you may happen upon an elemental wand. These wands will allow you to cast spells of the right element for more potency than usual. -PAGEBREAK -SECTION Wizard Armour -Wizard Armour --------------------- -As a wizard, you will need something to protect you from the creatures you fight. No ordinary armour will do though. To make the most of your spells, you will need wizard armour: hat, robes, leggings and boots. Unlike ordinary armour, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much mana. Charge them as you would a wand in the arcane workbench or with a mana flask, but be careful - if they run out of mana, you will find yourself defenceless. - -You can obtain wizard armour by crafting it from magical silk, obtained by crafting string with a magic crystal. - -Those wizards who devote themselves to the practice of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find. - -Legend speaks of an arcane seal used by the most powerful wizards to greatly improve their armour. -PAGEBREAK -SECTION Wizards and Towers -Wizards and Towers --------------------- -Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter tall towers with distinctive pointed roofs. These are the residences of fellow wizards. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder. If, however, it is a master spell you seek, you will need to speak to a specialist. - -Unfortunately, there are a few wizards out there who do not welcome visitors. These wizards are typically outcasts, and are hostile to anyone crossing their path. Approach these individuals with caution, and be prepared to defend yourself against powerful magic. Defeat them however, and their knowledge is yours for the taking. -PAGEBREAK -SECTION Crafting Recipes -Crafting Recipes --------------------- -PAGEBREAK -PAGEBREAK -Crafting Recipes --------------------- -PAGEBREAK -PAGEBREAK -Crafting Recipes --------------------- -PAGEBREAK -PAGEBREAK -Crafting Recipes --------------------- -PAGEBREAK -PAGEBREAK -Credits --------------------- -Electroblob's Wizardry -Version VERSION -For Minecraft MCVERSION - -Designed, coded and textured by Electroblob - -Thanks to Minecraft Forge and MCP, without which this mod would not have been possible. - -Thanks also to the Minecraft modding community, which always has an answer to my modding problems! - -In addition, I'd like to thank the following individuals for their contributions to the mod: - -Code: - -- Corail31 -- 12foo -- Shadows-of-Fire -- HellFirePvP - -Translations: - -- Russian: VilagVil -- Spanish and Mexican Spanish: MadWrist -- Chinese: ZHENGLOC and dragon-evol - -Lightning ray sound effect from OhhWowProductions diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json b/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json index 4c40250d..311a4c20 100644 --- a/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json +++ b/src/main/resources/assets/ebwizardry/texts/handbook_en_us.json @@ -1,11 +1,12 @@ { - "ruler_text": "--------------------", + "bookmark_start_section": "introduction", "colours": { "text": "#000000", "caption": "#666666", "hyperlink": "#601ba0", - "highlight": "#dd4c1d" + "highlight": "#dd4c1d", + "new_section": "#ee88f7" }, "images": { @@ -33,74 +34,196 @@ "width": 36, "height": 33, "texture_width": 48, - "texture_height": 48 + "texture_height": 48, + "border": false }, "magic_wand": { - "location": "ebwizardry:textures/items/wand_basic.png", + "location": "ebwizardry:textures/items/wand_novice.png", "caption": "A Magic Wand", "u": 0, "v": 0, "width": 64, - "height": 64 + "height": 64, + "border": false }, "crystal_flower": { "location": "ebwizardry:textures/gui/flower_picture.png", "caption": "A Crystal Flower", "u": 0, "v": 0, - "width": 64, - "height": 64 + "width": 48, + "height": 48 + }, + "wizard_tower": { + "location": "ebwizardry:textures/gui/tower_picture.png", + "caption": "A Wizard's Tower", + "u": 0, + "v": 0, + "width": 110, + "height": 110 + }, + "wizard_armour": { + "location": "ebwizardry:textures/gui/armour_picture.png", + "caption": "A Set Of Wizard Armour", + "u": 0, + "v": 0, + "width": 90, + "height": 90 + }, + "obelisk": { + "location": "ebwizardry:textures/gui/obelisk_picture.png", + "caption": "An Obelisk", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "shrine": { + "location": "ebwizardry:textures/gui/shrine_picture.png", + "caption": "An Earth Shrine", + "u": 0, + "v": 0, + "width": 110, + "height": 67 + }, + "tiers": { + "location": "ebwizardry:textures/gui/tiers_picture.png", + "caption": "The 4 Tiers Of Wand", + "u": 0, + "v": 0, + "width": 96, + "height": 24, + "border": false + }, + "elements": { + "location": "ebwizardry:textures/gui/elements_picture.png", + "caption": "The 7 Arcane Elements", + "u": 0, + "v": 0, + "width": 106, + "height": 20, + "border": false } }, "recipes": { "arcane_workbench": { - "location": "ebwizardry:arcane_workbench" + "locations": [ "ebwizardry:arcane_workbench" ] }, "magic_wand": { - "location": "ebwizardry:magic_wand" + "locations": [ "ebwizardry:magic_wand" ] + }, + "novice_wands": { + "locations": [ + "ebwizardry:magic_wand", + "ebwizardry:wand_fire", + "ebwizardry:wand_ice", + "ebwizardry:wand_lightning", + "ebwizardry:wand_necromancy", + "ebwizardry:wand_earth", + "ebwizardry:wand_sorcery", + "ebwizardry:wand_healing" + ] }, "magic_missile_spell_book": { - "location": "ebwizardry:magic_missile_spell_book" + "locations": [ "ebwizardry:magic_missile_spell_book" ] }, "wizard_handbook": { - "location": "ebwizardry:wizard_handbook" + "locations": [ "ebwizardry:wizard_handbook" ] }, "crystal_flower_to_crystals": { - "location": "ebwizardry:crystal_flower_to_crystals" + "locations": [ "ebwizardry:crystal_flower_to_crystals" ] }, - "mana_flask": { - "location": "ebwizardry:mana_flask" + "crystal_blocks": { + "locations": [ + "ebwizardry:crystal_block", + "ebwizardry:crystal_block_fire", + "ebwizardry:crystal_block_ice", + "ebwizardry:crystal_block_lightning", + "ebwizardry:crystal_block_necromancy", + "ebwizardry:crystal_block_earth", + "ebwizardry:crystal_block_sorcery", + "ebwizardry:crystal_block_healing" + ] + }, + "crystal_blocks_to_crystals": { + "locations": [ + "ebwizardry:crystal_block_to_crystals", + "ebwizardry:crystal_block_to_crystals_fire", + "ebwizardry:crystal_block_to_crystals_ice", + "ebwizardry:crystal_block_to_crystals_lightning", + "ebwizardry:crystal_block_to_crystals_necromancy", + "ebwizardry:crystal_block_to_crystals_earth", + "ebwizardry:crystal_block_to_crystals_sorcery", + "ebwizardry:crystal_block_to_crystals_healing" + ] + }, + "crystal_shard": { + "locations": [ "ebwizardry:crystal_shard" ] + }, + "small_mana_flask": { + "locations": [ "ebwizardry:small_mana_flask" ] + }, + "medium_mana_flask": { + "locations": [ "ebwizardry:medium_mana_flask" ] + }, + "large_mana_flask": { + "locations": [ "ebwizardry:large_mana_flask" ] + }, + "runestone": { + "locations": [ + "ebwizardry:runestone_fire", + "ebwizardry:runestone_ice", + "ebwizardry:runestone_lightning", + "ebwizardry:runestone_necromancy", + "ebwizardry:runestone_earth", + "ebwizardry:runestone_sorcery", + "ebwizardry:runestone_healing" + ] + }, + "runestone_pedestal": { + "locations": [ + "ebwizardry:runestone_pedestal_fire", + "ebwizardry:runestone_pedestal_ice", + "ebwizardry:runestone_pedestal_lightning", + "ebwizardry:runestone_pedestal_necromancy", + "ebwizardry:runestone_pedestal_earth", + "ebwizardry:runestone_pedestal_sorcery", + "ebwizardry:runestone_pedestal_healing" + ] }, "transportation_stone": { - "location": "ebwizardry:transportation_stone" + "locations": [ "ebwizardry:transportation_stone" ] }, "magic_silk": { - "location": "ebwizardry:magic_silk" + "locations": [ "ebwizardry:magic_silk" ] }, "wizard_hat": { - "location": "ebwizardry:wizard_hat" + "locations": [ "ebwizardry:wizard_hat" ] }, "wizard_robe": { - "location": "ebwizardry:wizard_robe" + "locations": [ "ebwizardry:wizard_robe" ] }, "wizard_leggings": { - "location": "ebwizardry:wizard_leggings" + "locations": [ "ebwizardry:wizard_leggings" ] }, "wizard_boots": { - "location": "ebwizardry:wizard_boots" + "locations": [ "ebwizardry:wizard_boots" ] }, "blank_scroll": { - "location": "ebwizardry:blank_scroll" + "locations": [ "ebwizardry:blank_scroll" ] }, "firebomb": { - "location": "ebwizardry:firebomb" + "locations": [ "ebwizardry:firebomb" ] }, "poison_bomb": { - "location": "ebwizardry:poison_bomb" + "locations": [ "ebwizardry:poison_bomb" ] }, "smoke_bomb": { - "location": "ebwizardry:smoke_bomb" + "locations": [ "ebwizardry:smoke_bomb" ] + }, + "spark_bomb": { + "locations": [ "ebwizardry:spark_bomb" ] } }, @@ -146,13 +269,19 @@ "include_in_contents": "main_contents", "text": [ - "To get started with wizardry, you will need a few things:", + "To get started with wizardry, you will need:", - "- A magic wand, crafted with a gold nugget, a stick, and a magic crystal.", + "- A magic wand, crafted as shown:", - "- An @arcane_workbench arcane workbench@, crafted with 3 stone, 1 lapis lazuli block, 2 magic crystals, 2 gold nuggets and 1 purple carpet.", + "#recipe magic_wand", - "- A @spells spell@ book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, with a book and 4 magic crystals.", + "- An @arcane_workbench arcane workbench@, crafted like so:", + + "#recipe arcane_workbench", + + "- A @spells spell@ book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, as shown:", + + "#recipe magic_missile_spell_book", "You will also need a bunch more magic crystals to supply your wand with @mana@." ] @@ -172,7 +301,7 @@ "#image magic_crystal", - "It is widely accepted that mana cannot be created or destroyed, and that when a spell is cast, the mana it channels is simply dissipated into the surroundings. Indeed, this is how the vast majority of mana exists - spread thinly throughout the world. However, to be of any use, it must be concentrated, either naturally over thousands of years, as is the case with crystals underground, or artificially - an advanced subject covered later in this book. There also exist various ways of making spells more mana-efficient and recovering some of the mana dissipated during spellcasting." + "It is widely accepted that mana cannot be created or destroyed, and that when a spell is cast, the mana it channels is simply dissipated into the surroundings. Indeed, this is how the vast majority of mana exists - spread thinly throughout the world. However, to be of any use, it must be concentrated, either naturally over thousands of years, as is the case with crystals underground, or artificially - an advanced subject not covered in this book. There also exist various ways of making spells more mana-efficient and recovering some of the mana dissipated during spellcasting." ] }, @@ -190,7 +319,7 @@ "Most wands begin their life as a simple arrangement of a magic crystal of some sort attached to a wooden stick, with a gold nugget affixed to the other end. The crystal is, of course, the source of the wand's power, as it provides the focus necessary to channel @spells@. The rest of the wand is important too though, as it provides not only a means with which to hold the wand, but also a path through which @mana@ can be channeled and directed.", - "As more spells are cast with a wand, it grows more effective at channeling @spells@, and can therefore cast spells of greater power. This effect can be discerned from subtle changes that occur in the shape and appearance of the wand itself: as a wand grows more powerful, its crystal will become more vibrant, it may change in color depending on its element, and after a while, the wood from which it is made will start to grow and twist into more complex shapes.", + "As more spells are cast with a wand, it grows more effective at channeling @spells@, and can therefore cast spells of greater power. This effect can be discerned from subtle changes that occur in the shape and appearance of the wand itself: as a wand grows more powerful, its crystal will become more vibrant, its colour may change depending on its @elements element@, and after a while, the wood from which it is made will start to grow and twist into more complex shapes.", "When holding a wand, a small heads-up display will show in the corner of the screen. This indicates the spell that is currently selected along with a pictorial representation of it, and, if the spell has been cast, a cooldown bar indicating the time until that spell can be cast again. It also shows the names of the next and previous spells bound to the wand. To switch between spells, use the #next_spell_key and #previous_spell_key keys (these can be changed in options -> controls). You can also switch spells by scrolling the mouse wheel while sneaking.", @@ -208,11 +337,13 @@ "A @wands wand@ is useless without spells to cast with it. Spells are recorded in two forms: in books, which are permanent, and in scrolls, which are temporary.", - "Spell books are of little use on their own; instead they are used to bind the spell they contain to @wands@. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more detailed information about the spell.", + "Spell books are of little use on their own; instead they are used to bind the spell they contain to @wands@. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more about it.", - "Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself by crafting a blank scroll from a piece of paper and some string. You can then bind a spell to the scroll using the @arcane_workbench arcane workbench@, but only if you have knowledge of that spell (see @enchanting_scrolls Enchanting Scrolls@). Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your @wands wand@. It should be noted, however, that scrolls are at best an inefficient method of casting spells.", + "Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself (see @enchanting_scrolls Enchanting Scrolls@).", - "To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right-clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification in the process." + "Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your @wands wand@. It should be noted, however, that they are an inefficient method of casting spells compared to using a wand.", + + "To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. Futhermore, there is always a chance of misreading an unknown spell when casting, with potentially dangerous consequences depending on how powerful the spell is. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right-clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification in the process." ] }, @@ -230,7 +361,11 @@ ], "text": [ - "The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind @spells@ to your @wands wand@. Simply place it anywhere and right click, and you will see something like this:", + "The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind @spells@ to your @wands wand@. It may be crafted as follows:", + + "#recipe arcane_workbench", + + "The following pages explain the various actions that may be performed in the arcane workbench.", "#image workbench" ], @@ -238,25 +373,34 @@ "binding_spells": { "title": "Binding Spells", "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], "text": [ - "To bind a spell to your wand, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press apply. You will notice that the spell book is left untouched during this process - this is because the act of spell binding does not 'take' the spell from the spell book; rather, it attunes the wand to the spell. As such, you may change the spells bound to your wand as much as you wish by simply repeating the spell binding process. You can bind up to five spells to a wand at one time, though this number may be increased with attunement upgrades." + "To bind a @spells spell@ to your @wands wand@, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press apply. You will notice that the spell book is left untouched during this process - this is because the act of spell binding does not 'take' the spell from the spell book; rather, it attunes the wand to the spell. As such, you may change the spells bound to your wand as much as you wish by simply repeating the spell binding process. You can bind up to five spells to a wand at one time, though this number may be increased with attunement upgrades." ] }, "charging_wands": { "title": "Charging Wands", "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/arcane_workbench" + ], "text": [ - "To charge your wand, place the wand in the central slot of the arcane workbench and place some magic crystals in the upper of the two slots on the left, and then press apply. Each crystal is worth #mana_per_crystal mana, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals so if the wand needs, for example, 30 more mana, #mana_per_crystal_minus_30 mana will be lost when charging it." + "To charge your @wands wand@, place the wand in the central slot of the arcane workbench and place some magic crystals in the bottom-left slot, and then press apply. Each crystal is worth #mana_per_crystal @mana@, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals, so if the wand needs, for example, 30 more mana, #example_charging_loss mana will be lost when charging it." ] }, "upgrading_wands": { "title": "Upgrading Wands", "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], "text": [ - "To upgrade your wand, you will need a tome of arcana of the appropriate tier (see @tiers Tiers@) or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the lower of the two slots on the left, then press apply.", + "To upgrade your @wands wand@, you will need a tome of arcana of the appropriate @tiers tier@ or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the top-right slot, then press apply.", "Special wand upgrades improve a particular aspect of a wand. Each type of upgrade can stack up to three times, and the total number of upgrades that a wand can take depends on its tier. Upgrades cannot be removed." ] @@ -264,9 +408,16 @@ "enchanting_scrolls": { "title": "Enchanting Scrolls", "include_in_contents": "arcane_workbench_subsections", + "triggers": [ + "ebwizardry:handbook/scrolls" + ], "text": [ - "The arcane workbench can also be used to enchant spell scrolls. To do so, you will require a blank scroll, crafted from a piece of paper and some string, a spell book for your chosen spell, and enough magic crystals to provide mana to cast it. Place the crystals in the upper left-hand slot, the blank scroll in the central slot, and the spell book in the single slot that appears above it, then press apply to enchant the scroll." + "The arcane workbench can also be used to enchant @spells spell@ scrolls. To do so, you will require a blank scroll, crafted from a piece of paper and some string, a spell book for your chosen spell, and enough magic crystals to provide @mana@ to cast it.", + + "#recipe blank_scroll", + + "Place the crystals in the bottom-left slot, the blank scroll in the central slot, and the spell book in the single slot above it, then press confirm to enchant the scroll." ] } } @@ -275,11 +426,24 @@ "wizard_armour": { "title": "Wizard Armor", "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:arcane_initiate" + ], "text": [ - "As a wizard, you will need something to protect you from the creatures you fight. No ordinary armor will do though. To make the most of your spells, you will need wizard armor: hat, robes, leggings and boots. Unlike ordinary armor, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much mana. Charge them as you would a wand in the arcane workbench or with a mana flask, but be careful - if they run out of mana, you will find yourself defenseless.", + "As a wizard, you will need something to protect you from the creatures you fight. No ordinary armor will do though. To make the most of your spells, you will need wizard armor: hat, robes, leggings and boots. Unlike ordinary armor, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much @mana@. Charge them as you would a wand in the @arcane_workbench arcane workbench@ or with a @mana_flasks mana flask@, but be careful - if they run out of mana, you will find yourself defenseless.", - "You can obtain wizard armor by crafting it from magical silk, obtained by crafting string with a magic crystal.", + "#image wizard_armour", + + "You can obtain wizard armor by crafting it from magical silk:", + + "#recipe magic_silk", + "#recipe wizard_hat", + "#recipe wizard_robe", + "#recipe wizard_leggings", + "#recipe wizard_boots", + + "One may enchant wizard armour using a normal enchantment table, and due to the inherent properties of magical silk, it tends to be quite effective at holding enchantments. Of particular utility to a wizard are the Magic, Frost and Shock Protection enchantments, which may prove useful defending against other wielders of magic.", "Those wizards who devote themselves to the practise of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find.", @@ -296,6 +460,9 @@ "page_numbers": true, "separator": "." }, + "triggers": [ + "ebwizardry:handbook/on_subsection_unlock" + ], "text": [ "One cannot master the arcane just by staying at home - there is a world full of magic out there to explore! Ancient ruins, relics and mysterious beings good and bad await discovery - if you know where to look. The greatest wizards are also the most curious, and gain much of their knowledge and power through exploration of the environment around them, and experimenting with what they find.", @@ -311,39 +478,59 @@ ], "text": [ - "During your travels, you will probably come across curious glowing flowers growing in the wild from time to time. These distinctive blooms are known as crystal flowers, and they are strangely effective at concentrating mana - to this day, nobody is quite sure why. We do know, however, that they can be harvested and crafted to extract the mana as crystals, making them a rather useful above-ground source of mana. The amount of mana obtainable this way is limited, though, by the small size of the flowers and due to them only growing in small patches.", + "During your travels, you will probably come across curious glowing flowers growing in the wild from time to time. These distinctive blooms are known as crystal flowers, and they are strangely effective at concentrating @mana@ - to this day, nobody is quite sure why. We do know, however, that they can be harvested and crafted to extract the mana as crystals, making them a rather useful above-ground source of mana. The amount of mana obtainable this way is limited, though, by the small size of the flowers and due to them only growing in small patches.", - "#image crystal_flower" + "#image crystal_flower", + "#recipe crystal_flower_to_crystals" ] }, "wizard_towers": { "title": "Wizard Towers", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:wizard_tower" + ], "text": [ - "Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter a tall tower or two with a distinctive pointed roof. This is the residence of a fellow wizard. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder. If, however, it is a master spell you seek, you will need to speak to a specialist.", + "Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter a tall tower or two with a distinctive pointed roof. This is the residence of a fellow wizard. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder.", + + "If, however, it is a @tiers master@ spell you seek, you will need to speak to a specialist.", + + "#image wizard_tower", "Unfortunately, there are a few wizards out there who do not welcome visitors. These wizards are typically outcasts, and are hostile to anyone crossing their path. Approach these individuals with caution, and be prepared to defend yourself against powerful magic. Defeat them however, and their knowledge is yours for the taking.", - "It should also be noted that no wizard will take kindly to being attacked or stolen from - and will readily take the law into their own hands." + "It should also be noted that no wizard will take kindly to being attacked or stolen from - and they will readily take the law into their own hands." ] }, "obelisks": { "title": "Obelisks", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/obelisks" + ], "text": [ "Vestiges of ancient magic are scattered throughout the world, the most notable of which are carved stone structures which bear a great many symbols and runes. These ruins are all that remain of what appears to have been some kind of ancient civilisation. Whoever, or whatever, built them, they clearly had a considerable knowledge of magic, and used it to place protective enchantments over such locations that still persist to this day.", - "These stuctures fit broadly into two types. The first, and more common, of these are obelisks: tall spikes of carved stone, known as runestone, with an open structure at the bottom that usually contains minor arcane relics from the forgotten past. These structures are typically protected by an enchantment that summons hostile magical creatures should any human stray too close. Fend off these creatures and destroy their source, and the relics are yours." + "These stuctures fit broadly into two types. The first, and more common, of these are obelisks: tall spikes of carved stone, known as runestone, with an open structure at the bottom containing minor arcane relics from the forgotten past.", + + "#image obelisk", + + "These structures are typically protected by an enchantment that summons hostile @creatures magical creatures@ should any human stray too close. Fend off these creatures and destroy their source, and the relics are yours." ] }, "shrines": { "title": "Shrines", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:visit_shrine" + ], "text": [ - "The second, and rarer, kind of structure is known as a shrine. These structures consist of a circle of runestone pillars surrounding a central platform, upon which sits a chest filled with ancient artifacts. This chest is typically protected by an arcane lock enchantment, preventing anyone except the owner from opening it. The entire structure is also protected by a containment field, which prevents anything that strays too close from escaping.", + "The second, and rarer, kind of structure is known as a shrine. These structures consist of a circle of runestone pillars surrounding a central pedestal, upon which sits a chest filled with ancient @artefacts artifacts@. This chest is typically protected by an arcane lock enchantment, preventing anyone except the owner from opening it. The entire structure is also protected by a containment field, which prevents anything that strays too close from escaping.", + + "#image shrine", "Due to their great arcane power and significance, not to mention the riches within, these structures are particularly attractive to any aspiring wizard - but be cautious. There are numerous reports of wizards becoming trapped within containment fields and slowly being driven insane, perhaps by claustrophobia. A growing number, however, believe such occurences to be a deliberate part of the shrine's protective magic, and that the wizards trapped within are in fact being controlled to protect the structure. A chilling prospect, surely, for anyone who dares to venture near..." ] @@ -351,17 +538,23 @@ "creatures": { "title": "Magical Creatures", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:handbook/magical_creatures" + ], "text": [ - "Besides wizards, a multitude of other creatures also use magic. Many of these creatures are arcane in origin, and most can be summoned using certain magical spells. One may encounter these creatures guarding an obelisk, or perhaps a powerful summoner. Lesser arcane beings are even found occasionally in the wilderness." + "Besides wizards, a multitude of other creatures also use magic. Many of these creatures are arcane in origin, and most can be summoned using certain magical @spells spells@. One may encounter these creatures guarding an @obelisks obelisk@, or perhaps a powerful summoner. Lesser arcane beings are even found occasionally in the wilderness." ] }, "artefacts": { "title": "Artifacts", "include_in_contents": "magical_world_subsections", + "triggers": [ + "ebwizardry:artefact" + ], "text": [ - "When exploring a shrine, you may be lucky enough to uncover some kind of ancient magical artifact - an object capable of granting its wearer unique and powerful buffs and special powers. Three types are known to have been found: rings, which grant bonuses and effects to spells, amulets, which improve defensive abilities, and trinkets, which give utility effects. These artifacts appear to function only when worn appropriately; simply having them on one's person is insufficient." + "When exploring a @shrines shrine@, you may be lucky enough to uncover some kind of ancient magical artifact - an object capable of granting its wearer unique and powerful buffs and special powers. Three types are known to have been found: rings, which grant bonuses and effects to spells, amulets, which improve defensive abilities, and charms, which give utility effects. These artifacts appear to function only when worn appropriately; simply having them on one's person is insufficient." ] } } @@ -370,26 +563,40 @@ "tiers": { "title": "Tiers", "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/tome_of_arcana" + ], "text":[ - "Wands and spells come in four tiers: #colour_novicenovice#colour_reset, #colour_apprenticeapprentice#colour_reset, #colour_advancedadvanced #colour_resetand #colour_mastermaster#colour_reset. Each tier is more powerful than the last.", + "@wands Wands@ and @spells@ come in four tiers: #colour_novicenovice#colour_reset, #colour_apprenticeapprentice#colour_reset, #colour_advancedadvanced #colour_resetand #colour_mastermaster#colour_reset. Each tier is more powerful than the last.", + + "#image tiers", "#colour_noviceNovice #colour_resetwands are the ones that can be crafted. They hold up to #novice_max_charge mana, and can only cast novice spells. Novice spells are simple enough to be cast by anyone and they do not usually cost much mana. This does not necessarily mean that they are useless at higher tiers however; their low cost makes some novice spells useful even when you have access to master spells.", "#colour_apprenticeApprentice #colour_resetwands are the next tier up from novice wands. They hold up to #apprentice_max_charge mana and can cast novice and apprentice spells. Apprentice spells are a little more impressive than novice spells but usually cost more.", - "#colour_advancedAdvanced #colour_resetwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold #advanced_max_charge mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on enemies.", + "#colour_advancedAdvanced #colour_resetwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold #advanced_max_charge mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on foes.", - "#colour_masterMaster #colour_resetwands are the most powerful wands in existence. They hold up to #master_max_charge mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution." + "#colour_masterMaster #colour_resetwands are the most powerful wands in existence. They hold up to #master_max_charge mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution.", + + "To be upgraded to a higher tier, a wand must first become powerful enough to channel spells of that tier. Wands gain power as spells are cast with them. Spell variety, spell power, elemental effects and other external factors may all have an effect on how quickly a wand matures.", + + "Once a wand is sufficiently powerful, a tome of arcana provides the final catalyst needed to elevate the wand to the next tier (see @upgrading_wands Upgrading Wands@), and once this has happened, the maturing process can begin again for the next tier." ] }, "elements": { "title": "Elements", "include_in_contents": "main_contents", + "triggers": [ + "ebwizardry:handbook/elements" + ], "text": [ - "Spells belong to different elements, which describe the nature of the spell and also have perks when used with certain wands.", + "@spells Spells@ belong to different elements, which determine the nature of the spell and also grant perks when used with certain @wands@.", + + "#image elements", "#colour_fireFire#colour_reset \nPerhaps the most destructive element, fire concerns burning, lava, and explosions. A powerful pyromancer will unleash hell upon their enemies and probably set the world alight in the process. Most fire attack spells set fire to their target, causing ongoing damage over time. However, be wary that fire spells may have no effect on nether mobs.", @@ -397,7 +604,7 @@ "#colour_lightningLightning#colour_reset \nThis element concerns lightning, storms, and the weather. A powerful storm mage is a force to be reckoned with, and some posess the ability to call down lightning at will. Lightning spells often damage multiple enemies at once and usually seek their target, making them an effective attack against any mob... but beware of creepers.", - "#colour_necromancyNecromancy#colour_reset \nNecromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon creatures to fight for you or even bend the will of your enemies.", + "#colour_necromancyNecromancy#colour_reset \nNecromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon @creatures@ to fight for you or even bend the will of your enemies.", "#colour_earthEarth#colour_reset \nThe element of earth is focused on the natural world: animals, plants, the wind, and such like. Earth magic is diverse and takes a wide variety of forms, from poisoning enemies to unleashing the fury of the weather. Earth spells are a mixture of attack, defense and utility.", @@ -407,22 +614,7 @@ "The boundaries between the different elements are not always distinct, and some spells bear traits of elements other than their own.", - "If you are lucky, you may happen upon an elemental wand. These wands will allow you to cast spells of the right element for more potency than usual." - ] - }, - - "growing_crystals": { - "title": "Growing Crystals", - "include_in_contents": "main_contents", - "text": [ - - "Magic crystals normally form naturally underground over thousands of years, by gradually drawing latent mana from the surrounding rock as they grow. Crystalline structures are very good at absorbing and holding mana, hence the mana is naturally drawn towards them. Given the right conditions, however, it is possible to greatly speed up this process. This has given rise to the advanced technique of crystal growing, which requires both great patience and attention to detail.", - - "In order to encourage crystal growth, one must begin with a crystal seed. The most effective seeds have proven to be crystal shards, obtained by simply shattering a magic crystal into pieces. A crystal seed must then be planted into some kind of substrate, usually rock, although other materials are also viable. Left alone, this would produce a sizeable crystal in hundreds of years, depending on the conditions.", - - "To reduce this length of time, several things can be done. Immersing the seed and substrate in mineral-rich water helps with crystal growth, but not with concentrating mana. To concentrate mana more quickly, two techniques can be employed: firstly, surrounding the growth site with lesser mana-gathering objects allows the crystal to draw from them, meaning the surrounding environment is constantly replenished with mana. Too many, however, and they begin to draw mana away from the growing crystal. Secondly, mana can be drawn through some materials better than others: air is very poor at this, whereas dense materials tend to be much better. Some wizards have taken to experimentation with exotic, magical, or even otherworldy materials to try and improve crystal growth. Some even claim to have altered the type of crystal that is formed in this way.", - - "If conditions are exactly right, it is even possible for crystals to grow far beyond their natural size. Such crystals are known as grand magic crystals, and besides containing a great quantity of mana, they have a few specific uses." + "If you are lucky, you may happen upon an elemental crystal. Elemental crystals are magic crystals that have absorbed elemental properties as they have grown - though the exact conditions required and mechanism by which this happens remain a mystery. We do know, however, that such crystals may be used to create elemental wands, which allow spells of the right element to be cast with more potency than usual." ] }, @@ -435,37 +627,57 @@ "page_numbers": true, "separator": "." }, + "triggers": [ + "ebwizardry:on_subsection_unlock" + ], "sections": { "mana_flasks": { "title": "Mana Flasks", "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/mana_flasks" + ], "text": [ "Arkendur's Arcane Supplies Co. - magical items for your every need!", - "Need to recharge your wand on the go? No problem! Mana can now be bottled.** Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge.*", + "Need to recharge your @wands wand@ on the go? No problem! @mana Mana@ can now be bottled. Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge. *", - "NEW! Introducing the brand-new large*** and small mana flasks - now you can choose a size of mana flask to meet your needs!", - - "* This process will consume the bottle.", - "** Some mana is lost during bottling.", - "*** Large mana flask requires grand magic crystals." + "#recipe medium_mana_flask", + + "NEW! Introducing the brand-new small and large mana flasks - now you can choose a size of mana flask to meet your needs!", + + "#recipe small_mana_flask", + "#recipe large_mana_flask", + + "* This process will destroy the bottle. Some mana is lost during bottling." ] }, "throwable_items": { "title": "Throwable Items", "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:handbook/throwables" + ], "text": [ - - "Various spells conjure physical items, some of which can also be crafted directly. Firebombs, poison bombs, spark bombs and smoke bombs can all be crafted." + + "Various @spells@ conjure physical items, some of which can also be crafted directly. Firebombs, poison bombs, spark bombs and smoke bombs can all be crafted:", + + "#recipe firebomb", + "#recipe poison_bomb", + "#recipe smoke_bomb", + "#recipe spark_bomb" ] }, "automated_casting": { "title": "Automated Casting", "include_in_contents": "miscellaneous_subsections", + "triggers": [ + "ebwizardry:enchant_scroll" + ], "text": [ - "Recent experimentation has revealed that it is possible to automate spell casting, to a degree, using nothing more than a simple dispenser. Nobody is quite sure why, but it would appear that the strange properties of redstone even extend to triggering the activation of spell scrolls. Placing a few into a dispenser and powering it ought to do the trick..." + "Recent experimentation has revealed that it is possible to automate @spells spell@ casting, to a degree, using nothing more than a simple dispenser. Nobody is quite sure why, but it would appear that the strange properties of redstone even extend to triggering the activation of spell scrolls. Placing a few into a dispenser and powering it ought to do the trick..." ] } } @@ -477,11 +689,18 @@ "text": [ "#recipe arcane_workbench", - "#recipe magic_wand", + "#recipe novice_wands", "#recipe magic_missile_spell_book", "#recipe wizard_handbook", "#recipe crystal_flower_to_crystals", - "#recipe mana_flask", + "#recipe crystal_blocks", + "#recipe crystal_blocks_to_crystals", + "#recipe crystal_shard", + "#recipe small_mana_flask", + "#recipe medium_mana_flask", + "#recipe large_mana_flask", + "#recipe runestone", + "#recipe runestone_pedestal", "#recipe transportation_stone", "#recipe magic_silk", "#recipe wizard_hat", @@ -491,7 +710,8 @@ "#recipe blank_scroll", "#recipe firebomb", "#recipe poison_bomb", - "#recipe smoke_bomb" + "#recipe smoke_bomb", + "#recipe spark_bomb" ] }, @@ -502,8 +722,6 @@ "Electroblob's Wizardry \nVersion #version \nFor Minecraft #mcversion", - "For more information, check out the @https://github.com/Electroblob77/Wizardry/wiki wiki@.", - "Designed, coded and textured by Electroblob", "Thanks to Minecraft Forge and MCP, without which this mod would not have been possible.", @@ -514,13 +732,17 @@ "Code:", - "- Corail31 \n- 12foo \n- Shadows-of-Fire", + "- Corail31 \n- 12foo \n- Shadows-of-Fire \n- Tora-B \n- Avatair \n- Aeronica", "Translations:", - "- Russian: VilagVil \n- Spanish and Mexican Spanish: MadWrist \n- Chinese: ZHENGLOC", + "- Spanish and Mexican Spanish: MadWrist \n- Russian: VilagVil, kellixon \n- French: Hahdrim \n- Brazilian Portuguese: lorrampi \n- Chinese: ZHENGLOC, dragon-evol \n-Korean: shejery, rewi_wire", - "Lightning ray sound effect from OhhWowProductions" + "Lightning ray sound effect from OhhWowProductions", + + "For more information, check out the @https://github.com/Electroblob77/Wizardry/wiki wiki@.", + + "Can't get enough wizardry? Join the @https://discord.gg/MTmMzMv Discord server@ for the latest news, discussions and extras!" ] } diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_en_us.txt b/src/main/resources/assets/ebwizardry/texts/handbook_en_us.txt deleted file mode 100644 index 5cae001e..00000000 --- a/src/main/resources/assets/ebwizardry/texts/handbook_en_us.txt +++ /dev/null @@ -1,225 +0,0 @@ -PAGEBREAK -LINEBREAK - - - - -The Wizard's Handbook - - - -By Electroblob -PAGEBREAK -Introduction --------------------- - -Greetings, wizard! This book explains the many ways of the arcane and how to use them. - -Should you ever lose this book, you can get a new one by crafting a book with a magic crystal. -PAGEBREAK -Contents --------------------- -PAGEBREAK -SECTION Setting up -Setting up --------------------- -To get started with wizardry, you will need a few things: - -- A magic wand, crafted with a gold nugget, a stick, and a magic crystal. - -- An arcane workbench, crafted with 3 stone, 1 lapis lazuli block, 2 magic crystals, 2 gold nuggets and 1 purple carpet. - -- A spell book. These can be found in chests, dropped as loot, purchased from wizards, or you can make a beginner's spell, magic missile, with a book and 4 magic crystals. - -You will also need a bunch more magic crystals to supply your wand with mana. -PAGEBREAK -SECTION Mana -Mana --------------------- -Mana is the arcane energy that gives wizards their powers. It manifests itself in naturally occurring crystals, which can be found embedded in rocks underground. Wands can store mana within them, and this mana is channeled into the spells that you cast. Different spells cost different amounts of mana, depending on how powerful they are and how long they last. - -Mouse over a wand to see how much mana is stored in it. -IMAGE CRYSTAL -LINEBREAK - - - - - - - Magic - Crystal Ore Crystal -PAGEBREAK -SECTION Wands -Wands --------------------- -The wand is the implement of choice for a wizard. With it, you can cast any spell provided the wand can contain its power (see Tiers for a more in-depth explanation). Wands come in -various different varieties but you will almost certainly start with a basic magic wand. - -When holding a wand, a small heads-up display will show in the corner of the screen. This indicates the spell that is currently selected along with a pictorial representation of it, and, if the spell has been cast, a cooldown bar indicating the time until that spell can be cast again. -PAGEBREAK -SECTION Spells -Spells --------------------- -A wand is useless without spells to cast with it. Spells are recorded in two forms: in books, which are permanent, and in scrolls, which are temporary. - -Spell books are of little use on their own; instead they are used to bind the spell they contain to wands. Spell books can be found throughout the world and it will not take long for you to come across one. When you do find one, you can mouse over the spell book to see basic information about the spell at a glance. You can also right-click whilst holding a spell book to read more detailed information about the spell. - -Scrolls, on the other hand, serve a different purpose: right-clicking whilst holding one will cast the spell that is bound to it, destroying the scroll in the process. Like spell books, scrolls can be found throughout the world, but you can also make them yourself by crafting a blank scroll from a piece of paper and some string. You can then bind a spell to the scroll using the arcane workbench, but only if you have knowledge of that spell. Doing so will consume a number of magic crystals equal to the mana cost of the spell (rounded up to the nearest MANA_PER_CRYSTAL). - -To the untrained eye, the magical runes with which spells are written are unreadable. In order to identify a spell, you could, of course, cast it and see what happens - though doing so may cause unwanted side-effects, and many spells need certain conditions in order to work. A safer and more reliable option is to use a scroll of identification, which can be found in chests or purchased from a wizard. Right- -clicking whilst holding one will identify the first unknown spell book or scroll on your hotbar, consuming the scroll of identification. - -Scrolls are quite useful when you need to use a spell once or twice on a particular quest but don't want it to take up a slot on your wand. It should be noted, however, that scrolls are at best an inefficient method of casting spells. -PAGEBREAK -SECTION Arcane Workbench -The Arcane Workbench --------------------- -The arcane workbench is a block similar in appearance to the enchantment table where you can charge, upgrade, and bind spells to your wand. Simply place it anywhere and right click, and you will see a gui appear like the one to the right. -PAGEBREAK -IMAGE WORKBENCH -LINEBREAK - - - - - - - - - - - - - - The Arcane Workbench -PAGEBREAK -SECTION Binding Spells -Binding Spells --------------------- -To bind a spell to your wand, simply place your wand in the central slot of the workbench, then place the spell book in one of the surrounding slots and press apply. You can bind up to five spells to a wand at one time, though this may be increased with attunement upgrades. When holding a wand, you can switch between spells with the NEXT_SPELL_KEY and PREVIOUS_SPELL_KEY keys (these can be changed in options -> controls). You can also switch spells by scrolling the mouse wheel while sneaking. - -SECTION Charging Wands -Charging your wand --------------------- -To charge your wand, place the wand in the central slot of the arcane workbench and place some magic crystals in the upper of the two slots on the left, and then press apply. Each crystal is worth MANA_PER_CRYSTAL mana, and the wand will only take what it needs, so you can keep a supply of crystals in the workbench for when you need them. However, bear in mind that the wand can only take a whole number of crystals so if the wand needs, for example, 30 more mana, MANA_PER_CRYSTAL_MINUS_30 mana will be lost when charging it. All wands will take an exact number of crystals to charge if they are empty, unless they have a storage upgrade applied. - -SECTION Upgrading Wands -Upgrading your wand --------------------- -To upgrade your wand, you will need a tome of arcana of the appropriate tier (see Tiers) or a special wand upgrade. Both of these can be found as loot or purchased from a wizard. To upgrade your wand, place it in the central slot and the upgrade in the lower of the two slots on the left, then press apply. - -Special wand upgrades improve a particular aspect of a wand. Each type of upgrade can stack up to three times, and the total number of upgrades that a wand can take depends on its tier. Upgrades cannot be removed. -PAGEBREAK -SECTION Flowers and Flasks -Flowers and Flasks --------------------- -You will probably come across curious glowing flowers growing in the wild from time to time. These are crystal flowers, a naturally occurring source of mana. They can be harvested and crafted to extract the mana as crystals. - -Need to recharge your wand on the go? No problem! Mana can now be bottled. Simply craft a mana flask with a glass bottle and eight magic crystals and take it with you. When you need to use it, simply craft it with your wand and it will restore some of the charge. This process will consume the bottle. Some mana is lost during bottling. -PAGEBREAK -SECTION Tiers -Tiers --------------------- -Wands and spells come in four tiers: BASIC_COLOURnoviceRESET_COLOUR, APPRENTICE_COLOURapprenticeRESET_COLOUR, ADVANCED_COLOURadvanced RESET_COLOURand MASTER_COLOURmasterRESET_COLOUR. Each tier is more powerful than the last. - -BASIC_COLOURNovice RESET_COLOURwands are the ones that can be crafted. They hold up to BASIC_MAX_CHARGE mana, and can only cast novice spells. Novice spells are simple enough to be cast by anyone and they do not usually cost much mana. This does not necessarily mean that they are useless at higher tiers however; their low cost makes some novice spells useful even when you have access to master spells. - -APPRENTICE_COLOURApprentice RESET_COLOURwands are the next tier up from novice wands. They hold up to APPRENTICE_MAX_CHARGE mana and can cast novice and apprentice spells. Apprentice spells are a little more impressive than novice spells but usually cost more. - -ADVANCED_COLOURAdvanced RESET_COLOURwands are quite rare and are much more powerful. They can cast all spells except master spells, and hold ADVANCED_MAX_CHARGE mana. Advanced spells can grant superhuman powers such as invisibility and wreak havoc on enemies. - -MASTER_COLOURMaster RESET_COLOURwands are the most powerful wands in existence. They hold up to MASTER_MAX_CHARGE mana, and can cast any spell. Master spell books are very rare and the spells can cause complete devastation not only to enemies but even the world itself. Use with caution. -PAGEBREAK -SECTION Elements -Elements --------------------- -Spells belong to different elements, which describe the nature of the spell and also have perks when used with certain wands. - -FIRE_COLOURFire -Perhaps the most destructive element, fire concerns burning, lava, and explosions. A powerful pyromancer will unleash hell upon their enemies and probably set the world alight in the process. Most fire attack spells set fire to their target, causing ongoing damage over time. However, be wary that fire spells may have no effect on nether mobs. - -ICE_COLOURIce -The element of ice is made of all that is cold. Frost spells often slow enemies down or freeze them completely, and are especially effective on creatures of fire. Frost magic can prove equally useful outside of combat, such as freezing water to cross a river. - -LIGHTNING_COLOURLightning -This element concerns lightning, storms, and the weather. A powerful storm mage is a force to be reckoned with, and some posess the ability to call down lightning at will. Lightning spells often damage multiple enemies at once and usually seek their target, making them an effective attack against any mob... but beware of creepers. - -NECROMANCY_COLOURNecromancy -Necromancy is the element of darkness, chaos and the undead. Necromancers are mysterious and often regarded as evil, though this is usually not the case. Necromancy spells are commonly used to summon creatures to fight for you or even bend the will of your enemies. - -EARTH_COLOUREarth -The element of earth is focused on the natural world: animals, plants, the wind, and such like. Earth magic is diverse and takes a wide variety of forms, from poisoning enemies to unleashing the fury of the weather. Earth spells are a mixture of attack, defense and utility. - -SORCERY_COLOURSorcery -Sorcery is the element of force and change. Sorcerers manipulate light, gravity and even reality itself to fit their needs. Sorcery spells can be used, among other things, to grant their caster magical powers or move objects to their will. - -HEALING_COLOURHealing -The element of healing is concerned with defense and regeneration. Healers seek to protect themselves and their allies as much as possible and as such can be very difficult opponents. Though generally not used as an attack, the purifying light of some healing spells will do considerable damage to the undead. Healing spells are indispensable when in combat. - -The boundaries between the different elements are not always distinct, and some spells bear traits of elements other than their own. - -If you are lucky, you may happen upon an elemental wand. These wands will allow you to cast spells of the right element for more potency than usual. -PAGEBREAK -SECTION Wizard Armor -Wizard Armor --------------------- -As a wizard, you will need something to protect you from the creatures you fight. No ordinary armor will do though. To make the most of your spells, you will need wizard armor: hat, robes, leggings and boots. Unlike ordinary armor, these will not break. Instead, they use arcane energy to shield the wearer. This of course means that they must be charged with magic crystals, just like wands. Fortunately, these garments do not consume much mana. Charge them as you would a wand in the arcane workbench or with a mana flask, but be careful - if they run out of mana, you will find yourself defenseless. - -You can obtain wizard armor by crafting it from magical silk, obtained by crafting string with a magic crystal. - -Those wizards who devote themselves to the practice of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find. - -Legend speaks of an arcane seal used by the most powerful wizards to greatly improve their armor. -PAGEBREAK -SECTION Wizards and Towers -Wizards and Towers --------------------- -Fear not - you are not the only practicioner of magic in this world. On your travels, you may well encounter tall towers with distinctive pointed roofs. These are the residences of fellow wizards. A life of solitude can make wizards a little grumpy at times, but they are usually friendly folk who are willing to share their knowledge with you - albeit for a price. Expect to pay precious metals and gems, and in return you will recieve many a great arcane wonder. If, however, it is a master spell you seek, you will need to speak to a specialist. - -Unfortunately, there are a few wizards out there who do not welcome visitors. These wizards are typically outcasts, and are hostile to anyone crossing their path. Approach these individuals with caution, and be prepared to defend yourself against powerful magic. Defeat them however, and their knowledge is yours for the taking. -PAGEBREAK -SECTION Crafting Recipes -Crafting Recipes --------------------- -PAGEBREAK -PAGEBREAK -Crafting Recipes --------------------- -PAGEBREAK -PAGEBREAK -Crafting Recipes --------------------- -PAGEBREAK -PAGEBREAK -Crafting Recipes --------------------- -PAGEBREAK -PAGEBREAK -Credits --------------------- -Electroblob's Wizardry -Version VERSION -For Minecraft MCVERSION - -Designed, coded and textured by Electroblob - -Thanks to Minecraft Forge and MCP, without which this mod would not have been possible. - -Thanks also to the Minecraft modding community, which always has an answer to my modding problems! - -In addition, I'd like to thank the following individuals for their contributions to the mod: - -Code: - -- Corail31 -- 12foo -- Shadows-of-Fire -- HellFirePvP - -Translations: - -- Russian: VilagVil -- Spanish and Mexican Spanish: MadWrist -- Chinese: ZHENGLOC and dragon-evol - -Lightning ray sound effect from OhhWowProductions diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_es_es.txt b/src/main/resources/assets/ebwizardry/texts/handbook_es_es.txt index 90cea3cd..237a026e 100644 --- a/src/main/resources/assets/ebwizardry/texts/handbook_es_es.txt +++ b/src/main/resources/assets/ebwizardry/texts/handbook_es_es.txt @@ -173,7 +173,7 @@ Niveles Las varitas y los hechizos vienen en cuatro niveles: BASIC_COLOURBasicoRESET_COLOUR, APPRENTICE_COLOURAprendizRESET_COLOUR, ADVANCED_COLOURAvanzadoRESET_COLOUR y MASTER_COLOURMaestroRESET_COLOUR. Cada nivel es mejor que el anterior. Las varitas BASIC_COLOURBasico RESET_COLOURson las que pueden ser crafteadas. Almacenan -BASIC_MAX_CHARGE mana, y solo pueden lanzar hechizos basicos. Hechizos basicos son suficientemente simples para ser lanzados por cualquiera y no usan mucho mana. Esto +BASIC_MAX_CHARGE mana, y solo pueden lanzar hechizos basicos. Hechizos basicos son suficientemente simples para ser lanzados por cualquiera y no usan mucho mana. Esto no significa que son inservibles en niveles mas altos, sin embargo; su costo pequeno hace que algunos hechizos basicos sean utiles cuando tienes acceso a hechizos maestros. diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_es_mx.txt b/src/main/resources/assets/ebwizardry/texts/handbook_es_mx.txt index 90cea3cd..237a026e 100644 --- a/src/main/resources/assets/ebwizardry/texts/handbook_es_mx.txt +++ b/src/main/resources/assets/ebwizardry/texts/handbook_es_mx.txt @@ -173,7 +173,7 @@ Niveles Las varitas y los hechizos vienen en cuatro niveles: BASIC_COLOURBasicoRESET_COLOUR, APPRENTICE_COLOURAprendizRESET_COLOUR, ADVANCED_COLOURAvanzadoRESET_COLOUR y MASTER_COLOURMaestroRESET_COLOUR. Cada nivel es mejor que el anterior. Las varitas BASIC_COLOURBasico RESET_COLOURson las que pueden ser crafteadas. Almacenan -BASIC_MAX_CHARGE mana, y solo pueden lanzar hechizos basicos. Hechizos basicos son suficientemente simples para ser lanzados por cualquiera y no usan mucho mana. Esto +BASIC_MAX_CHARGE mana, y solo pueden lanzar hechizos basicos. Hechizos basicos son suficientemente simples para ser lanzados por cualquiera y no usan mucho mana. Esto no significa que son inservibles en niveles mas altos, sin embargo; su costo pequeno hace que algunos hechizos basicos sean utiles cuando tienes acceso a hechizos maestros. diff --git a/src/main/resources/assets/ebwizardry/texts/handbook_ko_kr.txt b/src/main/resources/assets/ebwizardry/texts/handbook_ko_kr.txt new file mode 100644 index 00000000..6071ff5a --- /dev/null +++ b/src/main/resources/assets/ebwizardry/texts/handbook_ko_kr.txt @@ -0,0 +1,239 @@ +PAGEBREAK +LINEBREAK + + + + +마법사의 안내서 + + + +By Electroblob +PAGEBREAK +소개 +-------------------- + +안녕하신가 마법사 친구! 이 책에서는 마법과 그 사용법을 다룬다네. + +만약 이 책을 잃어버려도 슬퍼하지 말게. 책과 마법 수정으로 다시 만들 수 있으니 말이야. +PAGEBREAK +목차 +-------------------- +PAGEBREAK +SECTION 시작하는 법 +Setting up +-------------------- +마도의 길을 걷기 위해선 몇가지 도구가 필요하다네. + +- 마법 지팡이, 금 조각과 막대기, 마법 수정 각 1개를 작업대에 대각선으로 놓아 시작의 지팡이를 만들 수 있네. + +- 아케인 작업대, 작업대에 돌 3개를 아래에 두고 그 위로 청금석 블록과 보라색 카펫을 쌓아 올리게, 마지막으로 양 끝을 마법 수정 - 금 조각 순으로 쌓으면 되네. + +- 주문서. 이건 상자에서 찾거나 마법사와 거래하는 수 밖에 없네, 그래도 가장 기본적인 주문은 책 주위를 마법 수정 4개로 둘러싸 만들 수 있지. + +그리고 마법 수정은 마나를 충전하는데 쓰이니 많이 필요할 걸세. +PAGEBREAK +SECTION 마나 +마나 +-------------------- +마나는 우리에게 힘을 주는 신비한 에너지일세. 보통은 지하에서 결정체로 나타나지. 마법 수정 한개에는 100의 마나가 담겨 있네. + +우리는 마나를 지팡이에 저장해서 주문을 사용하고, 주문마다 그 위력이나 지속력에 따라 사용하는 마력의 양이 다르다네. + +지팡이에 마우스를 올리면 남은 마력의 양을 알 수 있네. +PAGEBREAK +IMAGE CRYSTAL +LINEBREAK + + + + + 수정 광석 마법 수정 +PAGEBREAK +SECTION 지팡이 +지팡이 +-------------------- +지팡이는 마법사의 무기일세. 지팡이가 감당하는 한에서는 어떠한 주문이라도 쓸 수 있지. + +지팡이에는 많은 종류가 있지만 대부분이 처음에는 시작의 지팡이를 사용할 걸세. + +지팡이를 들고 있다면 화면 구석에 작은 창이 나타날 게야. 거기 있는 그림이 지금 대기중인 주문이고 그 옆의 막대기가 다 차야먄 그 주문을 다시 쓸 수 있네. +PAGEBREAK +SECTION 주문 +주문 +-------------------- +주문 없는 지팡이는 물 없는 호수와도 같지. 주문은 두가지 형태로 기록되는데, 첫 번째는 영구적인 주문서이고 두 번째는 일시적인 두루마리라네. + +주문서는 아케인 작업대를 이용해 지팡이에 주문을 저장하는데 쓰이네. 이건 잠시 뒤에 설명하지. 주문서는 전 세계 어디서든 찾을 수 있네. 주문서를 찾으면 간단한 정보를 훑어볼 수 있고, 책을 펴 보면 자세한 정보를 얻을 수 있네. + +두루마리는 좀 다르다네. 단 한번만 사용할 수 있지. 두루마리도 세계 어디서든 찾을 수 있지만 종이 한 장과 실을 사용해 직접 만들 수도 있네. 그리고 아케인 작업대에서 알고 있는 주문을 각인하면 되네. 이때 마법 수정으로 마력을 주입해야 하니 주의하게. + +대부분의 마법의 문자들은 배우지 않은 사람은 읽을 수 없네. 주문을 써봐서 알아내는 방법도 있지만 위험하지. 이럴때는 지식의 두루마리를 사용하는게 좋네. 이 두루마리는 마법사와 거래하거나 여러 유적을 찾아보면 있을 걸세. + +두루마리는 한두번 사용해야 하지만 지팡이의 공간이 부족할때 쓸만한 수단이네. 하지만 두루마리는 몹시 비 효율적이라는 걸 기억하게. +PAGEBREAK +SECTION 아케인 작업대 +아케인 작업대 +-------------------- +아케인 작업대는 겉보기에는 인챈트 테이블과 비슷하게 생겼네. 마법사는 여기서 지팡이를 강화하고 주문을 저장하지. 사용하려 하면 다음과 같은 화면이 나올 걸세. +PAGEBREAK +IMAGE WORKBENCH +LINEBREAK + + + + + + + + + + + + + + 아케인 작업대 +PAGEBREAK +SECTION 주문 저장 +주문 저장 +-------------------- +지팡이에 주문을 넣으려면 아케인 작업대에 지팡이를 올리고 주변에 주문서를 두면 된다네. 한번에 최대 5개의 주문을 저장할 수 있지만 지팡이를 개조하면 최대 8개의 주문을 저장할 수 있네. + +지팡이를 든 채로 주문을 바꾸려면 쉬프트-휠을 쓰거나 지정된 키를 쓰면 되네. + +SECTION 지팡이 충전 +지팡이 충전 +-------------------- +마법을 쓰다 보면 지팡이의 마력이 부족하기 마련이지. 지팡이를 충전하려면 아케인 작업대에 지팡이를 올리고 왼쪽 칸에 마법 수정을 올리면 되네. 그러면 100의 마력을 충전하지. + +SECTION 지팡이 강화 +지팡이 강화 +-------------------- +마법사가 지팡이를 강화하는 방법에는 두가지 종류가 있지. + +첫 번째는 등급에 맞는 마도서를 찾아 지팡이 자체의 격을 높이는 걸세. +두 번째는 특수한 도구를 사용하여 지팡이의 효율을 높일 수 있네. 마도서와 도구들 모두 유적이나 마법사에게서 얻을 수 있네. + +특수한 개조는 지팡이의 어느 한쪽 능력을 높혀주지. 같은 개조는 3번까지 중첩할 수 있고 최대한 개조할 수 있는 횟수는 얼마나 중첩했느냐에 따라 다르네. 또한 한번 개조된 지팡이는 되돌릴 수 없네. +PAGEBREAK +SECTION 꽃과 플라스크 +꽃과 플라스크 +-------------------- +전에 마법 수정은 지하 암석에서 얻을 수 있다는 말 기억하나? 사실 마법 수정을 얻는 방법에는 한가지가 더 있네. 지상의 꽃들은 가끔씩 마력을 띄고있는 경우가 있어. 이러한 꽃들에게서 마력을 추출하면 마법 수정을 만들 수 있네. + +혹여 이동중에 마력을 충전해야 하나? 문제 없네. 마력은 병에 담을 수도 있다네. 유리병 한개에 8개의 마력 수정을 두르면 마나 플라스크가 완성되네. 언제든 지팡이와 이를 조합하여 700의 마력을 회복할 수 있네. +PAGEBREAK +SECTION 등급 +등급 +-------------------- +지팡이와 주문들은 4개의 등급으로 나뉜다네 : BASIC_COLOUR초보자RESET_COLOUR, APPRENTICE_COLOUR견습생RESET_COLOUR, ADVANCED_COLOUR숙련자 RESET_COLOUR그리고 MASTER_COLOUR대가RESET_COLOUR. + +BASIC_COLOUR초보자RESET_COLOUR가 사용하는 시작의 지팡이는 BASIC_MAX_CHARGE 마력을 지니고 있네. 초보자 주문들은 금방 익힐 수 있을 정도로 간단하고 사용하는 마력이 적어. 하지만 그렇다고 해서 높은 수준에서 쓸모없지는 않다네. 특유의 저마력으로 대가들 조차 유용하게 사용하지. + +APPRENTICE_COLOUR견습생RESET_COLOUR들의 지팡이는 초보자들의 다음 지팡이지. APPRENTICE_MAX_CHARGE 마력을 지녔고 초보와 견습 주문을 외울 수 있네. 여기엔 유용하고 적당한 주문들이 많이 있지. + +ADVANCED_COLOUR숙련자RESET_COLOUR가 된 마법사는 몹시 강력하다네. 그들의 지팡이는 ADVANCED_MAX_CHARGE 마력을 지니고 대가의 주문을 제외한 모든 주문을 외울 수 있어. 이 등급의 주문들은 적을 직접 파괴하고 초인적인 힘을 줄 걸세. + +MASTER_COLOUR대가RESET_COLOUR의 지팡이는 현존하는 최강의 지팡이라네. MASTER_MAX_CHARGE 마력을 지니고 모든 주문을 사용할 수 있지. 이 단계의 주문은 몹시 드묾어서 찾아보기도 힘들지만 그 여파는 엄청날 걸세. 주의하게나. +PAGEBREAK +SECTION 원소 +원소 +-------------------- +거의 모든 주문들에는 각자의 속성이 존재하네. 이에 알맞는 지팡이를 사용하면 높은 효율을 보일 수 있지. + +FIRE_COLOUR화염 +아마도 가장 파괴적인 속성이 아닐까 하는군. 강력한 화염술사는 적을 불태우고 자연을 파괴하네. 화염 주문들은 불꽃을 내뿜고 지속되는 고통을 야기하네. + +ICE_COLOUR빙결 +서리와 얼음, 그리고 모든 차가운 것을 포함하는 속성일세. 적들을 얼려 둔하게 만들 수 있지. 아니면 아예 얼음에 가두는건 어떤가? + +LIGHTNING_COLOUR전격 +위험하기로는 이만한 속성도 없을 걸세. 번개와 폭풍을 다루는 속성이네. 강력한 폭풍술사는 무시무시한 번개를 마음대로 다루지. 이 주문들은 동시에 여러 적을 상대하기에 알맞네. + +NECROMANCY_COLOUR사령 +사령술은 어둠과 혼돈, 언데드를 부리는 마법일세. 보통은 사악한 이미지가 많다마는 꼭 그런것도 아닐세. 이들은 자신을 도울 친구들을 부르고 적들의 의지를 꺽어버리는데 능숙해. + +EARTH_COLOUR자연 +자연은 매우 다양한 요소의 집합체이지. 동물과 식물, 하늘과 대지. 자연의 마법은 그 유형이 몹시 다양하다네. 아무렴 모든 것은 자연의 일부니까 말이야. + +SORCERY_COLOUR신비 +이 신비한 힘은 자세히 밝혀진게 적네. 빛부터 중력, 공간까지 뭐 하나 쉽게 설명할 수 없는 요소를 두루 다루지. 그래도 확실히 편리하기는 하다는군. + +HEALING_COLOUR치유 +치유의 힘은 자네를 보호하고 다시 일으켜 세울 게야. 대부분의 주문이 생명의 보호와 유지에 몰려있고 공격 능력은 매우 낮아. 하지만 일부 언데드에게는 치명적일 수 있네. + +물론 이 모든 속성들이 엄격히 구분되는 것은 아니네. 어떤 주문들은 다른 속성의 힘을 쓰기도 하지. + +운이 좋다면 원소가 깃든 지팡이를 얻을지도 모르지. 이 지팡이들은 맞는 힘에게 강력한 조력이 될게야. +PAGEBREAK +SECTION 마법사의 방어구 +마법사의 방어구 +-------------------- +마법사로서 싸워 나가려면 그에 걸맞는 갑옷이 필요하지. 오래전부터 전해지던 마법사의 방어구는 평범한 갑옷과는 다르다네. 이 방어구들은 마력이 존재하는 한 찢어지거나 파괴되지 않을 걸세. + +마법 수정에 4개의 실을 둘러 마법 천을 짤 수 있네. 이 천들을 이용하면 마법사의 방어구가 완성되지. + +간혹 특정한 분야에 전문화된 마법사는 그 분야에 도움을 주는 더욱 특별한 옷을 찾아다닌다네. 물론 이런 방어구는 몹시 드묾지. + +전설에 의하면 특수한 마법으로 이 방어구들을 더욱 강화할 수 있다더군. 믿거나 말거나 말이야. +PAGEBREAK +SECTION 마법사와 탑 +마법사와 탑 +-------------------- +두려워 말게 어린 마법사여. 이 넓은 세상에 어디 마법사가 자네 하나겠나? + +세상을 떠돌다 보면 뾰족한 탑에 사는 고독한 마법사들을 보게 될 걸세. 이들은 홀로 지식을 탐구하는 이들이지. + +자네가 원한다면 대가를 내고 그들의 지식을 배울 수 있네. 물론, 그 반대도 가능하지. 단지 이들은 좀 너무 혼자 있어서 그런지 꽤나 괘팍하다네. 절대 이들의 집에선 아무것도 부수지 말게. + +그리고 불행하게도 너무 오래 혼자인 마법사들은 세상을 배척하게 되기도 하지. 이들은 옛 향수에 빠져서는 모든 이들에게 적대적이지. + +이들은 위험한 존재일세. 하지만 이들을 무찌른다면, 그의 지식은 자네 것일세. +PAGEBREAK +PAGEBREAK +SECTION 조합법 +조합법 +-------------------- +PAGEBREAK +PAGEBREAK +조합법 +-------------------- +PAGEBREAK +PAGEBREAK +조합법 +-------------------- +PAGEBREAK +PAGEBREAK +조합법 +-------------------- +PAGEBREAK +PAGEBREAK +마치며 +-------------------- +Electroblob's Wizardry +Version VERSION +For Minecraft MCVERSION + +디자인, 코드 및 텍스쳐 by Electroblob + +마인크래프트 포지와 MCP에게 감사합니다. 이들이 없었다면 이 모드는 완성되지 못했을 겁니다. + +또한 마인크래프트 모딩 커뮤니티에게도 감사합니다. 문제가 생기면 늘 대답을 해줬어요! + +마지막으로, 모드에 도움을 준 아래의 각 개인들에게 감사합니다. + +코드: + +- Corail31 +- 12foo +- Shadows-of-Fire +- HellFirePvP + +번역: + +- 러시아어: VilagVil +- 스페인어와 멕시코 스페인어: MadWrist +- 중국어: ZHENGLOC and dragon-evol +- 한국어: rewi_wire + +번개 광선의 음향 효과: OhhWowProductions diff --git a/src/main/resources/assets/ebwizardry/textures/armour/invisible_armour.png b/src/main/resources/assets/ebwizardry/textures/armour/invisible_armour.png deleted file mode 100644 index 892b9537a21e50551194322f4d148dfdddd39f2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2411 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEb}-In zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifGI0tDiOQW+7GhxF_~Gf|7*cWTZFF>w zOt|E~XGLY#cE_#XURIVIq`tIsqwH?4rN>y0iacd>-C{b$tB-}%iG?+=`N^K8i?l?( zGBPRDN1CzgeGeU%OR$eRRIUeE-%q7)5MxwP|7&b&GE z?#N>On>(0`Hw%_-~SPBH|AkpdaRnSZrhVT%fJ6y`{d7d{WA+Dvd8!Pnx!&s z?8x}r9WLvFrK)`{8kBxoBEG}l54h07RR-11t6I)a`BO}`s zST^q3*HqhS@$9)iBg4F1AJQ{cvAJG8aIit6;{lJuMV^Ms3$m;ZO=5AqJ~3Q`r9+eP z(C2^>S!3?myal{PQX;XgaaR|vIB>H1SK+H0i7m`FPLo=G%S#_G-v8b`VB$u7!Q(%E z-v01YKE}cOwpk%E6ur!z7f{w{a$Huv-o&n|H_2|0QzbWA;?RcH6t z>{BJH&G|^C2bGKr3$mV73oB1>+rY4{K3`(hvZfD8Z1=v$@sz!9op%4gr(05C##-N0 zZV5gJwfWy3UXcGkmZ9PPxtJrh@-{7BeMP0EBabL4-HMJ@WSM1Hn#p*1{eD*0a78Yq zlEV$FGBcD|Dt()my`Hd{DQa==L#9X0Bp=0pS~F_bw`GS4zkz2ywOuWK{9V@7T-izU$G2P|?%b*$fR=d%DE`|7`o} zy>vobvh8+Lmun|1Uo#%JPda};e(v_;oa@i;4GR4G;NTHgon@O}bhK@laW3i6g?6uX z{&&AB{W{j(^@_(n+M;LXM9(k1{8vraW!yMY8!UED_NKz>zkL}m?#|}9T3zu}ylqp~ z_e7!9yv%&1^Vt|uo~pJixqCxYdV^q0^xSRF7;Zc>FAo2h|1;_C%<|7)Yo2j=Y&d(& zM6_*^x1xY$fXnhHK@t0`Lhmtc`V>?e#Z|@>t-zrEn8Beb_kqWmn)6H7{B(H2(7`Rs zFu^OPA#2A)w$-I!yVo?V5QwnSnv=_TaOOnMGd(_Gd-vtnoQOIbYECMcMCT?J--A%+hz>1LO76h<-%l^E zzv)w+6LI8ImDpQdMV7AzHcgI_^Wy`cJGdF&nk^??EJepP2k9$kTaYw_ZnKc**l zt6lHaocz+4^|3np$F=PuE{CtWHi^99>*J03Zg*NkwCl6lhf?khJei)>#UTP`?aaE` z-rm|8bHFe@_|Ch7E5Z$)s0$RaI;vmV#TaDy;nSk{Io8?L<^TQ#ZDgLi*pfl|hsD{s zbZ^IXJ)_Ydz>GHnofxogYC8RePTU(_b{WZl=|H7J; z3X?qjl9f{z)fY$S$DX~RtFta8Ah_JEE{`+R=1**a;xeJH2biDvN17EL>9tf3sALRV zI_)sm)$H?C{ZH55=NE}8-WDj(@Zvk$itYN-g||Ij9AEY1*VL&V4f{X)bu%i@W))#Q z^?V;kAH$P7EL*0>ZCWeNbw-=NZjXSUxX`+joDS2vUo-mg{+xSzRbq-=}oE%x8|xn_fZs! zbSREq|2)y_?9Y$?v+lH~wspJ2{FPwXk+G$t%})B|7In4{Q(dZ~ONFOwW++qn+@Ey) z`@a-JH_80}$JS3gWB+PbU$>j%yjr%#_`b(IXW(#OWG<~h=WT;WWYNJl(b@ z`l*rMTj`TaGXG6VIozbgquHRAI)^pz#3ozmHD;2ZChxdnUG+v<-YNb|^0Vq+;i;QF z)?bMF;uZIbvFU5VJr8<*W zZ&-5I?22|Ne$$Zse1%Bu*|`gg7Kd>!cx#ZgYl`MJwg~U%9&5ffn12#W*zKHGaXsynr$PfCtOlkY;a_15#tK7f?Y;SPChwA9Mo z`W)-3Qpxq_0uTQ`?)hta!keql!@T0>SVwOw-eOUHZPDV!=)=(td#&8pT<}qxF=L~$ n!-bVEgAVu351PB~Kco2dUy3?5yjvL<7#KWV{an^LB{Ts5Xe@i@ diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour.png new file mode 100644 index 0000000000000000000000000000000000000000..71917bbb7c21c13060bbb21a6fd247806196b750 GIT binary patch literal 12450 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 Slo=Qp7(8A5T-G@yGywoVLe$3q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_earth.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..81ed19477216aebb5c0f64f9e0cf1faf386ffcb0 GIT binary patch literal 13287 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 I=akR{0F=AJA^-pY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_earth_legs.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_earth_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..c7c4fb3eab1cf92abeb5c2a8f34ea4d69972ac9c GIT binary patch literal 1726 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq|91DkP#LD6w3jpeR2r zGbdG{q_QAYA+;hije()!*4yytN!sc>f73-HowyY_ryceVz3Dh@K6Ba|$^P_r$}3O# z?>f!9R!nG)vWm>J`1-0J%;KV6ik+#ttHjrZ1a*qet+~4{+B^K#`P!wQIp51aQQTMC zAz&D_Z|^IcU!p~oJR6cbZ@E`)sC)Ay`9)2I@rl!)Kb3v?WO(GG+VanGrzFEK?|wQ* z{Et7tIBam-G@^@l)u}p_+50D3-_6t z!(5-cv>6P0kKUicLtB4#EvNu9xpdZ^m16FeF!%Ed_vRAz(J`nprGLJ4NkG*n0j zm2BaM1K;GWbb4$~t(dIll(|eZc==hI(`))7ioZR1^y=Bo?(5ds?N|HPTof+8zuB#Q z>(Pi?Ro@bLlQx?RZ@JW|bM8Qd56iJ!!-j^w?#>=kUh(aPr!Shbg*)!6WP>-y{K zEMiU4Gf#M0B&y16DJgk=sa;{G#iWq-rw=0&#Ai?c+>q`b_v*F6Lc1=XE2V7emqnY; zesf{IBs=M1$5y@17Pbep`y{({d_Ud2U>X$dw2hG|VeOQbmJ$g^oG$%A`fP5URk(Gtt;YdkA{l|i;B&M z=(gOJo&^W&e3Xq&U0)@3H>~8h!G{?eKD=R8*w8FpKGSzYuB>-5z-*KL;5)3~_4@IX8VkD0TNNjSTQ90OL2j?lJfOC2ZL^Cz)@>^%)&`+${eivVueM<&H+n-;+ve z*kH&Y9aQpT%3?u7k3Bp4yOh_iU3_A9%!b|9SDUTj6YETAEd9ruwsgPtltm&h85kJY zlDyqr7)~%eWnk#%=h9C&xNJXev z@NrhkoMpxvdoL1-i1p}OCCpFx@aN*qJ&&UTUgqY%UG_43tL6GFkE1TU zTy}Xnzsup!XQjIeIUihoQt|J_p&5SWc8o>R?ul#eFmB4LVai}HsbxQ5Z=EW*(8HXe z;n5E!vkwa{r8~xba)~K!TqRv!QI)=ZkMo}w3}zn;rueKbx&3Rea!T{2IQ6>eTWy$p mC#qR~^9-wwS=XE2B|LG@BG0!aF8vG)3=E#GelF{r5}E*BJ0&*& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_fire.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..972abbc6fa75aa6d48bad7500e1faf892ae06fd2 GIT binary patch literal 13116 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 AFaQ7m literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_fire_legs.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_fire_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..a66695791418aa99c98b79f028ddf0f37b5fdcf6 GIT binary patch literal 1703 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq~_FRY*ihP-3}4K~a8M zW=^U?No7H*LTW{38UsVct+(OPleE=&{-%pYGC6S^EIQ&Gded>*eCBr>k3XJSovpU= zl>aQF3t5UsEQKCy`1kAbVfl&`S)7quriFPOnH-&W^1{lG-|j?p{k-!0`NXsDN{|i zn(%2>iho+NAf0X9gRBPAHjBHp3yt%wKl84dQ7L31d{83sh&Sha&ibHtZFkCF2;~~Q z=GFc&wT$6V@7X)+7P2~>(D!-zpxSH43`NGVU&2%(WPreNM=&2w_cFf#ZBKeg0HPvfb!kAGtMFSVZ?TK4XKf?m!my=QTizgxCuK6iQOeBs=o-prKa$Jkm! zbwh8bU+Ta8!Jqd}{tJ8aE#)jZTeY6)#I>t?0M5`J%kG z+1j(#UC*)(&)9$D$3oX>a!VubS#5k_6PsmNW2jY^nOk+RlK1%03g1trHKi%`L4}q3 zuKw;>Yi2c1a;@^gG(R)(O=UVMg@xDR3RGMqA4PPRmo*#C;4{D7>t4P!x_7srr}LrJ zf;kRBuD>>z-aZg%AO6vZYhA@&)0%=evUi;&FU!hpS!XhLVb^aa&P}&+w%+TF7K~EO zD+%_$F?-j##C03GYlXLay^RTbu&;n~1LIM>w!N8~vd%Hz>y=){y5XPP!4Jk6@e_IN zo4<+P{9v1r|FOCEcPi(@>clUqY{nDLZ`(Nkneo-Pd&?b*Qrs6vi#23jTevy>y@h^J z=_+sA=to@B{KYGqf{!dusEt$8`^@jWCGh~uQs<3{`exhhDtot>UKg4ZV8gZDwmw$o z*rmJdDk^V+vW~pf@1H2ZzRn|V#@B_%S5!W`wCDYvW0o6!9Jv_69I5zqby0pjP$fN-2ra$Y%A75;VJH}MN#WRctMYY*4Q z{Bb+}zk6kax`N{+8?O@+aycALAKt9_y5{-b%#YR2lWn{LIDbFA`MW(_eouYbzl|pz z*ED=TUapf^{eR_qg{&{86XvY*2#H}WJJRftqTcs0S5dBC>urKW+U75{$2E)<9Ueuo zZ9BirYQwV0|8`i`-(zzTa1#2T_m6EZ%c3fE;|q)o3=C{Z-tI08CmA9c_}@*jtY%EalYaqsQ)y?sp% zBCY2oBBx4hZaFgl*r9Vjgv$1{@^62i@+Q|rZG|D5N^ru$Ud_F5SPz=vdKGr!;4$T`ViIv}(40 zPSEk*ZpXN#xA{ZH9mbIDc8q(NSM6hdao$hq`-JBYex1txCD6w{*=|zdBB76G*hB99 zSYa=`{!iPFtBi*}esJ}fT@vgb&>V7JSbnN4ldIrKiHBzc<`q_&?bFa(t~oFL>%qP8 Q3=9kmp00i_>zopr0C2q^RR910 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_healing.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..5d4c2faecdbbd8074a6e6b0711c09bc971bdc1be GIT binary patch literal 14008 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 HDWM4f)LU5b literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_healing_legs.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_healing_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..da815502e7eb131d8dac21c47ea3dd90a1b9077c GIT binary patch literal 2067 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq^ZoDkP#LD6w3jpeR2r zGbdG{q_QAYA+;hije()!*4yyNO;0uW{-%p=W#Lw2Ih{B`DT{sYAG1XTR$B zr)j;eSF)v~k1cQ0|3B|un#at%HMJ{a_1m z`)o$LB=Yy!ueSZn{_AONqur#8x_AD&f5H&c)9izjn78GdX{?~Rp^DtO+weNOt>i@|ZWGN0?(VyjH|H(cL$ z@SW6oo_{>9yIvVDtULJPrTS0HGWLc2QWv9*>*W}-t7`YyB|P6Zd-vUIy+Ms3zWssM zl^<;}C}i@oJFS&>)c?Y@;_^GZYI+U(4n8}wSE%%q!|jz9mO1*B-Rl+$(Yd+l(cI6c zYJN#&zpMP{%b53R&4P6Gya!p0rf%hRFP+lw*L{obXsFFSbjC-(E#l+hxpmimmcN^> z@Vy{*5yR%Y5svF+_&7|Pc2*>baVXXsOl^L@^K$pK@7f)y1{&s)v=kJkNL#HtTM@5mEHV9^@Phs zZ+cC=((|U(lq+v-;COh7D@(vZVYNu(|BTEJ3l()#J3U0Fs>QlJjaqdjYO7nH)TyYD zEvvFFuUlNG?HiSQE9!ObmphW0K2>jLRlVNZ-{{Nk!oNmthT*X@lhbD!y}oiYZGQ5> z+OWt?uP$8;i%))jR{G)o*Vne(epf9a8FR9$Gc-8+TCPRS*_++n;o@<-d&Ziq;aW}B|Sk$oawO?&w+)-1!bmMs_exFZ(cQSax#ig z<}5N}O-|S#ky=<)`2E}+{Yvkke?s{`t)B%2eBYm-$6Cr?Z2#$-@U?FiqOJUnf~}1& zkMUTKB`PTyDnnF zb0xXc)$4R!+x;J!N+=ffKiaZk-|ai<_kG`=`n`*FTemRRt-W`SwZ{Hm6?h@>);qa* zvC|gsIq~4~$A5P#w`N>@nOc*hEV4|*_{gUtt1iX#2FIIjPuo*%ekIODYwf$x>6hoM zYP)lJ^Sj2b*zfc1nd#2XI$>$GUcip=^|K@UvOoV;zO}gGSoM!{Z}*m(C>XosJ$rk0 z!dkay&pa$@BW0C!kJcUZ+}bO-B0XWnwxuRpcNGT8-Dcl3Rk2th-Pirwq2%1}mgV!k zZtq;awJ=HXqY?KRDbd|hUz=n~AMa$)R8cg27^wZ}#I~*J#{9l%3-)D;dq#b`=W+aO zVD&>|71^&_U5x$a*8iGoSITgOcPaBB#w*8``NuDf4m4o%UmDK6<&B|I# z#TDOOPhM-fo84`q{lW1v+o@%T|9iF17pP!cu}`ajJ*P;u!_nc*$voMWMPjx2-q-x{ zqIDgrvpK(AKOHCUuUjP zcd=L4oZ2mV^!Ou|9byT$1ihIHnigJeo59@*Qs0+m6>=?AqpW zJzp=?*HjBh!T5ryg6~51lMI^x=uYy0*Z?7>S>0bIu8|XNIx9N{c9Bi+bY5ZFB7<^&_bR*wH4vp?1b7ka-x@xW?6U57YdoxAfn)$Gm6l`mDk$1mqtu&Mf&{tcC+?<&W97BVm}uqAoByDFdh=n3au}Rpp2Bgy#$ljCP(bjv*QM z-cB>jJLDkX`d`V+MZ40+%2N?y{`a8{Je!{b*q<~+bYs#023a%TR8U-@A zmpiz$10xdZ;@Q^>YI6k(SjS22d?B7EBsUV_V40@ z#mvXDqy8pe;yvUR^ND%tmVI~UZ>;`jGuM~lv8j#5veI37N+Hdw=B=rl_Lgf&>kU0c jzSl=y7iHE){b7C<+%KNnz&4$Mfq}u()z4*}Q$iB}id@%Z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_ice.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_ice.png new file mode 100644 index 0000000000000000000000000000000000000000..2ee99037c7916363fadf7054ef05b92eecf92e35 GIT binary patch literal 14111 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 Mr>mdKI;Vst0KQ2zRR910 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_lightning.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_lightning.png new file mode 100644 index 0000000000000000000000000000000000000000..abd9333fe6df7c68f240d3a49f389efbf261ed7a GIT binary patch literal 12621 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_lightning_legs.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_lightning_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..2ce2af0cc141f7b4052aa8536f85df60cc74fffa GIT binary patch literal 1749 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq_-KDkP#LD6w3jpeR2r zGbdG{q_QAYA+;hije()!*4yyNNl!F*{yrBeX5n7g`gnupqI`qn^VwgXirTeGc~_Ov zv-CF}%^L+C*?MYR{`K2^$^L@Cz3W1b#H@bRy822`vGeiu$G>L0)OudIuBiUd@7*7# z#M`Ct7)I6Yd9~}Q^s%R;4k1}7|^9z7yHZ&!F?#DS^OQI`H^t6MILm)V@2_M2z-mp63` z=l36Ym$jW`f4fp_755AFo_B?l&Tq8l*t@kOZr9Jh>=&O4*(Zt{+9uhSUGHMj^!>hU zUG&kHjvJW0>@II}I_!U8dvW-kK3%>ByMt-RZG}QlIasf_u*A*r^_FHfADzln=h>f6 z)Et|md)dqfwwsI@t2ZJZsy`+P!8QdDxyFcyl9R_b+Ex@v5)7 zb~eUOo@l+~OW#zf&EOIdoxo!#v13Yv$IDG~dO0kteq?U2DLyI7Gr?ot6s9`{N(VPR z-)r_vLiVQ4Ps5%oOiC?Nd9NrmID~03{onZL!$LJ3)y|HtPVcG9*0{Qc`j+=)9SigE zIeTVpRPnb*k6t}{cQyL#)QN|dWNi)Ed+nB#SZ=^wgWZmcw$8Kueraj;_IG=~nLV&u z%p+-)^JB&0vo@7Vf0p}sUrwK!d$CD-?WUBMo1U&-C-!0M0}aK6i4Ox8+eYq=tUWJP zoAB=Xnu}*|rLB>%tWM=UoTjgpv0V7(oW_kY96h(w82ILzr%w;otTf(kxjV}(z=JJY zW%eA;*@gxYVyT=}Mc+@|(XaFls_WkVN3=LI_jBswB|Bj zCeAJ-%`$EKo80-H_wz2#*ZL8Ev3^}fI!m`|-iZgcQZaEH>+HRG+kWpS^xGS+{>x(POS7dfR=vnyW!soS458vnITCR^&KGiYd+qU??jEAn( zQ;waFJAHIVCeM*y2LfZQKR3MO$nP>;q-Pe(`1*EvFxmI{a2IzE~wbc&qH=O_Q$MjJXZQm|t3u9C zFS+>BU;O{hR4xOa!!R`2q~)q?lAY{M_PKHKuNZfG$G>=A^+r2HdYZ}0*GFSqW;TRe zvR3$-=bAjf;mCUitIrGtH*PaDIBk6LbK<)5YRQZYVdWWj1nYiXw@TO?#TRfo{vz?E0? zdw#y$=+9ufIa0URy5Uv*bcTD3p0^plq`O;1Tbz?(D6k4sG)kTECGGSyEy43K3!0A2 z|IGaHr1gS SuaJR(fx*+&&t;ucLK6VN084NH literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_necromancy.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..f90e785c186fad065b074f186f14b60078a3e5db GIT binary patch literal 12490 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE=_->+leEB^WU zt!Mf7_Pn;^``@$Qp1E#cFZup;{QjKpTfUe6zbx|1^S$&Xed)dHZ~rL2Ez4aSKk;wz zbNT%dH~&W7*1!GM_Vm5i@7A@pES*$o{`KampW^v%W?Y)zue#6Zzw5ub=fj__-f*<> zqWZlzHN45IOCzdpCoIn`yIs1E-#Q|x;B@LfYx6nw>qY0smL855|B$-<^p13?_zzbP zWY3#^_j=Tuo%y!krMDG4&#YX&Ip)l#&ia~}`}h9%|LJS#!o8xquGu|39k%AQCPQSK z&GP+~;(Qx_Z_Tv%W*h(P=gZms$+mJm$IrC#Zd-oe`%A|EBh&2bzU|SsJGkd%&gUBa zhRz-3DTdb`H>yX<=Wg;Z(~Itw<^Gqs=FZOtR&pB*cV(VEWVDr`&HnD%_f@*@pH};<-oELE zbIgv-zioNKJ2!p~`u*|Rhlczm=VWfWiMyq*EoMwytMc#YrsSBqUt-78($~&BdC2pI z?CEERcE3KfqsH}K%E+r8M&CCcYpX6vxpUw2iATs(iCyZ+zz`~L3{ zm@tyF z-|zR%HfL4)#Qn2RocRCl_cN#3?+>^Y3X!TJ}dBe>XYGV%q8utNR~s z9C~c|``NXK!}{XBdJ;twFI8`xEBj-@o3nW(o@abk^hfS~ZgsQx=y=9=r{beaxaUs2cI2wj`v+Mk)!vw-Ei)@N{HT01=I)h8 zuK#YnQN9_Pq{RLE#?5aw%-Wv2uHRx3qsQQuyDGW$y02Ez%7KOTryFHHE3di_NhAymYwh36aC?#(Qdm}^D^J?asOsqddL0EvX--bHf)TV?e{zV zH+{TOtjZB_dZ(j`cKXw*DIC|UirOlYr2{|AF-v5LDQOjKJ0SVvNZVblN(Y_EH;Ths zxhnr^Z|1q4(_r zFoAjHoM|Qsm7-sAF5Il?kzILivwn}Y=hE398KQS;&Y5~BS~PEB%iUk+W}Q&-KRCgL zS;d2Ya_LROPy~Fvd0bwiq7p6N@R+eZ}%~OER;#hM z9}a6)S3U4M>U)v9uglb?R_9LP0}VNgsOSe0?l1a{6ggQH1pD5<%wg7KiOEsmQV|jn z`p=U8Cs3^Ap+)ldc8fcE=U!>rADH(;q*tTEU65*-u^)Q0PL#bqy@c}y5Z7Teh6-#=j&QeJ^H#c{K z-}PmRm5-N-XuUhHANA}0|2#XJu$GXV^oc#mt<`U1H5~s4U8=0}-1cMn+U3G>l@7ZO zq@22{Vsv&}-yu`}@*Pu|ztnXyTYj2rHeqAa@+N)8pqk!AH(oLo8Z2^Oa&UuoCllYQ zPxrH0OAbn{Jl45TDD)lw@-?S0rMcLw4ce8Epd$%-#X$eE!EeF0}o<}SXvW~Rqwq|vv3(P#f zBw^=-2|2PQ40TKW0$e-RW+rOPeei7F75xOiQ1$YzvmH(v6Q`c6vepl}vpw>ORD`>j zdIBTU3q9tb1B)gKxbF46WX|lYknu21?3c~Wq&PkwiRS)b*Mfx~=4uB>7;kenyWt$J zP_900qW`HqY=ZV7($k!n9?a9UH!TcU>#>#D)amOirOySj-#572W7#Cu^=#*g?W+=B zUXXU;-m&`U71@_&{kp3)&6`6e6q?NLdTtlH{dLvr;@KKoqX(0A(QSseJhg2tlTMbQOKe3V^7eE_YFqJloWP7Qfvr}bL7%1 zbpLU8U&JP*f+r3qcd@JP&fBVVviXO?98bk2u7v(yA{{mn1&5bPUv;RM*0S%|n+N7I z)I;_&Y~~HU(8)hBd537B=BI~3smnL+;d87Jo|zxE^66A-j^Ip9#@f8h3K!n3eNEx{ zf^$N+lf*60&J*&!!+Y$OKckm~%)=zbiV23NJ_h&A`>tqe#8HJWT+&esUP>sGqy^*g(1pIXk`JsB|l+&-tL?xr(WbY@G}*@(_{iadX5 zOU&|FtXFRym)fJ-G_!?wllDfHPt5BUF(|a&nfmk@m-q>{0I7*-0@|80dW$xAXNX)4 zs(54EQSKRBd+S$W#QyN3vl%4TnCaBN+nwutuHvQN76nB^ztYCIyG%hE$Kv-2vrl^0 zlpLk4@O_OW=fkZFRfBG=*!hF$U2*NrLPurI&1dgyzWq;U8c*N}JBu?ct(wYetMWg% zWlIK|Oq_G(r)AiuB=zGSo8k)Zr2D5R>-4L-C)#Kq`P-GX!Mr7B!ihph=RS@0{UKtv zwiry@Zkp}fv$>1Yv?R;qA*T^XmUiCuNf~Ey9&FTXUvxeA#!7>lF5M;H@A-XQsI|%C z3r~w$=g-5pTCO?Rhcv7@>gBVpsrv`R_P-4mx*MT>ZN)g+jTonEi(xHagMO_`|r z+pgG%v&plLZdLfoBrVpp%WUP#s}<&3nH0V?dDiu3x<mcI;o?Q=kPJB1~Y{<%k2x6S|;v2lD(pKf@W&By~$EPuO}iKmX^&h5MTLtb$htc z!Ka%awP-E%j=87r|L$_W5|f`lU)O36IX5Ba2f8u)_O7md;rZtL&DB@tPL^_PpZ{-) zRwF~3wWHc}t8E|ZvyGzTv#zrQW_R3HZqiuF@~Pl>iQY2bTf+6yP7Ar4N+K9qEV8y& zZ$6|s`*>CG&2yrU&VCJkcg{*Clz)X&-&Uu8H!}Yh)_=}rWVv_3eD`@V&b`{t63=++ zij{gSShj294&Buv&p)2}f4TES`Qb^qj4H>EEuZCovi4?#Sl@+nqD7SK#gyoWiyGEl7rc5n z_p754>xZd4o3=;3(^!6cUb*C?@1;V4OnaI?);q}lY?qB=w!EU}=;+gQ+4$6V_qpFM zw;N{5e%#u}6YrSt#9wc1Ug;y&wUb}OuRC*D>$}Kuu^&xW5A9`0FH(I{vW@M06aS9M z0-g^hZ0hn1-K=T)B%?3m#f-lfFaLg_cdzsBTq%xdp(}gle&+hply;-Sq|}h(za0C9 z-Tr}gxdvvdPf7jQxF+O*se$SY-`6=8R{T%kkM|Ecv}a#>zn>BbnI6}NtmPda zEEZ`?6<#?pzx3Sm0|SgnQ_q}vG$7jefASQlk8r8xV^^t@B8gsqbt!zLZG z{pzKr>6O`A+mTV%nW0~>W%;)4U)I+BW?%C0rNRv9AFmX7#3Px#Dq4bhIJ+}?bAo1#d+K#)Ic26t5sC;_%lZCH#zxo;< zbV}#-l9i6x;(7OFHi+^}TXk&p{pIe`?=GHlyMz#l@0^9nLjz+|9yCr_nw=V%wGn(_ca;{5BS4#Cm!7|$-%rKbe6>C?uC)B zGM7j(wcNFxU;b4~Z}GqDVX~Q5M4WpU8D;F=lzW-;*}iSE&v~9lm93uJkb1i2%HgPg z!ISS)lx%p^=E*DRuE2hA&%H}qdT;rwrnPVQ=3=z?tf$qM)wkP?BP*uOGGgK?jqqcT zZrD9Pc>Sk&fudU^x0GIoAb`vi#3N5Z+$iUBElC`GfCir)7Lzw*ax@l@}!rC z#BYCEtWa~etj}b2U)qACfWIqlPRWyfG$W&eqxF`Ggl=JjaM1hGk~t^7tr3wbHBNjh zqm-{S|FrQs2iJ};_l=Q9_iX8ZaQR?Ji?DEKdtsgW90S*dfqQbhYh53`H22W2*K)f5 z{uVt5?6S%e-g!;pDhrGK_aDXG1-JHkEvx;dWmW2Lb!O7KXT{AW=6Nq;^j2toFM27P z$GGM5;Wdm&*IZpAetu(SdUWNTu=~;K?a{ZF%`+CMKRGwxTapgP>ghL^r8&lV9!V{= zlE@2`wMtyFPOxBIsd3^S!DHdc(ht|Utns~Q)Mql8x8vhlx9d__Hh%?eUM(wsef#pN zpYnAghkmVIeEsI$^$!FO8K;J)vu?Sv|DxXiNY8&e{mUw6EfMhRXE1tx`_;SX^&i>m zy_KyUx7(jpU6WM5eZ_=6Q#&_V^{*+OJH1@mR;kfy?>@XZVN=sMcLt-I^tteNuHJ<%>cI}bq>~v$D_ZT+@+Q3y;(we_3KYpB`h_c9E_hX zxb*5~RW21RSJkz_9r>5Hy>1a{R?8`wGJn6VN{$Hs`J3&}BRc$8Ud%Zc^w98x4yRy2 zWOArFgS=;erM$gP;RgA+uM7@*BrK28+VibuPjrs~*}CBVs|7MmiK>mIHX?^ur)m6nVbyhRR>e!V$HiA%WQDqd zl3!e#uTkhBnK9*K&=x&k?H2|0Z`T-htlAu#7wva=L2T8Z6)SxBAFVH7t&B-GdNZf` z`T3pZx0c;cV+-9KYx>e@&!MfsnXA9P=V&jNip+SCwjcWwEUd9=~~ zvWHguES8qu7blFoJ?BSzomY8rMK(aM$jZ6EI z@1_?$JGc4ovp(6DNqP#$?#gNh{5|ibGUxUZg>IoMO2?|pen_6}5T5=2=*I;T?@cb9 z+5S`eD~~_NcN4#0sm3a{MN>UG#b?VL4BRlG`PHlC=i=Y3kl5+MVO_efVwa5M>2y`A zX~s>z?3bO^sl4v}^3A?tDRocN=@+)z9le^nK6CDoxZLLxL~NL@Eu3*+b=#*sU%K8b zGGp}+e-!DeT&x+OUcT+S8GS9*?xOh@fn8L@uc#L{wppq$~eKi zra9ur;old}Kd%T4w*M?=Gk1SwewU6#mcly6{fl<3Nx#6NSi*n8+5Rlk#Vwc5G%E(r zdVFza_S|c|C+7Q2-QBkM%-o3C=^PoWw=b8IH@bc`U@!kFvE}x!u2~+6x{xLNtjC#a zai7$?l1V@9=3P0rC+>RFBB8C@+5cxxk}fUwdUYYE$D-o@;e*|LK_}{X!0KBoTP z?5|2(RaCFlG51XYLfguVdqmcr%J)jiHTt=FcZB%N#TzCjo{PKse1GBHBiWa3U-~Wi zaaGY}R_9hNX3MVkwZGd=f1Ky+Vk&)q&5p}#kaIIL})C z}+qiJF9N}yvPfOYeLU8Y73qbdf&D0`=b@FHlJ-j!~T3? zS;ocs?O)fnhrZ(5W_wa)%GMd&lFRO?gmbg5ewC7|_Gm@KT9S?2_YOXN zqLy^Hxr>+m|D5K=Slzi^2Sl#ArMiA*6BIUPME1cyFm?m{iu`ozNYkua8h4*e- zdN8CbPB`#8f=l6hfRXlU9S(gjoZ$9CL>e%S5w>E1S+-Bf_@wM;B()^Gwd@m-f`o839hQ)*A4d+kpyc%r2uEkZz z-z7F=HD5{Jdj{qw`Y#r0Oz4@L=_KsSEh+J8?SU(E=b0C6-&?d* ze0TX3U)hn6Z}swev5Lmx;#W>@1!B}swa>GNy!L9N?w=&b6Zy?rr&2^y4HsNKyWken zm9N?I|1xHmoa3K#uF7TY+@So~#>N%yGfg}e2|MR4OOF-Pc>d1i{zaC**504oC+lxK zeY)W6!X4Y@Z(x)=XRO&iM@4CRLAA-*Gi+&5vHts~ERp$~6TrJlLd`DbitOaazpl=W z>?&Fm%PC%Bu=TR%s+YX1^dkDJ|D}A&ef?sUs2QFcR*o^K*YPX zW*;vY9&grR7gb=X3UT&#+v96H(eHC}#67j7YWb)W@*j_u@kv)0%jX`fIz5v?#%%t^ z>zQ`Z*IhnmJ^#qKbgTVw1+UjjFRqx?|BjRYPx5L9t&5F~k}h_hQ!~SY^)p^P+@!Hr zYK`5c&dY|Sk4j&$*!;U1>EWgqvG*pFg2xj&)&^dex$(`w_qfPq zt)_pI_MFd^y(?@vY5SGxSN|nnO({PYcv@BPgYX>b&r244S(1L#C1p}o#H^ADTDCF@ zZ2Y~JpF{7@(JIPbki z-fx>#8RA#m)qArh*(BaI-v6T8bow){prZ>yZ_aIJRJ9F?+-EvxkG$TjT}AI@eP0C@Th2Nk z?!SKi&o$Qf7TkE1o@4%Urj>1or`@%H_REvqQ`SATdcpnNN!V## z(^>UBu2rV?W3c@jd;aJZ%uG5nLswgeUgJJ;yVmBt-?}jCb3c|Xv+XL_^fKgQt;L5e zhYw3~UspVBVqo$~WX=`mA`za_cmA>}n|~;oFU@N4n6T8@*za8U|JNGFYUUp0c_L=1 zvfpPm6Qg$Kh7yfWwKWdA4rGeNsUP06;`m&Rw38_Zt@PQ7PAwC4nbw>hd}vqro|P;a z8Vxx`ck86?h`n~_Y>n{ZUp84h@^T;FE|cTwB?@2Oe+`%V*|^L?VCE&B7SnqletbB0 zfY<)aq>TUJyBR^(`t4P-qxbDM4chzaO*7*xwrmqwzJI6k_T+tS(0@7W zYyH}T>(W{-toEI;RZlqW-d%I1bzOR~_hY5odUONXGZ^$GHFN1**QBUD>!$ zs?Bi4%@sNNiYe1~>3@pc^`MMP;?_D<-Z%5zpZ}^X$vdqRSk-09&$6{m{8W=%w#nVs zjEs^VUXyiB<}a%`EnGiYdu@DMRc7DMv&H8oFZT8Sr;@U({nGBJl!XspNu_|v+s6g$y&S2 z=T{ydJ?;HGOpqntipQ}-)VGQ4qd*03jD+0AbIIG>zF#`#CYH8r@y|Bp7%IuEIr}&dz-Bfqk@^7 z^9mJ~*I&1N@>aS1Z~pv_B-6=1EP|eqZjF~aKQ|XI zFxs&5(mMOi^(K|olNb1IaSYuOqrt`0A-lk6!-S9t6M`5T;%y2A_E&u>43JbPd*I%0 z-zH!GR#IOx~z|hXHA`;G2yDnBu&vGu8KGN4Cd7=;AG`vlv^$w zU$c+5zRsFw`ksbW0h+h^LLNu&w`??ZeX3EwQSqr!&893~qKNC3@f8t=Ef*5GvL7la zEY;Y+eMsvw1H%HPkg10rZg{-5>HToQ!*$ z7RquRWY4qpqT|-_MORXO-j0}6S zIUme)zjpVZz=m_o`#vq$S-=0*Z`sKQR-S&Jvi5fG6ZI`RHGIs>ht+nzdc|cWm3zqP z;A$)TX)?#YG`9QxRxke}`!)CX$KJ2ceg4?TW;$*8s=>GAy~*D5m8u!Ptd-^eKm2Cu z?3m7};h7q<++cmHjHpJ_YGPWR^vlre%-I=r=5v^(vgTct+hf4iU##oJbXKkL<4V3- z-iFM-yG&T>U!C2u@R36a^QzbSk6oT`iF-%_IsYoGuUXbZIj-G(9RpF#gB!h z`x`HD`6cTtH}%Y!_kio@rKtS3_m}>)+s-YwUVh_8iL~dcdAswbM3-5g@vGSRqMtv=f`B{ylS4s*qv?5{Qju~J5BJ!Q7@ zO>Hr#EloW6*E49oN_1+k{%l{)Wi|On+Gl-OGA%{f?n+x>vD1N&X7Q;y1))mwWe#rM zlBCgo>{tHOt!f6@d!&Wq%dfQV`k-UA>@f?&tiucL28zFWbvEv*Y$=n-3hw7-ESjrs zaJJ_QGbmVAJHCD}t?+%nXJ+UD`6tZNXIj*kO!JNN3uO>dVA$3c`X~F#BF)wJqqj|T zTig_8CAQLTjpO%>kRzgBuf7Rgu+zXJ`SIObnj&nb;UeP6-qXbW)z|G_Q7Y?rF{G>} zPrU8_>HGq%Q`{vpYo6N1h37BTk?Wtxh!|_NZy-e#gew9`nCC`IdTDR z-+}^|oHR5dbk!C_nX)mmE@io8C?LQU;3VE{dhnT+r@pt{cJJ_2^#@wpHeAapcU8?< z6?NhInooPqod1!0&`K!RwrlPFJFJnjTJDCjL|!Ut_mr}dR9xeEA>w_f zErZ8og>MXR#N>=y3{85EovhY6Bl7<3dp3qEIqR4iCV$#9dDFg%^9#ECud^4tIKA{q zl0VDxUEVL-Ct75!c3lUG@1(qAPk4K-zrW|eaNq@Nm}{pkgO>lyJ&hmTe*d3%msw)Y zmz}Y@9`&sGZqxATZ7m;@kM2E7hI-4c>lFrtx{aOLoD2t)eS@D&RAX{*EqrR`6XUIO zs^a6L*L-h(cUp7o*t&er%_@4ecU4EKVLO@Sw_(}CYgP{YUdO7+_7BnZg!^6 z%SVQH_CA%{CF4*M$2sZdYT2~rsbb2^ZI?uOB@4VXbRBGCX zUK^nTk>#5AjjyjPFEY<+U^Da!U$o=ny&sR3E6LuF%{zABfWgd_ch)(+T&Nck9v-kQ zE%Zv4W{<*|ZFWCnxlVsS$yUR;c;eHYl`A=WrFnwcn-+wfbLt3=`}AAm+Cs_mQi6sL z)&*=n*&MRzN=mQ&XG@1^5C1z}Pr9yIyxWUy-#I=PMy5Nlq3b{Aq&_T`w2!^t^Ln+{ zhhv}G6FVLi@BT9LvEoMA_Wjov#qVzwchq$jU;ODke@T*m#r8I1rR5vc_ejgFm*2Lz zHr?YyU}NL!!`|=WH_e|lYyKpG?KN}XT06%`%O8@+{?z37@2juWjyZB~4m>|xy)~b2 z8e369!i+bZ@0aDf_$P&jZq9r!J#n)4Zw8Q%y0ZF4^F8LZasmY+v;8KSpNQZy?f5un z=aCutHx#B`d_D1TLt?g%;nf_X$3?YRk%=UD^+oW*rim+upsyaB|mYcI|Bo^d_&j`F^-#wWn)8`Ca7Qubc79(lz(&HHBlD zIvW(%M{HMf3wtbm%50XJ>rJP`5bm>ocoixbN?%3=Ju{Va_lw_rN?&SGz?C+&%cqu{ zQ$A*OnpyGm)4LwchnYi49=zQmp1*Z}%V95WtwZ_@3~kExM-?~9=6-Tqw@B|Gv!`!^ zs-yCGGqE+w%ZfyKoOV_4FbBV!zwz1n)0sA5cIjH%UoSmht9Zz_=JV`BN9?amy~{N9 z;1+=yVQRkm^G-*v`E>czk~ER#bc1`FZas`BvUqJ3T;qM#YTfiNU)?ft}$WZ z>wIgmCWGO{lbP;}3|sHH$%I91G2OC6Gs{GY!B%J4)RRxQ9?qF7d1%$2X|qayb=>Ay zFhlW=qhNH_HN~9@PhzE(Pxaiv(!Y*pv2&7j*52L~U(Fs(xG^tqUS(tVj*nX&i`u-c zIC^CB+9k4SZVAenCw>=GN(7Y)f6u z&m?Ynv8U&)L4VfX-b^>H3tz9Sh*_c1@_DlS2k*p-e8Ed!yp}yVlfUQP*(oM%O%u6} zE;9M)Q#~VR7Gsb4`Pag0Hl1O3lal_3>shz^PtT%7KIa7&P6~))^N_x=s&mbWzHrqF z%kI{qD2|k%d22s99jsV&=IzeZ4HY8MU1d7jB5S_RR&-3ZkT7HjS#r|awLI$Igcml; zrh2Z~_5a?{Wj4!}RB%sRaG?0J&y>vGsk?4e@Vx8X)bsnUaO$p@eH|0SuSGDup84A4 ze9ZDb#t7CEA#BU1o-~)6qI<@bxoZx2k^j)Ipn7uTq;l+kaNt4WXS+766 zNCY79C<~i);q6B9y@=Br}std z!i&vo^5$!@%n-WSAf?@DqjKV#d$$)`njxgN@xNAkpj=K literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_necromancy_legs.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_necromancy_legs.png new file mode 100644 index 0000000000000000000000000000000000000000..ebb496be24a7fbdd3bafbc09d2f168fd1ec9406b GIT binary patch literal 1926 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfr0gCRY*ihP-3}4K~a8M zW=^U?No7H*LTW{38UsVct+(Nko8GAL{7n~)Y-+u5plC+ORN0iDmKXNb-k*DKO2||7 zvaP+29EE)#Ulamupl;OlE2 zZBe+vs5(Eh>-GoXEpP9LZcpxJUf{psW?{d}RHF-gS|%$4FIc^IWLBHDXVb&EpHI~M znxlK&=7%F=URTb7bhWY#h6kh;TifR@+?;3onzv|;4dagK z>s@5KEFW=j-5yziw47((go6}X9vute+xOhhKPrB`uTHb0rGd5CjdlM5F1E(icJrU- zvE1pk>+sB+dt3~H*Tf{8dD!$+#e#O}q$@M^@zqJ`oR2ADXI7b{zLded$792r%JsdL zZtiB@btTGM8#oeEnN2wqCWLk!s9$4Ivx3vxQ)yAsqoAdl*@1zfm**~?wNX?!*tmH0 zwK;ot?AW!l`fFHm>Jo#MQM#e)w{B~5l@2jKlQ$t_?elYcOJ3euTfKfS?~d~t&TV|s zcCRvw{pWG~UwQe`m&o+!Ef2g_>qPF#`MGK}YmKgjmq$iK#gz>IYk6V!H@Ur^@!KxD zWb-yjZTE9=k0*|ipd-%oc$;K{^YgPepN4qdJCl2E-7GCRSmA}$wmipd3d&m8rU1ILG;zb`6Gu$5@`|`*k zsrkUCX?x!qzubQR<$SFl@fYjYWu&uotLB|}U@H|9$Fa`do44)vPK9|cJ9~BK?>-P; z>eQsN)@!wZ&6k>WG0WeDO^hwsQ=7fFbxvAk*{VBTJazxBUeOO_J2&y>_u{KvwhtO? zVsBNPz1wAU&S0(b6;~N`%|}XUb-7>L)@*M(nH8gc`;pb8H2u_Ty9z#RTeeR$L(@M#Ev0L12RqEVbED&Rj&9h-_hZ{6y#s%JZ`*u1 zB$6k^Y?pEs%)h8a_PB7189LW`mV{J%yLPkg*!4@* z>BT?1_kX#1+0N>gyLt2ErTlSjdhM!Lx(?Udm0eoTDtXRghtOjmk?dODr7stsxATtT z-YUFDfU#k-vGyF{d7WYc>P{S242<+viMHHIUbklFtjJ|uxlB){6|eFsO_k}|8Kqus zal0cf@FLS42}YKT$A>r;YwWSHa;`tX?SFIM!+BO|N(XP=?6f}LWgJpIN1~-biEo2f zyJ7b6^b+Gk$;OfI>n7aP@>%vI!7ACXIWWBR^wKR|TNNT7ttec<8+n!4tS@mx;p@s9 z94nqVO}rP}{(6e&qSJ4+G)x~<&pB9hys%f+;oqN+FFyYY2~2;``DBiaWB010Jx)x0 za*>_>76%NTv`luAnp5|@!F~Uh&Z@F-o)(`8EMe>!hyG6t-NSW8p@qBXWT0i91*3tG z*tYgPOuiod)w^#mvMjr3ykRSs*7H4LUVC~k81c$}5S$^^mf>7_rBr?SHCD?r196wqE;UE;8qH$wwi_eg*~xwj^(N7lxG# zdl~+xd^i%uz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||W@Y1LvbM_NzRJMB=;Z0* z7?N@C?ex8QhYUno`xV!91h{-`3Xo{fRrct4yZA#v?Ub_jw-`A~8K(06;Z#&|)tK8M z#?Kj27clIl@D{wTy(4w3TWd_HtANMZ$c&E1OX+!7jH4%3l2V+Vc}{V5{Hx+gpw2H*C)9GI&|#9FlnH zWA1i#i&w4BuQ7bw%|4^#HP?ix>=DrnrN`4h@4dzxa`zY01okO+nXk;BYZ0aV$eV$o zT<&0nuvP5^siVuC?tE(4Wmc!i^lg6s^39wHdpg-wGv~hBIr~dVhEUko>__62>m9=0 p@F{Lvo%~38S?NwwJMB6Kx0BO~-KOP6GB7YOc)I$ztaD0e0sy@zg6{wT literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_sorcery.png b/src/main/resources/assets/ebwizardry/textures/armour/legendary_wizard_armour_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..1d9a9f7cd929ab35ab1bd03ef558745546a5e4e8 GIT binary patch literal 13352 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour.png index 4f391e29e8ff65faf776bfa2697522e05da67981..7a5d974e1613d224219f5b35c8169326dba2a769 100644 GIT binary patch literal 11798 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEe@iDHFP{4;=Ecv0ubbk^%l&@k{`1Zwzt7t5=a)=AbE5m6wdeleco^0=pCQ8?71ANm-h3BeEpex{eS=eRK{oIx31e7UU|E#)RI-<^n~YM z%-=4`StM9$PWb98mEpK0aPkepCypnB|cH#$I z?pSYr~^x|E8 zW?c)VUr&tJDK-{_aZLPia-o2;?k@?S9>b$D-fK3h&Ufn4Tso&EQ1`b?(HYI>F-2$B z{t)ugS@|T$OLy(ASB)DYg3m6S7L}cSXG`JBW6P!AXRO`*uKLBs<@2gvZr$$qqsQQp zhjPEstBlLO_MZP|rkQO%V|9B|cR*C)(Wzl^saLO>ZQS;k&-&e#&w9JxefxIn@zwWn zo9%7BpO4$zfBnhEf_u~V?>Tnba=%_8t9qc_;bgrCn|V(enQom-58tS0QR!#5dzG^0 zqQlu{rz|g@O0F=_dHrZx{{7m@ck+MJl76iJ^X%U2 zww32@{w-rwz9#$JjbBo`Z(e=tS2_7*=KF@qUoY1B>+Jin&Gq=F>TQ=l{_DIRrL()Y z?A@+y@~?kw-1q;@>Yv}u|K%=j74_ATQvN2hto%^cFB_|Ev(~MD@`|S=>z(DJz&&l^ z*}XekZybt?U<qaY|*S5b6bDwP68mrsZ$6fwq^?mPGwi_N^xBB<%>Yv-v z^VaX4vUl0t9f@B9%2!pZ?@!j=dR;KqFwncl`kUGJ8M`gqze?}BJ=62@hV^Ru17|;) zxApze|Cevs=KkAw_eD#}Tf5YpDVyGhEELJ_~x+K{grq21+Bx~Y>f>|0vFkQ)CvMmHvO7C- zSJQJQKk@jDS^xhiJg#(g=w}vs_)+!7rswCbuJ6cys62W04@(Z7>l{gCj9$|uB2D%k zfAwZjl2DKLf&MM4I$5T-vxa_~_RVK+;-fj!d%s^h!Ek4rr&6w=rOdv_;B|AKL{#}d zbF!OxC-RO`?;obWJimjWbB;*T3HNP&HDJ|IF zpgVVOh5C#+OVSUl+5GllnHpF4o2@HqKFfCY-Q8sIKqct9iT|&F^^b0xD$odjVi#{& zyzzVYjO4vy`co$-X3o9xv&-tUXjy4gLrIRb=jNpEC%ClMnEc!oqjGYY(}H;i3hpe^ zJ}YuzgMF}ibaMQZO|eoP*6b7Ztgz+GxtU|w|1h0%n-y1s{I{KZHocDtl74e@&CKhZ z#i3QI3F0w4O4iKZl;2Jk+{9wQ>-H?`%o*VHL*ucR$%zVUS%SC0RsKBp;X&Mfi`>If*i z#;LdAyl_>Vp?iUdj$OEZ${!9E!Rw4)w>hvKXVR3;x%k{_tGvqV54Ne7nQm|YFlWcf z-%$pIJJ%gQQuScARMS^jQ_Zwxo!+8rm7sP!xd~a

    6O=(jz}?l@uoHdUD$HHabmu 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 L`njxgN@xNAS>?eV delta 2532 zcmbOh(< zOBZp8d}U{8ap^F~n#kqi(GWFdii9R>2+JX+Ct(X4-YzMOniOIY^QYAAcUARo!#_9r z&%Aqk@9ocX^&gies%Y=Fet+id@2_Wm3m%eiUixw0+xcrfK2%)KUUKQr_VaxUXSQGH z@SP?ixU%KRpV?j>J3`$K`~A8){olhX`5VRNk2c-=!X!{IyZ=9T!cwz+Wos*{6Av7i zx4U-VtL^O!d8`|_rIu`dt`L2e`A_H6&)Db4jIp{;?T`j z(hxD#P`x`-n6+5nSzMuW($jjSWdS*}mK8O=<25?q5-_nr(BZPFfj~fDi$-U~ugkv$ zC#Q;tur87~dgqXiS?Z-7H9wgc9vr#3-{E@6id}q6Y@SmbBo@5lQLr+(>ku<-p%k0f zsxA&wRR>naRf!32P6Y|aG`qBCWoTrwh45N@aggVGf48&3#ldIV#}AjCfBclM|0NJA znsaK2VaYSUnt$x+7jNxj{MgZOxVrq&1?JiS(;3wgQVu@XH%gk_b!=GndO_2L6fp({ zpO!=e7bTJTZ}u~13v233>3Y$zRcUjb@)8fO^tf74h7JD@##TH(#k!|7S1fSmB2%HG zIdy#dC2HB1PU3P@=wo1UWMRnI^>bgFaJ`3d1jEbMUCx(H100?Hv)}8#dwbV{>0*Yq z_We8ewDHd5b7A4t|M#)f=0>?b!-MkV=N~S#mn9^69)6U>xU!|CZ<|@iM6sTj9ZeU_ z@3&=TOmN|3OTJJdo2}vMd3~WY+mxn`Z7Ib&8ou19oz2J~o0~gh-h6iBt_vozLQ@ZR zv~90n{*U{x0Ruz&e><*;vkq+gv5wJIw^7hxk&(vI3%yEq72)b-xxR-lnE0GO&&=@b zlT_Tl=c>=$pU&vpd$-)o^_s_?uMN!drO)5z$CMrC%=g>lx9SRi%=`YdbBS8v4(Ud1 zD`Oa!m)Gog)R^|JR&uZNZ&0#c_uhW@CgEh}!!Km(Z$0mg?oeMBF*jhx#bi&x`_eZR z*8e@1@@DUB9@8q8r{X?yi*MWeUTtTz-X_b)ATlMp@QHi>;6TvF ztc?F(e-t^#9LWFQwxi)S-?kY&?&gccdN%Nvl;m^Dt~GR@9H)5WR{dMqThCXk-YcmT z-|$`Qse0$uc^{n~ynOR_^*yGyA--i!CoDWCc7<6og=;#@B>dK0S_Hl)`} zYZkM|HOHP$ImM^CerMse`dl|y-rK}f-nEPU)lT}FgZ2m%kAKwz592}>*kgRU%$RRUT)2^`kLvB z+Gp*5Yk$4+Nafj3ud;I;`}O-)$!yl;wP$#mc6`6{mGeGt-@SUxg3o=|B$gEyoXWAU z|HD+ulDwNkfHOVKgjFQn=gIe)&8!c3+d}l>R&X`#d@aoPxaym0_ebV)b8Mq-?6-+t z^YQMDG^6cHl3rZMt9flGdh*96B}aCj?eh2E-uZ2_cw4|8bH^3Y4e1`|cg@_)dQm88 zamt;wvBz0$K9@H7GAwpH7%;=3qvV^+7iPuy7?1iTzqOgT_~XQCE6XejFMWOY_pjH+ zX4~}V3^flPo0k8+{loIoU1GnpH z$}7Yl%v@a-PWyXZdjI?pT2=CA zw}Rn1p|2;DpY88TdgS3O*ImDxAS;ngD6+SDyP49#2qyp{O7j)t3Rc^?(3qXdw#u8 zUsG_)Ye$U|23yYU1gsMaheC;T=Ua* zE}Q4l1Dhf*1TS}tKf!e3m+?A{zJ@pNOl(uRHlAUMx>e1@ADpSz^I!jXZAF@g(!+A{j@mR@3{xp1iRIj--JIA+rXdaUK=c|zSiug z|!-k1s0s1qH_6a|^YB&AR=BFinOJ=Y5>9x-7 z(5?eTG0TFUuXxFSFgQfuR0u^IEf?M--*F6+4EKl9}*N9o(? SYR(J{3=E#GelF{r5}E*!)7kC- diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_earth.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_earth.png index 46ec5132632457348b85b1a2a742676b8aeb1a2d..3baa618438723c2c7898ab525d6c86c7e173e16e 100644 GIT binary patch literal 11486 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 delta 2771 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 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_earth_legs.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_earth_legs.png index d6ef5a393d03b13ae8f01146b6fbd16e046965ad..e1e6fad04a95c31f7b94097b1c0962e256ddd0f5 100644 GIT binary patch delta 1504 zcmZ3bAzaZ{A&^Ri6}oTcSna{mW**f5+cXtUK(w_gP5fmao_J zVzyqN$1YW6yYBexbyf48ulg>qFaB3>o%D$pS{2ier+<#FTQI-=zWRx^ozJrCCzZaw z7=6+9!?F!;rhd=bKIdMSSKXJ(f9L+P&A+lg=lMTTORaf_5gw{>f=C=#H+?t#I>=D6NT51(~i6yi6P^ zS5JMAU&$pe6|+MvEl+37oyskjvL0WXwPo(&wtA73hc3CeEIoZ;QE24su2p5Sw%?mX zj_ob=jIDm3oN$rxD)VM`m18q1r$wrtH%oo>rdVgk`BmNF(VI%Xn(9Oww(K{ZoRW37 zZSvu%d#tL93%|Zoevlowh|Qgwvsdo%$y;Y%X=i_F-1&a9n|b!^ja5&c%r!0P-m`MS zT)&E9wqr%A^#*#g87)fg&58Be`t0nTXK!A41hyJSDBpV`k$dbwLg^`)FHhdh-TD60 zv>pFM@_$C3S?YUt|G}7BSMHvvefF07TF#uVAU;QHF7svKoGNAEhI~UCrRGAYx;b1z?4jbW^`&s==--F$33bjAnv`t<0>(tjR^_RcYxwgq~Tg>zI z?DNvL04BRVg0tN-LN9OMdcEd_53l3D-pcz|)E}`Op8jJ^(&LbVmJ=%`s>j&tyxweD zeZ{EdgT(_nuOYi7%O?#5fw%~@(X{qA;~@K31{Jfgcc&CI#?mgz*T3N|5r zxzkF|w%D~!l8r9Bp|CA-qLo|mk-EFu_dE0&taK)Xe8|uZNIzS1Go*j-FPksXug~1J za@M-)aF^x&5!tO9-#xQ4{CC2-R_?&OJhe5MKKI0Yx){@orrk9>a4_1tYjueH%K90M z{5k7W*IrF4mnmo4CLA|gW5dkGoV<-moW7Y4mu^zxJSQ&ik$$}TqyAn8-nbvmdK0$s z*OW9m@lTNzb*?wKcgdf9MgOHFsj|#_y!EMUG3%HXM;HgVq?~%OZMBnv(q{H9AurDb z#=n)!-2wK>tyay* zbLlZKFmM)lL>4nJa0`PlBg3pY5)2Fs Z>?NMQuI!Il*?3IE8*=89Y>f6}1OOrr$v*%9 delta 68 zcmdnZw~~2+vIPTMlDE4HgB*hp1Bdym+zkv244efXk;M!Q+`=Ht$S`Y;1Oo#Ddx@v7 WEBgaRW*$?f4GFnTo8PkfF#-Sqx(}oP diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_fire.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_fire.png index 5040c8666433f6991419092c28a3767d315723f1..47b1556dc1b63669a623222b03d82b1cb378f865 100644 GIT binary patch literal 12095 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 delta 2800 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 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_healing.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_healing.png index 866fd4861571d99ccf8f40db825d3d52116fd21b..5a1c4b510c2d9482eeea00ab6950ab2e0b665fcf 100644 GIT binary patch literal 12777 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

    X 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 delta 2765 zcmaEv{8n^=vH$~HlDE4HgB*hp1Bdym+zpd$)#d6RFfxf*NUANH{eXditIE^GF{I+w z+vw;VnQ+N}=iZ%pmtt<6t)6yG@gwUbtCjj*9+QQhGHE&q<|=P(baBu$X%t&g=`l}Z zkygkTMv)iJD-5)z&T7(fSTrg4s*vUawUFLTCsg%ZUYq54C95mFKDa&h_UU)$dfRUr zTN+y%@0MO)FTMQXbe;2aKA->i=YG9?x)0Cc2KnCp{@+G6e=nqW-2ZcNvZhWd*Olan zKb-`64bT0$EAhBsbHLquUw-TVy*t?N&axqs(taHeNiTYXB?))+<-s|AG#zCQD(IN#YzQ^*5iw#5`Y!kZ|_4)4V zqtenWI~CYtjgu1%1Q;GNIx}*)^6uQj#qi^0`M$3C@|6;8OagL04jyLz_+hXo9)cj5?uzp6ZKPLjeheigGSof@)I?g4IiySY8iiFB`amn1d+N)f>O+kuFL5T11z2o)2KkN>^ zD=>xWmXOe|xXk0`b%jEYPF?M2W3t$k&dvAkRokLNG0x$PNxS$&Z1xOaM!slkyEfU^(F;YN z8yFflzl;=JE$qv|8uI7i`ugK{@0K$#{F@_n$ky6i$$EWKo?iPgiS}h}Y%I>F3!fd5 zU~|9MzG(G>CYh4M4XZLEj(yh1k}`>PR}^<~uF2fN@cqEtY(@rOUfvlqW;QN-zHpV4 zMZFzQ^NNc9uPjPp*%{{4WD7XnE_m%Yfs+$HWgd{J!UtZyyg&{GBUQ5_9g3&+*MfpH}vC)_U)3Z%qzc&|E#Iq?X#)yZ!$wejAF0H4oUgU zJ6Xv;&VN~8%6`Die*XR*@79I8xaYr;bqK#7$8g}n%EfF9CpPf}iZC)XDcm@4B5m^o z6;8i>IcDAS=E()sUt}t3{qi-_GlNl#kzra&BpXA=A`V9Zh0{ixZmuys&vow8)i+Eb zhrN3v)^5I)%D6~jLyeAwe1(9|S3ZTS)&+OZmw$b`b)GoOLA5;!90JG9oMmq3#C0pB zMCv_W{J4~}X=1@|bZ{NHFU^6ZJ2Rnp|J_4d{6;zw_Gr@n4UdL0wnz;%D?)6XmnLHT^rIvhIk47Ycr zi$&~A+x?aO<>@O$|KBCQzv1)!MjfBksrn5pX+Ku9n!KB((!ERd*tA9dHJ@xvwyxR!Ol^~; zLb0U(-`urtXD0vlJ#77F(yLw1*4ShSPl(IE^^+s;)8q%OQ`5{Nch$Y_eV$_!FhOsb zpXAhScTQY+tu4lKVDtGk${#iQ&+KWcm{QLA;NtUh4Id8l^WW**D!nWBe0Af49@V+W z%jzSTw10XQ2OljwDMyYmLI?KDDD06C3?)>`)R2kQJ99q!rdS#EB*QJKTuwORahJ+i2GTTt9)lq-DY?46f4uB2bTeXLi!ulhP;$cJy=%C3tq`0S^!;(=e|-eclU zb$SLhH+U-M9xn^2f6uh0Ag(ER(dWO%t9iK&t+9EbsUZ9P@ye+ciK#QW7pT~5o%8VU zvZWVxcI|aAJ!IYZ!v0=%h<1d}t*B>mS6S@0%O(E!Ao<~t*X$2*j>V4BO4IdX4{gi6 z&A@OnMQAHSNcQ6p?ZDvjuxWX`Q$=c}R1Upyxm!N}=k5T5#~wyAbuQP}6>qN2p5wRt zw8JV9iMfV}d7pCcD@5ea`tfkD!^@0wZmJ9x=4XFLy6)9II8*dg&6nH#ao&-gEKIY_ zBAFz1$}G?b*!Ry@K<>eBe~0R?p|?LDob=(;zTanc7EF;^*C_0;Fkqj&!`XYif1ZhT z_uPzp9ku^NNncM`=F*o>(%0wj@~sc_-Vt#|FJ$F=^+_z3Zg4nHJNSJ*!~Z=z4rStd z0yZ!#T7J1^KWEZRR+Y(~=cj+1z53Yy_3EOV4o!$SbG4tb;mG4un=iLcq^#;^th3t} zF>`?!_k{fa^8(*UxShVKVrV4k{o(X(``i{ctBWRIT!YwLZ212DjGwvx_hEw+NjEiS zrFu_}H`Z6&=QQfi^}D@gu8*3nv4iQ)TE$iYPZftG!_VpySIoM<@37E1TedCRw@>Gc zU3ucCg4e^SgPYgQlui0JYw^}v-Kz_X|8G{!Uz)Z;?$CtZ4Teoj_p1w9C|FKi%iz^qsqI3NI)o(gCC9lt};=eQtL!8aV%L(P( zcYnl6ukK6S%^k3|YU|;=rr&|4e=AIHKYGL1u5&sfm|34;!9$aVPr)iDHdXW7C|}XP zLy`YL{{Ib81zK+%Z(S>tE9h9nG2?#h1O1bKO>(L~TQL;%>Hl;(QF%gl z`dyHHd%;6}oynZ~wkL;Pm-!s))3;)nTC-1R|LjQbNhy(xs-BZ#Dpzj1X<7DX*^lde zS?7N2shI2j{0i#|(FrTBhgZ0sn01cZNqO!Pxz{0==ejAqi=XwR$ntujechwrH&=c= zTH^P5O6HWm4;)2Y&oiyvx%1|umDB1Esyk0z@jAM?Gu}`CY2A6AqHq26_C_z*1s7>V zIdvw_&P{K)d9C=`oXPifl`j;oi#W>p>QGZcZsYk#j*XEH0xT(;Bdy!H zFvpDh9B-|@@6|;+U!P^FJIY&I81>cE+0#E5&W|ik~iDu%p)bfbP6!{nvz; zd$PC|ddb^YaK8E~*{kAd9$soT?>xil>csw9d$AP3PUN zbMTi%si}Q<(X21CUKdDmEwb2llV!ozJCAld=q~ul>bRWSLfb*TawpGh(<75aIhz>r z8Y^$Dm^%HcndqIhQ_G4OwOF$M`I!s2TQy!Q-j=?%DQ#o&k7NI@M=U)vsjBQi!M6{F zc?=txc7FYPE?q-E^3CL#Ry%qgUfCkQf40+KhTrn*c2v#gIv?7@z`(%Z>FVdQ&MBb@ E0DcB3q5uE@ diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_ice.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_ice.png index 3e25a69c53cb59df1927574deea7935e644c57c6..ffda7c9231df47516af0c786fa637b64e00b38cd 100644 GIT binary patch literal 12968 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEyT0;$>pl6J7=u^m8uRac zzxv(DaL)C=zw@u(JOA~|+roSQlQw$S?ECqBfAB#G?axU(dT(AlK6-!qJE2I&oQP%c)xRD4x7PNbN$c)+-+905OYdF(`%n7qnXUWQ zpQyk4^EiJO|Jz^x_UCV_o)E&X@@X#Sc0bKi~m z$L60>_UqaA;n{=pCHsChY?Yt?=hI#Ly4%-Zs(bq+wja7Kkk;`ns#kT3!C6hu`ai;4 z?;`cWYz#j}J$d?Jr&#{?+_L>Iwaeq?m9w2cYBT@Gary7d#sA0utBHG2DY9!G%bzWx zuerD!rYW9(nSZa<`OoKDCbMhb_Wu?$zixiq&1S~gGgH~$T(_7makKttn2Ejnz3J

    x*w%N^^@5=vG-UwgGmr4x_k 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 R4+8@OgQu&X%Q~loCIFo^hNS=i delta 2749 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 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_ice_legs.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_ice_legs.png index a62eef4e06307deb513531102ff39a1382064393..f18ace7519bec1972391ee14d52b149667bf6814 100644 GIT binary patch delta 1603 zcmZ3;Je7Zfay{#ds*s41pu}>8f};Gi%$!t(lFEWqh1817GzNx>TW`aoC%s+8`!`)g zvZ+;|=^=wt=uF49`KoU&-`)MYChD^K~qxphp;NkMmS*{%P-mM^b=aH`~Kh)eX_ zt#LcN^lka~Y($`^` zzsvr(&#zg2F1>#Ib@SUhYj?h{kKP@qr4xF2@s+O~7WoNt3{>Z*if(_TUU9v+{0^^{ zp2XdTXGiu5m7dzLEm(1}qu=kIZn3_IPv^P}pHKaHK`Q%QrEGxLohOlu{i=BmNsOj! zmiyB|j_-czGiUpo<4?;P3P6&9L%tJEZKspo3n=4#GOP9Sr@wX#- z(kJ-v6lSjeG=sGUE#av_WKLc9*2n7F}RAf`RbRcm>Ik=E0PYJ{I9~NKK#Ic z*1zXjUEKoiUlNh5`PFcm`{38LCFwijg^x@Qx%az^^~KUv_3O^D`goRzon;X}$~9^3 z?yD8rLb1nRuei2)y{q& z7ckFD{r%qDCv5ALi$9xAFOEOCoMU@zP0`gfv*inG7EeEN%xiViroD&jx|Dj(E&Q%5 z(YQ+g{z;YHbNMgmnsb!Qujg`hFP_!?E^1?9s`T32K8v{M%GpzT&up3g^=wpmQLK>q zw_DRMU3pb}z09!apn<#6!Nqc4&u+*vo0I?6iaB$2tV{PyLFPL5wKg4$LP8N74pp&Y z-3v43dx?b^Y%x>ua7cb*r(U%D!n*D9K3^uheP5-#hR65v!8Ht0JzE+l)h?MgeneSVJD>^tXevxHRvn_Yt09q!C< z{@|45H=o0qFK2@vgZuHNeJi=AG&uY?8>OM@z4(Z(Yg(8@ylyY!mIo%apH@kqun5sV zaP>hf4_Crg4px>s{&N4>6+fA#EaGzyueW~w#WrQJR{3sbrmJTzM!fscv@^X&BeFy7apS^%kDkr4({VDy|(s@@%>7-!rR5A6&F7k@)k}izr+_G`0d6`hO5u# za$9BA%j~$9bc0y#4Xk&yb>I8*^Tx^keJ>Xu`dI%lOwv)xs(!WMoRp+X z>Was2w7pjO5E(6+d0y+z8xF_lw*T!-OPcqpO;VD&WXEk~J1_ZMyyr(%^?&G85k@W*pj^6T^Lp}>}B|$^5IAr0|NtRfk$L90|U1(2s1Lwnj^u$ az`$PO>Fdh=n3avkLiEt}O(7ej-53G9&I*wL delta 43 zcmbQrzmR!?vH$~HlDE4HgB*hp1Bdym+zpe}+2pt$Ff#KPDIM{@-MiVJ&5aQN?$Zml diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_lightning.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_lightning.png index 29cf575539f9b1898ecaa4060287f158b4b479fd..f8c5ae62b1dc8bd05f3e2b38e378f8e7c81d6f52 100644 GIT binary patch literal 11578 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 delta 2755 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 Zf495$Z_+{59SjT%44$rjF6*2UngE#Z5a9p- delta 2793 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 diff --git a/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_sorcery.png b/src/main/resources/assets/ebwizardry/textures/armour/wizard_armour_sorcery.png index d5e31f09eb1f8bbc2018a837b5de9a0e3d056ed0..b8b1c69559d50a2ea1b0f660477237bab7bf358a 100644 GIT binary patch literal 11818 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hElQN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHXalRfE<#fBxn58+RFUB4|Lzcw_V@k&t!MuqUoUkz+3Aex)hTjytx~J9_h_8|Tl#;SzeWAL_=kTx z=GRx>uc>=bar*Q2{r1bg%H6N9|M$zOZhyk>_wQ%h-1|J`yUTladG#;5Ha$LC9aHK5 z?RNFFz1R2d789E0^=$9T{%Fhf78{DS>i13iG54qaC#(7Qr`~UkmXWA^ zboSi)#GI{s+4<6Mww%q|eeV8YzG)J7ie~PgD}8SM_pbBnb`{PM`f@vOdf|DKeGgVQ zUbo5LeSYhW;=5Jr%yS-|x?Hqm^PDrEdhP3G&%gI){-1v~7w>V!X3zhWseSFKNP~{^ zyvy@tTDjlUERjyrH_-H72Be|7|xJL?y{T~k?d{PDiZ8v$+yZc@Bi;c_YRlnT2-SJ0{ z!6Oglexp|zmwoL$|IbV_+kD3A_NMNDsKldF!{Sn}UNzge?JuA8yDgvfcE9`fa_jZg z`>W5^eZI4QZ(98NlgSTdrq@^YZZH04(JDH}hC zeM>s{*5A~4?xWrR@Zg3u-M8z0y_^30-%E4h!~dt=zjNOv{mHKX;`5A)?!Mk>|My$- z^)zeIqw?&U+^Lt3=Qs2=&(i+GE_Z+b-%pQ!M<-sJH|_e~B^+!^-@cxa;^UWFef`WP z-S%@wUuhX`+jlIltaNwqy)`X1{1MCg@BKP*BfI_DqU5Kxw_jS+?Yf(Eb6M{)?`>QE zMx5VX`X~NR?!U?d{oiLCnk8Z6cE+Mgea5o$hf91+VxQkjS8ym+UXyh!{KvX$Gom|m z-?aLcscvyQxAs}#{?^M?=j(jD9nAjx*&<=pcl+Y{I{mxV58}=%&FVN<{|{uS-ran^ z&XeJxnxBK$r(aTfUO8XlUW=RAFU4(P5lNXJU#7mb_;%yma#81VA{t!$OZlWOm4Dy0 zbkDOpnR#^)8{bLo_E+njdpW}L{XFOBlXBBPKYro2-c9Y}?Vcl#4xbfrmUg(HKBH*6 z`guQ&FR6?6P1^QallNM$e9*VKpROf+X}b|qpdxjN@} z)vLM<>PHs6+tO#aOVP*ZyGVcgF7@LZ58X20*_XP}IPAuqf~~vtH_5Tgs{V1$v(AC* z_3;N$JRrWuMWcPJN55FT6p_>Q-onMb<-o4r z%+jwH%T9j$+}3=f!N$L9{!FN1Of?s%IVbpMo6F^b%2{X6z6m`be=X10KF9p`3@b)+ z)?1H+efFM6mKOENZ3>9>unNzs)k0pOh5bUgs<=r5dId^i;mGozR;cu@BG^|$&y@9(msd@j{W6Tey5hx2u-@GBah{bBK!No0!l{WS+n4|oTtrk}f18!2oetK4L+ zB7MgDS;onLPT}?)TPIIy%Ho|`_QY(C48y+G#wGvs|CrYwueFXYIAt6+tx&msd+F;f2pc&zU=Jtj2KN~o^Iv4%E)*4b@i;PKcse={d35iuvA6CxbbR4 z;}nnCi*r7)e<^CO*SM=}RUWu$@8fqXbCLr*epQG}Ust5HP*~AW?x1!!W7=kc&1DO^ zc0c{p@?MbHWx>h^`;vBQUpPL?yv(>DX8sOQZ`mu%3@do2o+#nk!?f2UcVgyM;mCQP zrKc;uR!?}ucd*Y-AaUujm49>`qK@V4KF>czPR`)KMCtR>b}X2ZaC}9GV0BQ5`ld-X zoejTFrFc6j&sQnIG|@DPGoCrrtlFW&Y0uzuS$`4{JHDewEALF8h&RiCKF(j|qu&Xz$JXPkO3_}k#) zv;(31ev^8pY;v`F`f<8{Q_{2>rxYApqs};fIqzuMAY7WkG~Aln#XffUCnCVq8OH}Hugn+iWB_( z6*a8Z2dYLiaPO4f5XJ0rL8N9;!oAlYoitWSZ51nWlL`>h60Df+w(Fo{XHxzH*}p|5 zIy)02*DwfAJT2m`u%r5`dc@-5DLi>cntGJyoLJqud#-rXnKd4%p{+}rc(#_`c_tCX zYq`Lt=^AtGkM(XX&o*y)rnzV77AFnO2X_Rv*1LNcO8j&vvf!v{`|$B;+(xb6{9b{~ zr3a@^D|Xaok)HlBiFffN(Mjdctpcades1MwTIHrMCw`&z#GVQb?VkKw=fgRSUe%Vg zrx$-d8~(`Tp2c0Wnh)RZUtuYmBl_iF2j@PwcWi-6UlcrYzGS7&R_Cwb`TBs}?J3+M z;*wcp*DjCvvUf!#NP2B$f6nbXQ~&CjO!em*e`FjwnSOYgh(*A(^iU*A&=4Rk-c-_q(87_k)9Goexf*;!I)>?P)mr z!|PtpF6C7rGZK$}R^-_9pi971J@Ps8T2Xh^m8{9VU)G0&g+BkbbW_=aXGeCnJ1X>E zJKF6asNKo4tScv^lW#Z23C?phJ8!FPCUa-Y zGiE#I|6P{5nnHxPE|6Q;yRx@^=3)7s8&5lxeC8~$x$*Cgu+yWIZyU9P+)S!}7G>}p zTOl{`nOKow^COXT<}=K5U)B7Wta@b6ZAH1zLY6gm-YAqDekB+3HGRRKt;r>S)<>_s z6Qv~M*peT&0@&=n z-{S$k#?*m+;sZN!4NRRajTfIP$8czU+uSqoS&nN5?|#vXvG2 zI!jLbecfANq4+dZY;E_RW|jxC^r7J6I~adu=XJj5RRbZ4iJlqgfs->LtbgFpT| zbIwUbVdazZ7Ww2V4@S9<_fB-IT#;!Pp__j*`NcYh3KtK?X}cRH$S*t8e!sT2`gG(MxNpF7VH7ir4ho-SztUrKGbi*>*@ai;b({sp`h*cMjSnx!qkXl>FnY(lgVOh8!Db@h=pf{rrb*P^i?3 z!)$6Dd+KF4cVEA1@#hfZq4l@@Mcl+gZo5o6{qT4Duf%mLm)Pmd>A&@5`^8IFQg@zs zb*C;m+3BENzu(2o#H2}kihfKj*w7p&oWZoDB zZ;OJV;?J6DZ+4IUx(aVg;*ZEhzgw{5$_kD;`*1U(*l_Rb>(0$|EB^3sX<6(|1#Qu? zvai*)-$FzA-e#;8xh!Hl=gGN4QzehN-CTSv!E{UAyg%-o-wJZdQ}i857J2Uy-&5;X z*rc1(;l5X4g|f-Q^veR5W?XnL{c6STt*XmEO%1+aeZo-wszQ^(`qqljvNL8^o(6rL z@zt>V^O1Xx+MZdQ;H%;)Up@ay>in>R$T@e`uN6HQGgVqC=XFYxhmnp{`wX4H*o0LJ z_w;hBZ&F}feQl~#Vaw{0c_(yQ!>)QsH9smlTc35?tnq}yeqY&#J4EaIUU)TL{>w0F z5uc)bK>W)iVximhw$A;)P<8dti_5A1t_rV;-sRTl*tlaZ&y^Lwk19U?qbYFz-KCI| zZ6>RxAJxvfGcBUgYRzle70zY9Cm(6M{7-%T)sL^djP!crVhY0nAuGmUJxsNq*A^lg)(2x|l5`LGJHiEQ^nHYF@fIhyM=bAjBl zA3}HBKQ5@cd&HoQ>)@9o)w>O9jA|G|KW}T8EVw^(rme{{Q;F~YW}W$$XK-ezTD$O% z_EOPFN0j0W92E1>B)zxk)j>^Un|-Zj7S+W(*8(Qw9<2iU!)v^w<8mUze2csqafv2V+IS3UmO zyzkXNxoKBeZ~waY^NodVkgu|Ya>zZW&Rt1i_3PA`go?b6F)h5JwP1&5P=TCRa@?&c z{{1a;ZXNq6xc6$9jE?ZFJ&%`Kvqom^J7xU6_3E<*ucny&wcGdk$F}$vMG9F&ecX{g zZ!f2R+G5wF%IHABY=-&-v$)L{%dNZS_)b+XPFgr8+j^;b`;GHq+u!n?@4Z&8oI2C( z%!1mO4~lpA1lsjk#U{xvNu4^sN#((xH?LD9y`=0k9`xAnT~qo^?pz$hyZ288-k%n9 ztGW_%u&psb@5-*F-9ZztniStluF3t`vc_%qt|=UT3a`sn28A)NeZ{6=u!hqi)VOx_ z=jG?OKAzN6pd@@3D8wj;vTJV49(vGU0$)!X%O4o9b15ulxTzJ-#WZF=Ip3 zmJsLWDrV)J7r9L_(dQZ!BVw<( zJ>I!VN;*Mm&+_|u3AWZz$FH9C^0julJ&SYB4fe^he-^edR^DQ|Jhww|ZjtjZU%M9h z?FvmcR~{eq+P;|mi)(gV;Y61BpKpvxoN{kZj#CkTy;4>{b7KIbn(E%l9eJmJCuKHY zdFv#)@z!4fb1QYpe@s{V+8;J>E-6#7;S%V7t{mwy#Y4J(-LB<-Kd=YQ>79_LxO>5( zr?(9^gge=;e9wRF{_Pv@BHwQQb!h6Ty&KHWuVlLQPtkrOQ_OO0*EPbk*jK9^Oq?fY zV}DSKb-(}5CilpOpN(589&_<1@$A>=-m&Xzfd9dR&adXb@%WXN9e7CW+=*Atg@1Dd z5=8R<#=1>;_x*D$yZD~h0-x8H%icQrdV9aYk(R5AK8olqU~{hOJ}Gc8Wszm{_vBw! za}s-%{<|7fo4sXOp|R9H(SC8rGbVk0rO9u0#OqEgi~614Tyyi;&m~-&7oHVSiMg?L zE<>r`##OqXSA3lo@w-}K#^1?vB-1xy~q52>l@CxPAH6bEi+0_b*#@)9Vx?LqYQSg|FQL zEJH=*qEy2bmj1lHY>i+J!}nFUUM-k3#k4Kr635=;)ejXtIcJ2-X1?T6df*ywTk={b zZPRwoiPFoSH!RyZGi;tUBjav1qm{?Ed+twI#9Q2WBdI=wJ@;sS?z_ixu5Rhv?_(Kl z;~H(F?$!R|^p$xRYo%wuY%a{?m1juHaCj|y_0gAN1^X*G$)THP?Q+{)b(Hmi#NCJQ z*45|OzAbQfk{+90N zez0uUBj?)QA1O~XMch~Y$h*9J`$G9Y=T*MsU8=1+Q2on8eh+us)qfkFl^;E_&`j=M zSy%pa6Zs?4LvKeNNV2;uX1heUrIGLJyG0B~E3#isTl4cF)3f~WA3F}DUJdMsT5qvN zil>AxC+?Qy3Fqi_hYuJ7MwdY>C)rR^fzxN#rKiW}Iakw^;SK#cX+8TXJh{hg0Xmy)Bmy3p_ll z%XRzT4Wni!RrwgsZM+>}uDoiFyWcI(e)hnG;ZWC|q;AfA{FzVqnm87ytzMu~UzAns zVcP09eT6{DTeIDt)<*7OK6Y&V{;kvM-it}Ei+v^e*s|hX-pZ{--~VW`T;bGoP_mfQ zw8QWn%c{wecQhaHo(O)dz1}1AuGXdukuC48&-*I$tGjvXcKZ&q*~k4WB?@#hrT>bZ z$d`UO(`fEdP1mfXD;I)A&oaC@$=;is`J)>xBC*Z#H+!zFH z*4_Hfvrccl?4tgVdtL9=zD&u&7~Qt(cPRtA)R$9K~j@&fAnN;dMLXmC@a^XNs0}C1lIy zT5WB0T96>kp|oaUY-XI3t#YK3=l65}6OP@A-h0-qH!M>ic(?V^`ZA>|*}n@9u(m!Z z=93zLm2?LMGb}7B|Q)}jI zS+hN6rDSrx<)S!7k$+z~3tIj%8|qBeytwVQb@~L?&N=q6TeKg4Z|^Zb8ZTS#7TT6S ztINUV%Hb_rpD*X@@&0-4q|1}tQZH`>^=37D+8#S+)U)ko(Sy867Ye*$)wZs@C4KF!pzWS%nah*Qk`yzw|6Q4RpRFm( zy6N9(Ru@rM^Euz%9~BlbT-NpfPVXlHSuyvkes9mEZJnr|<^I<2igpP9o!L?*9=Bu} zzMr^x{-Vi^+2nTiuq)@xiN`}exlT}>w@{INCV$snk@=^5^B=FY-G4WC0n_A*uVkLp-9CH$ z$CJADn;8b7lhd-aSi~2bxdnc>@VIE1Sd#8f@jF^?_eDRv?`B}OY{jI9;TJy?PM1yj zcfR-E@{af>lW0Pgxq!W%WGK&tLdl15SoU5;B$sGI2x;dH)F04yr zV%Fr+i@7LaDyVvm|IqfW=N&FJofcdW5qVgHJ+nyi)@H@lJJWN&uh)&t*m~!Gs`0nm zdAe2mMem$CSiPd$f8%@mGpeCW_HiE3P76sD`2Q--_H;7)YTL)N-dM4o&iY)EdFAGJ z&e|iwSL(E$h3qcMX!{#Dx#pYl_NS`6%<&nvzuPlIc|+z(xy%p_);Rfes*m5-S96t2 zx5WtFN!;h!+q7bmPeE5|zgh4FF?K7}(|>1mG$%JcooD^a>)6@)4TXgtr*}2qT^+UJ zM!&9~v0nLktA9~7b$chNsc+l1>)AKMb0=e0$u+->XLT%#E0VqUedEf1E*C!;ujFR_ zEcG~gb6v@H0j1xj0U?vUrMIOVlgu{U5b{LL#QX45DG8h3QnCJvC%jlHzIFd;$z3;Y z1zA;BWjzl+!T9p}y`8$Be?JJ@yr@6xYYFd~)%^=*&T(F*vB%%4$~F0CD8Jg9N%uTA z=dF15)-L{2-opoyFBX4$^X{|Q30^LzN#betlNC;xp4xV7>9x$N`JQ6DUM;s=;w=?r zx=Uufx>(8?e3!?8Stdb2Wz*H7wcq6ToxeVNLE($@)_>>UU-9#=-~ZCZ`OE#8+ZS{v zZwv{@VCPalnksZExXMxI&ns3<)>HS}=NvF|G(K4V+Vwo=L5m+w`>%1Wnmp_4>v(nV zC0CqQi?Kv_rn*LqQ{7k&}+>|?~{^EMDa1c{g(J$j`Jibo1m|R!f`e!(e<@Ti< z(U^<-7ITIOR{XK9z3|_vHi1!EeDAYvX|-z$a@6Nf`m(xBI!d)q;Le6mD`LZX?m1se zU<`O6H?d`R`15mzZPWX{*la)ivVWe$@;2_Ev)wCK+%128|8Mg1``OF1R?V+YIb}6X zj72Bk?ipv!g?|%Dlg`hHOm>~A>i%U;*Mw&YI&DF+&HK_8U3&RY&a{u+>$}~7C(l-f zuHez1_|xvJkm7GCMb;eV_i5|TSlf7g?sH%Ls7(JKZ@Y21@#5u7D>6_1yW4-QFCr{* z_N;|L!ZMR0?B{LRcxm$YP3yOry5D)#_`&|#LGz=p_v=hI?pv7Hu_DY)QMSb<(%;iW z_`GR<30u-#o685j-{fYT#5GHF_jmVGo)`WpZa5!x_WIGHqu&(&|4?4GUgo;ov1ulb z_FGpjTkFa_@#EXB$MfBVySBVK&c18PZYR;L(sl3l&s6YSsmr0c=={v)#Q$@gEB0{; z*t*?#RVBa8i0kav`Ma-mUU^aB#L&J)MSmgeu0#vTid@rf6)GO{%mo+-$!>m zR!QBP1}%EE^j7pI+pEXs2x=|=So%(4 z-qY%fmld~qd3P@iiqtEHLvbinC8-?}65BS5~X0@)tEOjuG#atJ!*g*V+H-+l=FT%b(r+f3)xP^oOYt)7$Q! zZ*G*5zUA0o`SRh_=ow{p&FsrX(-v19^RR!g^0x4z2bY@9W$as>|NH44wKe&#--Nz= z=l}iXwxB~|yM10?SKj^8X4CCI(~r)&bVWyOO$I~c73UR?7-nmhI?VaMVoluEh3*C{ zOD&~1XYPKz{B7dd8iikvqTV(%9h2nGS+L=X#-8fa-j_0e{@WJkcSQQ-qQlN6=2|+d zy1IXFIA1H_;Q#&A&llEdA1~i%|8ZvJ->;RdM|RHpYx=)rW<%fa)kQYt5poN@9oM^J z(I5EwRm015}AK^%>9)2W=?`Xk1E(pR@% zws`yAKdh^9_L-N*J$3@>IT%xaz&<5l}IP~SE|*edPPN|HPyPtjk@3i7mo1oU- zFFKLeRy=KgcKyIsw|(!=<;m(=YbJZDakAxJ4>)thk@e)1_?dfNwv`;3FLuZ>-qgXKOWlLIknzc*4}OE%7PHhhm3&= zu54Lu{5A`AGVW$`Ty!YRn87#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|WtgKwjmbY3TU1nh5YV>q*45_&F zHYz$tCS3C0xi@Ftl^rYFbK`aC#(aiD`Jmt1@h6d~7J5tprj&8mCRdr3d`RlpT{JYa@ z(!QOEOHN%}uw-iaxu56X{JH;A|Nj5}&eTW^^Kb9($A=~KZ*n-b_Wy%B7PBfj_#dgw zOqF+9yXdd^6|F~slKgKx_y7G}Z@I2tUZP3JV3r&MWB<<|_6(~_AJ3e5=dmbrpS;AQ zGgAHR4E;_UK1->Hbw~1lX4H$>;UKq)^~}n}EDUFqc&_K`HhUbnw$-SqPQK{p)XTE_ z=e90oWZ$+m*>0_)Ij@Ez=gvKe>v`93i!^x$>Nn8@JGJnb{vCQDg{4~O$>SncgTD(Ubl2z{6<-v6*VzD7*f|Hs6$FC)%L zf1Bm6ap$xNONZUY7fP%FD|~`?9yngj)bOkqHH-My*SzF-;=pk8 zY3h#}N1bJ28}u%fT1jjF(3StW+#T_7#V8KkaWBKW`6nKT0XRTCTKl?(-gB$-G=U8mv?uu`a;drol{hUMj|BN~oZ0jkV zs5i&zvtiBK<9v1!nafvh|TwV7t&Rd~=JWmG0IG{8gM&`8${4z{K=#kKVm~J!4L!gMq@rv+_p{ zT~eyEt`h&bhs{yJjG^fPGs6qFhrc-4CZug(FxnB;nD=4=i{RnEfp4TExRvK0yR)}C zBIeRX;g>D(7e4OZA9u*O*_x3dzc>Ea=8d@?sU=G;N47+{mTcR8_<8=pqp!CcRynt( zy%MNZ66-B{$6wy{KbMQ)h%(2+>x|4DZj0~8hlOsnj5%)X!zV@Bd!Au!4o*PSLd+CnI@|Dj(rJ!amSLqoMuLbnLca}3wF5ZO+NYH*4FGLNv1Pm=dE1N#q;f( zN+_*nVNlsvr0*K2aN20nNfo1+Q?Ipha z|2lVw*72sztNt>W-`b?J_;&_d^7^w%V)|2VC99`jtPN?9nYPnwr~EW?|EbecZ#fCvlXnZ(=-$yceO+MDBWdy1N`|jEwxRY$k=KS(!AEbt=iS|) z%q~7Pq^Wj=np;Tomg#G(8+QJk%UcujaP@yf&x=f6P1@(3PNg;W-P`+NdmanJlj(V4 zT05lHHD6mhN$0|)ONah$EU`K}S6_X8opV`A>-Tl%tQY zmfs2#Vcop>&la&xmzSqdvf<;ewYSRCLhwm<((T*(Uu$6Nb$9$s~&NICo7 z-75kN();dZEmw67%vq}DHcdv|@#zX4?epD#O6*i?CiTeMck8Zyw^{UB(dX7>U9YXJ zU;McPi) z1A+XeZ~Tixsatv^V}nhG0(#<9r6I-`kS)rn;uj?%5flzwiGt z`5o`q_}u&XDl*5mbjO!1UCaHO4MR=#mk9s6*2{N#L9wXrgOg|7y|tHIsdQO1?mcm2EK zBVDUbJ$$tC`qDkqC#{V=obgtw?Y5EJkpiv#MxcDDtsfi1Iq52c!_@e-f!rK%&)&x+ zPnEZ?+val4Hr$M@f+3)o=fS5IF1z^551W{m?q5ECzZ1iQo!7VDm@-4%|22=)hntp{ zE?*8_RHHP}VJ%PLR)&P&^{XY6gg?K2nZLpJx{&MLIZdjGNxyh+N)?CZWpChoxARo; zwAC+;Y_we>B+=<|X!1Hf9-fGINhg;*yk8}C!6fI$Rh8}b2R`vI%#euObW?k-@amN_ zq$GuT-=)vi$l09w=84X{uK#P6=#-t_eCqawH|Pa)|6IMw>&&+1 z)m#eRb0t+P#GKn631;UkIbd;f@0!~?PQRE`=iu*uo;h^EEQte5@5fg^B-gXLAA-Ac|Dx%ho@z1lWkdb z?Ktz9ZOt)kCxYjsb-rA^eyT>e9*5dw&qLq%l_q-J{MQ&A7btSxt!I(Ol84JQyozvN~sPZ|?2)C!9=C$a^tk%LT#QGyAPGjFUDkdShbW5Gu+NzWDx!3;(^> z2rbMqzW?=&Im=gJhK4yml&{>*7pUav3u}EBsOJ|D7Ir7U@(52*N^a?AhI=n}uWh{^ z`)qGHNBiNeQxAVRyY9MG=$-2SmEOLL7c-_@dCjEr^5^IKeHRkC7FMwA5wqONG|e?= zyNB9jZHACw!Aqr~q24L2S1MPx{SDiyuw$j}Y5t^-65m-peM5H4E3%O4wQ|tV3VB_p z$B`#~GVN!`4zuZ+&aI~>$ozi0jy-af%Ot5=@r_)?#{+Ddib7^E9p2TQZu!PBveNKi zR!Y5U_=CM)KURr~^R@51GIM+Tsjj%jbFV|R=cX+FUCICc9q*LHvKa1%w!v0&j|JF7 zaW(v&FLft-sz^pj{nEYwRW*;rHKslnCbG`z;HYFfdNrZRN%v`i>C&Rbzbi8Xrlq?3 zEoao3=%FytYmu~-+QMZ&mWRGPvZDUl?)`#l5o>Ey z)igGoStmB>u$FkQo2Tq=Pg}i!^`|eaF%;>);c#LT&!I_^y^i{cz78|}eRf-O%T|T$ zH>-Ctgf5b~xJYy2ah8{M*J54PCoP|+;O0M->EYIQd2=?bJjZ*iIjd{a0#zZ-Bac`G qI%dx^Gv?QD-@NxlnQGQQd*v%TxV5gOEMZ_^VDNPHb6Mw<&;$SyRr@gj delta 2760 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 uH*e0tGv818tYs{YuD!+erZ!IOv%TY%JTnPXU3 zJ*4TDef7yxJ-=%L+@BuwTkUvQMI*Jor1Y2ijkjx?%`fk>y;Xnmxup6T2lpqE0l!X2 zO?@ezrf_lh+~>weZ|cw7{q)TIAA(7i^XK=rOB_9&G9&wblk=DbjNYx0x!wprH%{BLay zbILA_k2T`+vYgdzHO(lip#F}+(w;oN>BrA6dUss3kX6Uf`3uu5>2*Fbk zK?&P=dR3`^CTFu|tzE9Snaf-IjQ4kzBPLcm>)OQ|3TDr`webCp7kc?uWFr{s9j#ON zA`*gb%O!2DIjt)>hqW$DGN^jjW_@D@l|whgCMPm7K8?_^4vWh^&m+tHL*-0N_eE)r z4O@2^m~Id(Y!EJym#($pkI(&@ckCjQK-ip$1qa!fbdq&G9iQDG;}y0>F?;Ridu-CV zMUQ$mpR;`bOLFR-ipOiq@BMzT*x#{noC}4k z)GL;3dFgAm`R3W&I_~H@L2kcNCg+yjd_E!B&sALW#=oPY{;E?Vf}VDTtXg*K)vEOi zkIj-QTI*?i*6ex>x9+wrD|}b=U-{wk&en9^6)QvIKYx0q&fJq%+##>N&6wFRSK>&m zdPB>#`nfZ?a(do9u`(7lHEX@P;Mlgqns+)I7pz>9`}pWPw|Bbco1UrX{pyk_E&0!G z`Raw*&h$L}6;n;_X&5nljlE$SdZ}Q8sqkdJA6hbB_xk*Ox@CIhY~NP}8~uHEciQcU zFR3iS>QFZ6%$R2L-T^}^_eat(reXwxrQ&}}7Eat$YfqzxUg=2!3XJMKQih=4y2}jERMat{Tdg8fFJ{dv9rsuS9a$M>or+d zUhDd7vv5_xX-nm(p4D1W*&cBR^;c?zl&ZJ}^fNcie3Rs4&pEmwG$N0<|^TNDa(O0j|>-Z;mWc%^rDP<-X*`I_TT zHq5QwY019eq<6;;o>{-8ytl;Ldgr}m7yr6k3GLuId p)jYGYL$2CbTKRUAwEPKQmk;bLlb`S8dfUJN0-mmZF6*2UngA_Ml?wm> delta 693 zcmaFQ^^|pjvH$~HlDE4H!+(Y)49q3*H@;5xWRa_X#KFy{%2ea!puxbvROIR67-Dfc zbn@9el~5kH^I!Ltu3oi!vY*l1nH!{!Fddn9ch4yg8>{G6j|SY z@F-sU*_4ZQXX~&2ls*2p?cu+s2T>`uiw?VlrtW$xxP9^NKRwSJF3CRr$LQ&+aGOuj z__)up$GiQn*aSCUxbD8>T*+-g-L{|axC;B~of%HqEPQyRqK4NqVBdjVVwrq4XX7uv zR({kc5q*H$G<}ck#F&X{TO+bL4=#!n&nXp&>hQKa#=D}R^rQ9c`m?$pf6AQtaGtH! ztvk{x*){vnw@xSjhf<20HZe0r(Zy3 z72Cm!<&7p=I;_^1Dac0u7kpgLGmZ1PQEvTTrjFy+O>C4WFP`R69QoqB{|d3JuNjMJzB{?Rsl#!z>(vR~N3B*=Y!J2#og*D^d4jRW<0;GDeoR~TQrJ!UQgOY1 zm#&D$LdR8$O{N7z#b|e&ox{h)wq%-*m#}K|ugxt}O=s|xn>LB(7%r*o_Z421DrqG8 z_|&3^*Mn+7tHQY_?A8AKWD=+8(sai(K&Y>-xB{lSMt$xhCjTFzx~#o>~>9HU|?YIboFyt I=akR{08>Rv)&Kwi diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/arcane_workbench_side.png b/src/main/resources/assets/ebwizardry/textures/blocks/arcane_workbench_side.png index 15941b3c4acd82b3f3e63c8a3239f7033c43703d..9050fa299c21ad5a8ac059f8b97722689890ace6 100644 GIT binary patch delta 2171 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 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/arcane_workbench_top.png b/src/main/resources/assets/ebwizardry/textures/blocks/arcane_workbench_top.png index 4bb07810093f4c7177ed097daf93079c0de7b933..69e7e0b77c45c0c1bf3ec315ec1e7aee5bd4dd40 100644 GIT binary patch delta 2328 zcmbQlx=3h(ay{GBs*s41pu}>8f};Gi%$!t(lFEWqh1817GzNx>TWiCkH)*T${7Dy$ zWMbkxSX2>~${txai}6_h32_l`no&*O=X3o`S+H?6OP|qfBnMtnqxa`#5CT2{A5+1w7p!4 z{08a8M-6{{(ko^NI+(M(PrLrQFbnsBFV{CUcz+bNd0na+Bd8bFaPL6c!BAe+B8O^$ z;Ke@8ze?AKBr5HGCsO`=)#vLGUtUdGEv{*!FXiXxZ=7)CC)YKbw!699vA>sP@Ane4 zHg8&@tf9Q-N6}3GX8WCauE}REEam)okgIH`WP?Gnk$Jr$t5Zgf&(lNScby5YzjH%9 z$yQlSR?XUPYLHP8sbp`6V(Toa*?lC2wXl9f?!Ognq)f^$l;~aHH zI_2|X8JSfcNzG);+rzJ*zH6uXHI3L!es`qYG8qLQHHQZ@voJ-TY5Eb^*RfD1?nZ}) zz*G&-q7RMDEdnNIq^4fgUY!web%kf~m->l|j|i9^n~~(FS2@MNQ*ouI;nFF_W@iKD zZnSb%dj6fIGVuerOwT-bVi zUX@(O)`#r;l8G-mlzVG7Z;Px=?Y%eSw`um4$k{y~RhRQ$Ggwm z3IpTYdbM;jq0O_;_@2ut^57~==uMe)Im3vJZRh04j^^e3&+1Oj7W@~!XXpDF#*=sb zZ?-gEdHYQ5)3?moy7B5=`#EMsS{QDvTd<*b!lv#G?a_0;b6i~aTJvX8vjDee_p8hw zyY5x_o?XQxu}A9&uiq4|CC{H6Pz=UUw0dh%Ga@eelAj zm9BQH94^)rOkmo4J%`0k&wpy0%5o{yn0r$rXJx&beqqK*j)Q;MQrNG*o7Q&Gg740C zHO21E>F0Z_Hi=!4sJ*zf%*XA>^&&BL>wtR?&zatB-CY$IH)Fv{?`Y#Ui{Gl|eBV(2 z)O6ww{`rrdEm0SL$GWv%ZGnJ6&pa6U_}xyE~M^`lqBmNsm;sCIdI*wkBJ zjrg0hBNbomd7Cq#U}5vt%ru`9{~kBGq;%XWlWBVGcrDNMj_l^tTu}-2?0VO;aqrk( zS;Y2#mptLorJci+v~&7iZ&%hMGq*bA+^}6}7pI@#dyi@U^{@bY-k(F=Ki9^8b9qxWgY){WPKJtxBfCWot`WJgD(|DU-UPp&D$a8a z3)GpLytmuOGzRf!YQH+VFkybLeV1(g%IPj%?949WUH`wfom;pjLh;G7M~S~~U!AsA zJ?zTjZJeuZZJ4=FoH^K2e)Ykl*}H}9l#XZZE}pi#v|4&gTl*F7#g;K!lb0{>;eXHP ze)IT`BNvnRtM_*NPZcaUZ|+u^c*soYa$lJ%*P$){Li`?OFPQNwx8;t@zPt8|6YLH& zWPYy?5&gN>?#DQPrkJ${I_bT4dcnTAo<&QbEYX_+O2j%Z2`D4#$PA&H1j`w(s{8omBm{MJF1Yh#zL>yWd$ z{31LrOFrq@;yG%T5%pIp`@ZZ@X3y<)KD^(#J3M3I^Xv?_ROLr$YB{$nm$B-;zhD?> z)g>|Qa$c&|tW#TdzCQWjL~Z_Bt@~Fl^h{?rm7l>`&3&2GH)0;+uLc&M`}=&VKjp5F z*F8$cL917#P@+yxmj-O#Z^@^zEUB3y9Oo4hLoqdji%8H>tBg* zu4;OC#q6`Q6z^p=hpTsD97RRCtS%>yV>tAQcFw2?pXYUpnzueuw zSaK7T-)nt1C&$TPHf5UAx~3<6iL2CZ9ayDS_IJnR!!xe@l?oNs(VxNcr|I_2{Y|#~ zJ)UzvZj6c6eIO*G!e?`6zwaGJhTI1ieZ=0>s{Q*eWgNL|+4r>{|DKr>Gbb|T_w>VW zF8{Rmu&EdR-lYG^dCRP(&*^@G8E#5B$E-W$x{DnBf4`Y`d*5TTHPf?u?z~w3x?qZM zqnwgai^uW9Yrd%zoY9Rs+wk8b#P>(N!_^jRa|OW_VN?HkOgfPua#8VNk(KMx-N&A} zHSzZgTe~ HDWM4f7FJu{ delta 634 zcmZ1^G>LVBay4nJa0`PlBg3pY5)2Fs>?NMQ zuI!IExcOAMS*QKzVPIgA_jGX#u{gbS^66~hK#^nhp7}zO6E!Zkugsj>!Mc_Ig6rKY zy-gu21(~v9IdTJ=cC7f{punMb)K^QH6HUb(+|^o*sk0&zR?{hZTAnm$Yj6$W6K!BFo?@R?@1qXA;X?C66a1 z=ErLtl}<4%DhzMjSzjWx{ldaM3FTKp<}UOu6j-oiQQ5wqxA|WEmAf}}xnYmhk+^#8 ztZ%wUFZs<|%JqXOP9QD(Y2uZz28Q?pr(fJ%K4nPNz?2T#;qf_oQI=MbT9=ezBOQsAg(yI2R_!P+xN5%r0Nn zwXfSeH?2_g-gM)`<186f!L5dqbWZrLw8%a1^hf;3Y3yD~r!FMyVdI{`x=r}D+{627 z>x3Jmis~)ceu)YHukL*)k^DIN+7Fe|`x)P^e_kBuywl*jyWr^~XP<07{M;a{?qjW8 ze{s??+k4EiEYemx&2}AMm$x(5dY!Xf@$NGxZzndn&$6gl(|PB*jgs)Eg46XAPPX>{ zDcSYbUFqbZf6S9~&g^VdeXo_8-1}}`?HUz_DP5vUrx+eQaak~T)w0PmODE3`GA|2l v@R>b()w0Fe-FLj}A01q5RdQZvKjXy3#{VYuKk;B-U|{fc^>bP0l+XkK^ED;A diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_earth.png b/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..cf587dc108e15ce01f7b8b85a5be662795acb2ed GIT binary patch literal 2864 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_fire.png b/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..10940157553ba61bd0c00f8514d4ce40c7aadd67 GIT binary patch literal 704 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^JY`Rxtc$){4+# zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifad7hqiWqNU>tkSG^7V9a46!&JJ9&S$ zh@;4H`<=Ian*^^XO=#X>#^%)2u`F0XN95+I8$T9rjLFeyN=V(E@KC-WM|MM?#}R|M zix}4y{o4_vGUwtE!%oXJ~ICFeDWSUib; z&0N%Qd-J=EzhYV*&zbY!`s3;i{k50o3G*4usANA;-dyq6?y7jI3`5%jgU}YSB~yjc z;vU6uSzYuET@)_bx>D(7ztFSAM{LCp#7MTwJYf7AFu!vF03yeaIEj^`a? z#*;ZcJLHnYjM?I>S&vUU9isBcFC%r^0zKt3lU&woG91||@Y!$C_9=U3I`uI>C=c7m zrgGVk$KluBD=X91ZsT_Nq}H}DXEW!EZB4ZX-Ip%ym26^8JLtADOirnA3uf)5(2yIob z5t58H^Yxf_bcVms-_XeTlOZzOf=@W_3S?s6BPhRjk-&84GkcEgnc8t%@z?T0vp4jH z-oBZ8UB9?DPkw=;PuiCKn$<~a$E3eseBE{Hn;y@Nb6f3CG@HMA+{fBsXti^vIMb1% zd7Yk)JWVgo&)C9V^7mwKSn0Z)@c;eA>z`JuZApyx?~!?~Z+L;@+Mm~)q6`cS44$rj JF6*2UngClfFc1I$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_healing.png b/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..d20fb9f072d2e423a25505a5aa3b8c07e2d65c04 GIT binary patch literal 740 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^JY`Rxtc$){4+# zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifad7jRs0m)P+`z!VROspA7-Dfcce1a) zaG*%r{F##yrH;?)Ncw58WYK{Q8@N}LWiRTK&sn?L?3cKQ$xHsiwbNoFg<@w2lyzu+ zRL-yOaGepde6nOAv-(f@UjK`i^4!Wo_ zpFVTx)@ebGqX*`GXJpvl<-g~8OUveHm)&!Y+>AeVt8LoWJC@}W%sFEF9Z!2-Q4Zg% z&|Fj|l)l{K$1xd}2E7eM#w_QK2r$j^J;2J>_{^SxVJG*RKRgekizDneXE1ZlInU-8 zoBrRoZCyZ*ecMCE9RK%x3wCbr*_$M=&$vDG?4nqYgqfRHBwMk!D%}k)$?87O={orV zm%or?N=)Nxr@a{qjs{0O)48>iecpS|gnFX@_hTFPiv|2D&3Zq7Ax}@EmV!gH3**9U zO&Q~MnTAtAZ41@~N1od7YpsvVj+~HFJSUrimO7O@nphrOc3aiN@%7&RA}zPQ84LPe z%1E)@U2HY6(a!62YTKdODc81j-1GZ)*$KB9u1DW~DzmUtq`i$_Gxv|eCHZAr zcDa5@lgia-Onzn^Tm42{AYrzp-|?U;+-$Ep{8Bc|zm(ScB19@z#qsN7lSMC2zyE&l zl+Kk#sVic}Eo#9xT$?Xd&3tj!rvQKiS7{YDM3wV*%C4$J@CWbpy^H4?J90@Bgtqc$Ju3 w*Pqpu`LFzDyq4wL*2o)QFhO$Pjq~wcZ7gCnv$lIOFfcH9y85}Sb4q9e0573Mxc~qF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_ice.png b/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_ice.png new file mode 100644 index 0000000000000000000000000000000000000000..230ffdc26a80db4a4f51c5768765491e57003566 GIT binary patch literal 876 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^JY`Rxtc$){4+# zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifad7i7>g}&Oo6Eq!^wZPDF~s6@?!>$P z!R0c??DrS*-JR3Ob!d&QX>Q7F)53F%rW!LW!X!`XU8!d0`PYB*KeJM}_qN$bx4*b> zPiJX@W2cL|cNFc^Nncbr$y$>^uR=yAXJ6|s)`$9G;FU_9mi${|TI-{qLTB$@Jon|76hppNLbk}w z6K4JL_P&?imVC%~DSA6p^sLsT8@fhiJLN@wJpOmLnZxu%N>_<|Q}0}@$I5k1=S!Bk zRdamV$+3P(K~|~R_SHSS-#%YICBzW4!neai!sfr}L-o}@J>Nc8Xr8;0!N31rcN3F( z%>2intv=2z5sZvma_!sAb}f5{nE%$Dt7hHVwYMQ-qRJ=J3k;0E%A{Hjow=)iHud7C z`Rt1v@158*Pgi)3%%a~Kd#*hWx%KAACR4R_yau)PGiOh>Pk3KcxFRT9Dtu})N7USi zZGIn?KTPYD!ZP8BIw?6j$3=<6hspees z__O(R#e)71hq(7`kWYK}(rRXwWac%GCt5ynADg*sIAje1M40wnF1ZzIwoR%h_FZb- zM^(|Iet$irXYP&N#kYOZiK#mTB_3RSz1?G>lJCV7gD2l6+_`=9d6AiYRKdqTk`9N1 zay=9UW+Z4vtU6YnZnGv=jghrb-$=jy_h-cjA(6&sUoLpOS9qvumHf($2uZ^xV_MF~s6@>Ewgi zGN}^B>hFI)yDWS1T+>N%Jk#cuUJ~P9eWOV?Cunu=T1A%C>b$J2PNM#CqK_`_chqk> zW-Fo}EiiG0Y1ZruE+$Fg+oj9P(u9S#Pf9c1oV(f3_;Y1MPt}LLwjcKCpa1>1^5~g6 zrn#x|uF8xD_j?NpCH`5jR}<OAY_{_ias(O1uKINDsklZ>uv-4tAQm21 z4=*;6^yxbuU)$)W|ERLGZr$3A-jg_3*-g(zwVu2v$aVeHpJ!nQt@yZlIGVSao#f>$ zO8lZCAMJ-Cg``xoSgV zi-uFyJ1ucH|4k2AOv17vX6gvC-H+Svm+fv;@`cmpxavylKfLiute#gNPTt9teBSnO z(Oa|ITi?&DN}l7i@{DhKbL*#EIWM;btZAo~+)XZ1%#vSO;$fZn>DyBAndR0YbL=JT z|C`89Up1rTaqW*2hSTb9F4(#8)Y9q4PTVLHU*wVOa)^Pqb*EA9uES4$KCUtQY?_gw z=;&~uSwS&_z2?hZuIQ<$7PdT6JV_^Pk|xW)QO&pQQ%d=BC$pt*qLc8%AMee%m`h)X z2$UJ_`TcN>o>=z+MqV{L#>`7w7(TpYKQP5kreT3TuXVz^A2<4WKZ_p>wQG_&+pv^@ Pfq}u()z4*}Q$iB}+9h}a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_necromancy.png b/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..2db8bb8f5b633cda4e15062c7ca78aee2191c9b5 GIT binary patch literal 858 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^JY`Rxtc$){4+# zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifad7jh3kCM}OlM$VdhY4s7-DhScd~!R z>{6Ly_V@4qR(pGLvdPNKf2Nt2%u-(ps4_dww3@4NuS`hN!?yCvn}y=63Mpp$p4d# z5eJ$yI3Cyp$QwwAFl(H;9{;B=e%+ECTlan3&(Q7i?}$&Y0}G?Y>_dIa82dA)bXXV_ zvu?Bg{y{%yeO&d-1%*d?w?1EyzwKp9ZkKlEt=+X};xF&1{j7C+E93EA#`fjbOXkl# zxaIha?rRSmE7@2pFfbw7-IXCpS2j&i@@6F-!NMfJ{@r1;exF&o$GyWUl&W%D(@6ty=%n+3DXc znSUK;yuN<#p)6J3fY+DvcqA6~T>LER!gHKoPVn0;i5eTFH&=hH;9_7i(71p1UvI*W zZmuJzjD3zg?B+-k5q;R)e=Xx0TZO}R!v_UBjG%7NEPpNS@*$#2_p;s1r(3VDPwI7@6R@|M{g2?yFHCzU*K%o}Z?NKdWi08t zIrKGS+tC|FKZ|4x`=)Ap9@@ZqPhyYZ&62(x#m3EirB#hv8Cw<@sz~Y^l~=aasCItV z+5MH7Z?|lL+|7`AKa(bf8LLd!O<2VD)$RWxooWAG^1XCvl&||a?^SjF$CGKRr`g2Hv=fPqPK6SC|V;l=OJ}wXX!~7-A{$QlY RK2V-v@O1TaS?83{1OQ7BjSK() literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_sorcery.png b/src/main/resources/assets/ebwizardry/textures/blocks/crystal_block_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..e416e570ed3d6b5084f3eba1e0af1a6917feefa2 GIT binary patch literal 806 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^JY`Rxtc$){4+# zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifad7imYZQLts9<1V+U)7#7-DhSchcGX zDWw9(?Tz=hFOP2B#U{PT^!2)E1D7UF_q~$}3>udlXl(A~{KEg?!QE!{!>oRB784ez z=q_z^S=_1rknPHi43nmua`9VSD%um$cI%(F+b_xIZ+K27P4DyEnsmFOy4s8VzBLVs z4NOjgf(HW+{GZ~K3EAbzPl zF8%XvHqVV`cb2>oel~6YLzkxtZu07fFERS@H~jp@_4ixyvvj-UZ`;pX#@#*M`oUfC z!GSxURI7UV!fu|fd9C;N8{4AVMK;G=8$6r*4R?Q1ZN4U4v3iDg&F!xjUus>+esb^O zk1r}w^A9<6P>+cl4YH1zXe!h+={6nFbw6ELRo_kT#kHn>3 zsOq}ny<=JcL!ok;uF3fV@gt&-B;=>@Z@zNl!O8Q!7p8X?zvfUr?t4&Cb6=i?DBg3r89McP%-aa|=_WjFy?>B6=YK`iD&^AH1VBOZ)4U2;UW;+}>tX(qO z-!Vw+`nwCcYYlho=PUFmP|i85d*H)4E4`+d4BPEEH8M^;om@O;=iVb5Psy$DZIVAy z%JE8}VCzP&viI_O^L|aa8Gr8KCDl)B1U}3#-d;0x?XlQDZ#l)}?xa+_SJZ2o@MzHk zKI@>gdVBBkWYLxKO(C8KZiL=Hd+}6ufPQn@oH=#kuh<3rIXCjKD7feJ%qZD#N-;*J z*ZIkZ{^xr?A2#YzmZ+34xV5o!_CuA9enlYzw+CGwejN()i~=j0pHDmMrW>k|slmX& Oz~JfX=d#Wzp$PzH&28-f literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/obsidian_crust_0.png b/src/main/resources/assets/ebwizardry/textures/blocks/obsidian_crust_0.png new file mode 100644 index 0000000000000000000000000000000000000000..0e33184a67d4e7d89babc67b620d24a41d1f5462 GIT binary patch literal 884 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_1.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_1.png new file mode 100644 index 0000000000000000000000000000000000000000..707aa8e9e5cd651c0e948d5e5d01ab64938945f2 GIT binary patch literal 742 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||E7-DhScJl5% znNR@-|Ep`?&HH%f-KO1cN($~1CJH+-ZR+U!!9StZCFvhi=K-f8uS59`4HG7AXgPRq z?#G<-o2z&I4io%R;k{}}+^XZ6Kc77Q?(7sWXS%sGm#|#i+~D=)Gc?1+i+8EydF&S^nf zUm4e&Y-CsAoy0Y(rRw^}C+~}E8f*@%IaTvH@$ee06{lEU?O7N7O!%-Cp{vFZV zYrY>>wXa=u;)R29#h=+9-vl20l-J*FF#pDk@@N9Lw)w=c1c;1~^b!39<+_TGVR`9UcG^JSx@x6O|t4-!hvoPaY%XfXM ztO*h_XJhTRF+~K~urAdUd@Rawa8kgu&do6bj4Uo3H<{lSZ@Aa*I?K%XXvVJ|)uko} zl?(WH>0PdH3z6KUEcC_lLZ)fah360UzSiuwzxCQ_d zRccS36p{bU=I;azab{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||I21VsW&gQ-I zKKh)`KVR~FtHkYv6otR5&w$0Eq4}V^AlTl;R zhxd19t@5y`ct1&8KRrV8!}r^5cI=)k4PVpF|9}29hqZxyM{}R*o(fB5hsmm4DpyjS zLNvG!C+oawS9ny?`Fo)yQ*dg%ghA)Whd0<~wH%%hD42G7+A6OKx!LRWwble|vi>_^ z<`l2Z?AgT+7(JVpG^s7TS!VP1wNXuj&4DeaY<{hnni(1}mGesFWf_b45@yzKSFEZy zP*nQh_WkvbkDo6IaS`o(aB{uadHFD-_;&?@=hV%<#l~Ja;<@MQyA$8*?;P`wSDC55 z?TlEoSU2zb=hAZZH%?r)FE6YvKKJ0<7B8Ng7hhJMjZ9T|Ah_l5#DW6(ROzA%{C+Gl zX9~-8G#L&*$awebqjrPp(cpktLWa8>IHt91@`-uU#G#> zbu^c9$~9JBD4luDc+sf|vJ)4aZ@hN(gya0?@A=vDYW7Ubuj|YxbHBHi&*Zl9>)7*` z?bkoPIlXny+_f8)usFr4uF*MF?O?NDosfM^U(NU1p%%7zesW&(?AJWa+vgx~Xl~kd z#smgU&d`}B9?nn+do6o@-!7r^ZK{d_&)$b|G%>pdsVyz6OuMnqRzW?cpMAN(LD{&! zn^jg$=xX`lk$mo8$)p!m%T1QvEL$+SG>{we#O!Ucq!&Q^>RR>^}9Y zYzJTLuD-**(m>TZ=k~nKry}yKH?bdnkaK%pnswF(dGWUVfW1y#+zbp144$rjF6*2U FngA@yO2GgC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_2.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_2.png new file mode 100644 index 0000000000000000000000000000000000000000..685fb30739499f1f99a035d413c54d0e8f364a12 GIT binary patch literal 732 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||7-DhScJkS- zm{5V^^`Xn(xu5^ylQiQ^4X0qaU4y`cJ+0p1kF0lmkQH$}_`N`NM}cIEgUL*v^t5+h zuD{*)e2$j*c4OA9EA{_{{_)!P=gs8_0wT}vf6tZ@UNW_foh*Xt>T>PZIDDr5U6>$L{AdRA)dzR)@)@h9FE>oRD7{v-gMqWiVT#v%t;2FT zYZ}>Ac;A)JeE+}h)Ky8Jb_bEV%8MVqr8!?$Q)2q+z`U-V`SiUDS2Nv1U0It>`Ny07 z`Eb-D7&A=(OC^_1Ck_lHDGis5s%`(2}gRL`9_h z+-{eZeRK82eRgiJpH?Yq|LJZ#_bPqOogW_7ovzdIIV#xreEydf?zp)@GOL5lh_~e8S(ztN3QektokD_3mVDXtIBjd1v7e91B#voQ z93o0MvuA%3oS@PqJf$F{C1%dwl$y`(6TUV%&sEgADp_`Ujg*4w!ffH4R&%w23s+f- zr|a&oy}P(!mH^-N)r{U=_ob$%x4k{iTy)6PpHEFdK+Z&q=e6u3<5S0F=6vtev|g)u zxXkHl&!aOj>T@I4JKmSb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||AFt=hGVIWYa0nn2PqrU^<5-!v&IACZ&Tz%C%<@upc&h`CKLXoB zufGnvTikc{fmrTI<^S92qUS&D_P2L*3Yb%WFE_(yM_tv?4;v2qRQ^gi8Y0`E#+iRF z_r0-K9(ow^EcDNj?e%(#esxXae*eB)=GdVS8NrHgh5kDpT-7|f(dy|< zt_^R5_wU^?<+0{stvkFk^Z#Wm{;WEgBTUQQHvdW84PnI)ev|7D67Bg7MgP^+9{>GY z_BFrtyEeg(eerQ6pAM&2XU<-bnf6-Aab2U{u9?j-%q|;LR05Tnrc8wQXcFq{n$TT5qi216|B0%T8_x+$eZ})Tvy6AbqzhX+W9Irz zU1@Q3?&;Li>*K#JYM3R!Xa1Ve+v~nmxc6bc$AXrRXQ{Ibb8zrWiME}U`zZM|m{0H5 zktuVpO-VFgnB`WOwr=vdHP;us=W#!|)2?nY*ObrRDx%xkeWD~-9>^8XW9`+vnrNOj rZEoTI*(>CxJbH8N%!b+dALOrSWhNSQ>a;U3Ffe$!`njxgN@xNA&eumr literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_3.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_3.png new file mode 100644 index 0000000000000000000000000000000000000000..5a23e576091b394b6484992282475ea2b27bda42 GIT binary patch literal 727 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||E)GNLE-+SM`PfNSGyFTXCD!4v8dbX?VzTo1b;@YDDybU5P-(NHP za_#w%bM*FYT|@3an=>U>3%f8_*nG3OT7TP?;aLKk)z%N+%D5ZaBs?4=o;9qP5PYO2 zORD>^o&2B6%dgH|;Z?8Y^6}+E8>`c;MS7ye$9aRocy7p^YpMM5%IM+I$dsjT73EeZ z^Eu94C}GL!W#|-kY~!Z?79TF(KW`b8D%ldh|Ky#wR(4y|*NIKsG1qXFmYxDrTHlE+ zH_xtmcy@Kqici13_lYno9lEN-B(Q$IZsu-biyeon%8#5mY5CwCPx8};g$u$SSFbZH z?~O^0c)g|N^InN%)tRhETo&i#ArA>8_{;90xzJBN>WqRY+gWJ{f>yt>=tO}~1|w$&0j<#*pyE3Xg;c1XKpp|i-S$F0xnHt&jK z9)@c1?VbOk=DG?Ss+rp@4P-qf)4AYKvb~Uf&aIcn5_Lpp3jYkbyYa&xqvHP-PZfKn heh#qY6K(j<$Y2s_a`9l84FdxMgQu&X%Q~loCIE;~JkbCE literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_3_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_3_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..c4087bc965b93322548841ecdbf07a25910ff340 GIT binary patch literal 730 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||AM^EH>>`oM8WQT%A**LN;f+v8%=7O`z!l=Cg2 zU97_4Qo;(qlbum>L#7nw&W*@fj zWU$-4^TBd`cEP!K&Mo8EU>_1!Q`gvDT)tnqQ$W##KPTtlx5FOkhtkR){kEUi`lMw$ zvzOv_hv0|Lrz@WRE%#kBNK_&^;d9=jgq&cmS-^0YhIts3 z&M)WG-D$&kN%ZL5pWnXM?l`=Aw{HG)>%9M!{R~Y?T34Rgd|9r^+AyVMor=?guja*? zs+;R>2q>yNwAoZ7qov6?ZAzq}n0VV;e)lImt1Z@C`#ZB*ePx2BV)|W{Gd_}T%V%tQ z$sTfc#knJ;v)<(E&M0j&zWAe1I&{IjaHW+WcF21cHzzDQZ#z#+bM_^fUx!b)rrUgB mKHD5M_n*P0m+TDx*ef=q`i9=wQp&)b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||aDeUOgQqZDUD0X}I zy|3@yl$49M&&=^$J89SJ<*Q$5|9o?~KQ<VAD8sV^Hmg}5J{2)Gv`MUJx^R^- zaN#1LHDArX%FFX)hhygJ6YR@%cisJZq9t33hqcY~{+%_QQ;W)XFB5w4`;e!( z+N#By?(nQQ=3#c@+fRdeL36fsN_cra-O#HwVfj=Jtu@;_e>{6zwCCf*!kG)I)Mv*& r`?BI$*bP0l+XkK@)=JK literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_4_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_earth_4_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..000189caa6dcc9d9f04225c0d20e0025186ff990 GIT binary patch literal 739 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||68>Y zZ}E2KyM5ooHoi#ovRZ8wx@uLim)*}F&PP~}?%20;ao3@ri-XN>&y$$yzM3`IkYSa= zpW0&gVAgZ@ZJ++UIxB+v&(HI1A#)U%4&1#h`~UdquVM_v2F!CcZT3eoFHmG#rBG7p z5VB%*$4?)xn}zla_GY^8Ttds7-Htv#GGorJAT{GNy&-dw+*V96|I5O$LYYfb{8p5q z!}p_x?F;<0+8%K@#cCUBndg72`TIro|BFXF#>*{OMB{SV#Bx>E@msIb3N|bw6 z=AzV7tfGmZd`>Y63OKk#Y$;q9t!w?KV2_s8-w8jSZC@H+v%x9Upm>pml!zeXoSb9L zY7@E_@{7r;`_74e9HRI@wZZzg;peySwf{f-95wInMm4shJV^lzMP^%kGUZqcn2&E{ z3ctQR=3mvT`}XUe-0Z#{^Ka9K@8_qR_%g7UFPtG9T)6Ffry7@@0@HUZ!Np29Z{B&k zqo(Saza96d>u1FRA3SIek$F4oCi_Z@sa&VmJzK6H{^{!Zi`B(t&WXU6LU65e+rxzG-q3b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||v`$PZhkM2=)F%k4q7gl{~mzpo#sGIc{oZEYJS^ZJoVQ zS#I7u#sHSQ$y`o{%o=xuTx>hGWA=mzN6y~J<=ZE>zu+wsw@#v?+oc92%Wy$?m8P3V zef2`b3#)BDr0Q@8H$@&@<9YiATW)_FQ|k&XqivCE?z*hqy0zhjQJFBy+ccM$_YW?) zDi{e1=w38SF8#bE?uNEm7srGEZkA#{qvFN0Z#OtQbzJq8F^&{jlNXg>zFEy%%}r$4 zt{HFr?UjXCj>{a`bi1A{MV`BtgLQrJ-g&AETk?#Uc(TR&pKsT_$Dn!Rxl?KVuLz}; zt9Y;b_7(D)>r9k6cE~?j@!q}r6Isos>wQxG9?D|i)Z=mGY}C=S5gTT!HZ4Cr^MVIg z{?5L$1vh1mEpT2Fy2ke6)HN^8pZ&8jPU8FWGQi2>(8%W(&XJ) gESkS{?T>nKKh0ljXITX^FfcH9y85}Sb4q9e00V6bb^rhX literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_1.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_1.png new file mode 100644 index 0000000000000000000000000000000000000000..71eda33ef8c65e80b760eb428ec4363cb33a5f5e GIT binary patch literal 712 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||YmM&cyUZgJ|>?-VjWPd`^As6A^iy!i3EfP;mk@We%rnz@o-JMJG=GA_y zlAPleW1q10>mK=Uhr{o4cvp06-_3iohy646wcobA(%;jIy}mG{6yJMW))VwB%kJ^l zvy*I;3in0^i>MScl(jQ6Fp1sfWoqF#V8{@6Ux%^4-_I<4j+DWU$6hb>X98LTi7OrSvJCm8UBJktQlrwklBy?0=Tgb(MbjrVJ!uwKWm>c^|IBW`Y=1FH3@N}+Le8H3>U^Y8AHDQrU z>g}z}zs}#cy*T^oq&J+La_64!iCpg?G5xaS|99ULCfunsnf>|UW8KgV@2%fGWwYO= ztH#{9?c1K)Yfe7%cy#!f$xunXs-R0aqXGMo|JeygMmf^XX1&gnE zb;?;=hjyMnyGK{Ha%1FtQ3J2HhQ|Nwx7R-GzSwg0rGwG()yGzb^_8ypp}ySBf6eTJ SO8E>73=E#GelF{r5}E*B%QiXy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_1_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_1_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..5a373e2360787c4404fa788cfff68ece29a27e07 GIT binary patch literal 713 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||ieDS`?ViMBMv$L*?W7!*&ivT2WxL%+VL@C=b|GF4rb5q-|dS$6|;8Q zo_(>C(^b})e-~jrDbsMbj=!N{_FFbaCzb~i4D0i+Gwe`TpKa{VD>3IuTNi@_%R&dC zg%1vMhHg^-=6uliaqnIx_O=x=rzVzO_tUp%WH@|Q!|=lOQ+I?LKQwbSdIazCqQTEMYmR|UQ>nz7A3 zyVA%YaM7l>y9NIq&!6|{S)T8=7MA{S?R$6bPc+aI_x_h1ZQ${)W>?I|cYm2fFYwtu z->FzzS9WgS`@-gRVc(AP89NKbYMR{id^Y3AvxUg=d6^UV3B=V#A&pTj>5W*(c%cyZdi%{7O1|8tlsp_JjBXq@`Nelb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||{T{i}+1<@Tq)X-N^$>|)T=j%#EHGV=`c(8xb!e1J`Hn}-H>z>_00(~iC6zWdJZ zdC0~Mk{{Q5hkm{PWOjPIg-}3o*zRc>hrTAAd{(d^=;6bsO(~KM8mErm?Xz-`)7PuK zen%ji>HTfqlf4RD2iCo2C`j0wTX>+5CxE4){46iSD#y-6KF+L6lOqBP7&bNUeE4pL z^#6l<1WYeHZRwhC*7y9NoqECXf?59<90VL)SB7+G^(-~G+VC*rJ?CN0cW0cI?D)9S zdV@53*m~=Eb`>7ha)J+Q6og$Po1eaEGUo2G-m3A)?ei*i^O;sGe>@-br}=)qRwLe;6ltSw&5eTO45{@r{m z{P^)|<(m(los43R5f0T9UZJWW8Tap-YRiG&-}vli8$5F| zbiU)6cO;S{WRZ&bw!;&j{hs$xOiov<=J#pV{r~?muJw=9ynABLx=ho6J2P54!oEJS zQ|Mn-ysmyu;CcUzf4AH(w%z??_xyPqC96c1pJzVFHG83bVEyMm+W%jFYg@rsynM#T zl#Ndg=XLK6&R$TVxa!l7tdpzm24p{&;Jz-Y_1kgfM@;W{mMR>m+Rkdsr0~dvbBE>X zZ++bYh2~nJ+a5P~@rcaPQ(x3pt-ahZNoz@v$Fzx?gIRayKeOvSQo7qxTVcs0LBW6h swSG1$((mxeI!@Wh;jH=PX~@TVMqRP^HH#dUf>I-cr>mdKI;Vst0Fo6&0RR91 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_2_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_2_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..f32c33c322b256e9a4507297d828a81646f2831b GIT binary patch literal 743 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||y z8CL;Uf0wk-{mXXezL}_+%s46h4->!lJ&7=n6ZNOe53nh2^Ekmh!Sq{2*UWWwJ65eW zGH!C+u6}J{$Bx2xQ{T_4S>&&Et*x_bq1Cz5o}7gDwW;CObF!KJIKuU8I%Dw3S8W@M-(~LQW5ItJ&xK zN)#`gq4-Y4{E-feR^TM*+YdcH2fu%;YZJBh$G`78|9rh~y~VC_X^C?8u4Pvp3X{c@ zqOMM^Znl}Fx8qN$+Sf-ZxA}kDPT$NO_ve?7nREZ6FO>?BiN;^lU)tOKpH-iq-yvmC z-X-ZDmVNK-wjI`6*}B9RY4uOfUU!RkD;r;Bilp|T=bu&YS}bBZ9>k&ark&ATxkDf% zK%{)RZP^)T*FxsTe$9nK%&f~#cdmFS_teDAr!|D@q*0Mt=!V}Z?=E}Hn0Gn#`GcA+ ypQT>MESF5IoKs-_O{9F2Wc!qib{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||dqlV~E9R-^pkD zq(eno_7|Vqn_F#jMuo*pF-YtoYlIRL_XGj$iadcNPMu91NBr9=)VAH0+rIn#-sc-$ zC@zv)uw>PGuQI#EBktkT_uSf} zS}IZhX4{kkACZQCB}@tpv;X!nG#y}cWvJL%$=$F@({swwRDp;kKFSO$80Gw29z6V` z-tQLlIE33Xscg=nmscdR99=s(1Xc*Ha0ol>BAIp2IbzjDsrxu` zPU7-xeQOc0H&IDNFz=lEwUy51zvUPLQ!}QXEjVwl?{8E6g~h$2;jhW3@86aEJSReI2wOKjQ-xep@8tOVcfk!Fvpuk7!i8l+~^^s0Aj>MZjwMO&XJrM4vG zOkLyj#QPJ zu1i}34l^Ef{lKxMWwX98!!k4L^~U?_>yC@t*B_d{`>xLu4!;YTi*_mtPAMo!brW0K za`{l8=$m~X&gReGWGffY=*R2w@tMPfD-H>%oM-Po`s*N)IMpcr|F5R&@ADX+-jTZA zts4LL)12GCnOAvzJXR+2tde=gfkQ^RO&mL3S5KQ(FlVad^RS(^ax30lnGunZG}B0a zNe|z1V<9F%pS6w_s&g($J#-Y%F;NukIB?5I&@U|2zITPnV!_Yrt}-li-QdF+zHp1% z$1a-*SwDWK%bjxBbu(99O2BJ%2gm>G3&rG0wci~RRy%d2Wus}ES^S^)#^(X|w{DUy RVPIfj@O1TaS?83{1OQouFZ%!h literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_3_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_3_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..c5ecfe2110749c61ade8f8b38d09e8a983eb7b0f GIT binary patch literal 714 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||gM(B~>?R{mxf88tg%Vm4F z#4f>m_qV8Te@+H(Xlehk{Qjh~KmNR$b@rjd^J9lkYkP$-Y_iP%H81j1O=|k0Y(e91FOGUGu)Xx`E2A8KAvYg7b`NXQV{V_5~v?aP^0+Z?{WTaKYPJ!9(Eg5&k)`>Q@Z5NuRDm?!n~`|-ej`8uz% z<7XnC-u%ga{WSNxXaoP5QccGVu5r2+So7_vD_kz2z0{}0rT3Ut>6VNiPm2z^zB4#- zLu;<|D@B8EsZX9Q4~+l&=S0j*Jyjm%pOxK0joUAs6E%=Akg+~kb^r6T_C@dOE7M+I z7TmqUL^707BGJvGB5;GYFvH2qmX%jOKEM9{>)G}3H}2nlTRD-LCF$8ru|`i3)_p#m z=jJS0pjlvkDfZ!0`S@GUHXP?on|EMN24lw?PM&F+kMHLE6BIZe@vQHCU47d6{CtMz zSER0gX1)LK+m*a`-*#B5O3f~`c+5M2=h@1|o*p0ey^mbtBcK!f=!%wkyRB){s?MG1 zVmlvCzVq<#%a)T4Nm;xiBCJbIMVvZzru!V?30vvRWmR5wxg*-oq~zHx;RKUT*K;k> zOHI8(-qfvht1&5#SG)A+-nt#)&zp_rT8kEH2#Z&qduwt*C5xp!=!Tyb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||HXlrjSE@;g_u&ZoKa(c=ua2*3z)$;&mr&CLx}*9@B>`x7-hM2CgN%UdAx%mdRb&hV5c87OlW`?ZHi&@f^ zYdI->vZ1r?m#qmb@x9CT{L)oe(6)GyifD&Igkr-gA--96j-+N>9^BuN6)J# z6?k;U@Z4eve){(P`JK1lGaO{KX^J^?b4uexjpI=Qf|oA-{C9r32g|c#@vBwK-}61W zG9gqmjl+pk-9KoN;L;Xle$|D(JEY5Z%R1U@VG>C%SbVXi)!1|9oh^%xH*p9E&XCmd z>Rlk{$f$RI=4$qijgo!o=lS*HkDq-tZ%t>g?h3Vev2lf$*Uot2^VNZ4-nsQV@2+uN zF!9JfzL;lhZ~NU<&P|bZRN8U3Or<5uFHF%hY3Eyxrp`2_Ic`(W7C5P@_dE#Tjucji zV0k>JP_#?(sP?B1nuq15@6=|lytr1LQ)G1q$N%f=#O7@g4qMLbIptu>WXZjA)&J?w Y3JiZe=~b^O0|Nttr>mdKI;Vst02fFzn*aa+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_4_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_fire_4_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..3f98c9fb9c2bd3d91a806ec33b3881f846a3e20d GIT binary patch literal 715 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||dS~EA!q0DQkFR5$_CetPn&~OVcJt#m-pG4-XUDv=nt_Zbp8eS!cX|1l^v{y{^6yUC zc9x%Jb#*jiPuP2#QQ<+^R+k0=MhmtBx7({3?o6J1R&qHXkK4}0iVUk1L_Cy4YUTte zS0{yY=UK(dh^Wk|)xDEv?s4#M-Qi6#l2>kAcgkl|Yr7^N=E0?jpP1iO}iT@ zQ*P2YJ1~0j>6zVk<{yajU8cjIp20P%W%kG8=H^L^G0nY3H4TN=FYgRqTsYC{+Ea&l zzQ=gBZdl*iR$(^l)7N|>me9u8lkYe<*(5dWUfdw$n74GUQi4zM`QOV$x7*7vRa8(d z%DkXH!|MLue}~>}lRm)FJmG}v!BspxXDqKY&78=0@O%9}lgSwuf4u(Kxcj>G(<>A2 zYOYO`aCMxw#3kJ?Fd^OZg|J}n?z3zQH;X=CaW=8?H({MTb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||UvY&DLyH~4T zWqp75R(f+3!;c>?o1QM1v#;vh&!_s+nu}^aHAQJNJeqnwe&0pbr(a(O->bK9X56<< ze`c~a(~cdxEdN};U(YZ>`^lV-j~FWcKU~w;mglf{gA{YEdIv`wPlILJnVuM}8;=>j z3S24vK4HQfWro?Bi{ltPZWZ0Qr9vqp>?XWmMZG}bBnG#2hs|}}aY(Kf$(1btEEJhqjdAYlwQ^YLdoAtMl1nx>)_;9DQE8WiJhPI4`T^5Z z47Jx|zCW^fby$)8`u59u?A0zd5vuOatcR2gjx+fM=(Cizi}G`yzoD(}Z&AyMy=vv$gh?aLH9zeQKZ{-x(l3GqYyvn2)Jo)9(TpQvZD%P{rW!o@R^Z;5?+ z$Ma447W@0__dC{If4+Me*UCqKlLZgFy*n-Ze3jn1_l4{39-8m_Brj{te@6e+@-I{h TG*cKD7#KWV{an^LB{Ts519&2A literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_1.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_1.png new file mode 100644 index 0000000000000000000000000000000000000000..40d6daaafc2fd34847357fa9bd6c8539a4cd4e26 GIT binary patch literal 838 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||&zpP9nN3kuB( zoE9zUJWwPes3NX6N1%GoX8C)u>+Q>It&QI|C!N`~`{>2J&*xP4?b!co+4ply8@^gB zj0@E{7r*r8yWsU&>(1D97xOVlYRvny+k1tmw|BSAtvhavHodofJ_)f*C}F#7c`utW zK}I5(V+q59i_gk-hO~!%TvLYVe*{^dyhx3|NGOx<*>S8@@1w>AHD+` zrY;NF6!c~8RdYSgWi1Kp0ixD^-Woy*RQ+DVejrd zxphdU@VkT}%f0Flh0fi|X<4%#Y@M!G$M>N1h_&}6`QptRoi^T1UtjF-si6DpTQTk4 z)V65DCf~wUi{Izqnd~1$XPz?x6Uo%N6zw{?)_f*vDNj%(vy=9Eu3@mrHs#t zaM7sjZ)gGcPlg+iKK$)1;| zEMKd5x;J&5{r&^D((iw~{_4EVjXMvUuYTWfZJxKlq|@ReL9Sa@wixh4?ubgS{Tlx7 zPxb8W`zpkfd9Kgfed5^N`x)iz74JQbz4K>Gi@)*XpRD|Q8@dwai_M6uL~#IZJ49 zJznWL=~_b56s;o`5_6xmM9p=*8L+x7Lf^x<+j4cIK$2GYiH3iHeO-^Anfw>&Q?OuX x literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_1_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_1_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..8f4700e7dc4e4a638106902ab2964658d07fc373 GIT binary patch literal 841 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||6)jDV~E9R*U7u{ zV?qUv)fd0BESHa*tYMK5S=Zn>U##jMgNDWm4bMiFBN7543W^t%8Yd)63-Izvu!st= z`nu@2b13gzu)+Dw>)NWfKem2*cdz=LWLNf^ysnF9-v53kz0>@^kyH`GzneJ$t0UBo z=Lh7!4O|_uuHVj;gONcvQtsbw-#0p!FHc^xHa~$;PF0sJ^CHWIjQ8W583oZbdO3+ck5X^DIM8DD(0U3!CY zLKSwRw|2-!-Hg2Ah?5$b$rQLFCmoCS@`7uRK9E~>TZ|2F1{+OG5Z|CoAe!e{u zOZo%_Lqw$|C;9bHTy;1{otNQ=%acmKy|*8qyENzCoSBEBPV>vxD}TRkHZyj|;>XF0 zS7@E%Qoh<0R`>sn>#NbY}Fd%TrrZfBtLMf6{tef2CpD+G~o6ELuxfe9-zT zF`rNG&Rn_Or(QieKdGdzv17@-wAG~@D<)jIeMWEJ%Ja6?oKZ7uPB5AMnDXs0D5r4m#PFj0bX`P*dl55K1j*lAy zrPk`5vur!8xT?#r?S|yHz96^t$7Vcy$ru@CbNQu$a*M-(32F1Hip8HRZPHmBQpD0~ zu`MNTb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||~YXE~i!y=K6BYYx%T055X zFH&$7(F+Q&*f@9Z?cK+u->%z#duKq+xnm$GZ``IJvw*{siB zn|`f+KKs2p*zxn&7v!CCwWb00pX-GRf;c4Thl8o?Y+@-r8&zW6+ z=gH#l{*Mi1dXAO2N!tJWX)C{ep5x9XX_Cx_ZlAOi4o>Cye>&5&RYKX(a?kfWyZ#to zH_r=bN&dI*d&Av>BI2($r?t9kx(2#lncVCB@n~GTgiTmNxxv$0&qVWTYiIL^`!Q}X zpHukvoK^q(f3DlFt9uGYGWm&%;#(@IDGbgcTM z(wP|Na;fbg>y3La72J~7&Uqr-rIoaG;VPR<=ganIE=K9-9eA_jh}u@$)2Aky>Dp;+ zI`r7DLu08}&lIzs_^BSd@7ii|1+ey1GBa7s5?ixpuS>p(yQXU#o7(0{nPIcv)z9%Q Wo)tXDb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||*UjU zF|H!6;d}FTuivHE!XnuGwBdyQ2k8z+JI21Zj zMkg8?C*OEiekV8Q%H4hIS6T6_dwa%fRjuFJ&FA&LrhLs-VPp7Ld3E{KEjqe!OU&n7 z$cj1_|D!`fnc-GM-2R)&h0~rsRgK$o=NQwQlC~$Qx=b(n`Ocl2`;LJ@{$O?gMXm;M z{q3)p>18JME}Ls5Ce(XPYB6iWo-Z97b}kdj`6HOmNi91rdh54PL*z3s$2hUs?FR zA75k`5C5xhDxdT5@q7CdQ#C}9Dzopr08ol^f&c&j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_3.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_3.png new file mode 100644 index 0000000000000000000000000000000000000000..d7784e67f1b0d9e6e3facf534983e4938ba7d2e1 GIT binary patch literal 724 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||XnTF0 zdAGGs+1jwLD}&?bPPcPYLz|zAOB}erTKbrUIOCf5y|(khr(b7y!ep5~hl}C-y!bPV_PsP*uEXYkU1L?( zWv&Af##_Tag)FGcN#NUK`OaR&LCbc_)UQ>ilRmsSeN~DfuzhCX&u8=A*ZrEe zet*=XIm*w^{3<)%zyHsH>8FohiTbFf!)9;&Jf84S}*j(_wh-+o(B zNo0Eex8$A{fsCAIi&q73Zw)&Za$%D4`g^_Z371U-k2`pE&N04MJ!_fbGn@V(?cWB9 zN-ZIQ_jO-HDL?Jp_dfIXv~{)z&j<(>otqMr@mIZrW0h6E!l`Cq=eqx2Z&%gT`RNKT zS7&}~vFXpBp6j!%gS;%B3ru_*%hA}ip;G=?03*9bU*@c}v9bFPR{LKsb>HxMHm_3C z%tXGna~8k1I39l2H|5!dKf7l~h7`8U=rCM#sFVdQ&MBb@0QRFty#N3J literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_3_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_3_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..53767af66aa2f605ade4f341319f2faf9f534bec GIT binary patch literal 724 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||*TX} zF|Gow`&X^oSO3jHWDbX0%LgwT#{L6*Dsn7lIu+t!Yc`!=isW0+V_P<<@KHm$(f0a0 z^KNUOvbAAfR|dz=op!(OUt5$K!@r7+&$gJ)(~&PMEk2!@Z(~#KqshupdTf6E-X$N8 zU0&{A@$C;2^N;G%!xGPx8osXHe*E*RPf`sr3eS6j86VvI+#Pwv-1ga&qYqw6xrP=- zF-jyayXG~I>qkiJ@#4o&j?^(Wo z;dy%%luUdNAI&;!ayDkq{G)L(_mq?@o*OJ*6PF*!BUigKido^6fwA8GJD>0R-@m?o zf7GKn%FoaIDm&i4|4+dF7`tWHy37*|f80DM-Y@1;%C>mblpu*)^WK(quVR`Iv?$7* zgHbS1Uc39Caj4_&%k4H6hCU0YG<6(cslBhPbS28rxTxzmTkUIx4#UNkeeSz<-{lir zxT9u^e6mW5L$a}aXlvAptwzh5rpZ)(&9h;ey{yxMEy(N1oR9Y|oA4SwubdKfvz=2= zaY@&&Jjd%&n*LvE{cmq8dCQsB)-j=Y*%YVO_Kq$AS1VZp<>p9y`n~>sQC*#%uJCeo z=EoMB{`~2=KHECT%i_7f#K*B5ja?fm<(~yGvTO8Z&RQEAyZ>Od|MgP$4X0O_zOrcF!Y2v3vQ- e-+$lyT7TEUtia~yBMk-y1_n=8KbLh*2~7ZzAwin} literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_4.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_4.png new file mode 100644 index 0000000000000000000000000000000000000000..4bd763973725f408e060fafdee0beca4168e424d GIT binary patch literal 813 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||=w9C`QF~s7u>tx^j zXjhT8`7^DJzsFq{IWQY( zOzm=6WY+uU$F0oASJnz0-&ejb;?9!DvpVPIe7AjXt^iyVW-H#kh17T-Nl0$NB{g0HJfMW%=o5+-DmYKjs-WYE6U%$`^H$nIHy=8 zh+)IWFOhdcX3I?Vh~o84Qwj1Cl4P6_)+eESj=dwDNsDo<5MRIUrJY<2i#wG~r8HH~ zHBS+0apG{CCbj9xgypkryk}0Cm$oj8efivAT>+SQD1pKe{$ox@OxS%iDXIlX{LwObl8yb-~pOTbp;@ z6tlb5RXOkR-t_NR70vhWKl#|Y|3~dhMQ-i*K%V1YBMvO-+9D+-&uWx?uHfMuCr^#j zlji>Gck5~U-f?7AKq(G&(ez2mb!B|W-14z>uw53oO|5zcvSUd>FxO+zw_H) ze!YK@#GB1^_+K>Cf zcH5YHZ{J>i$TQ);Z=`dnm{-$QxwWQ86XvUUb{OunF7KYsQ1Sj`u&Z)#j7|Q8rxh(* zzZ%I-=gZce${lj;;a+zy4#k9?L+u{ZB-eDC1bO~X=$dls0h5euxJ2yZ$Vhi(^B)>B zrpT3VVq4xaugSb7df~3S_f9TmFq@!~?#i(E@Fef|sUp9VTLgSoADF$k>#*nBU-kR) X5)2w-(&sZUFfe$!`njxgN@xNA`+0DG literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_4_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_healing_4_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..73287db93892f2d5c5d242b5688200482c9a8097 GIT binary patch literal 821 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||tx^j zXjhT8`7^D*pWb>^%cNt=s!y|ju;$#jxX9_YhJx4{fozeBUzAtmLHg^S<)A<*V(t<&_RHf4Kj-DJ^eDQRcLJ z2_DAgXJTsR3otQQ8RhJMG2uwt&!5^kHnnYxH(v712rCtI*jWDI-MzbSnIAA&Jnz`T zl<@fF=3SX{p3LyLoOL9n(=FR~32Q^WaOf^6pJ#r3%k!clCic> zZp*a=JYJfcOccF^KbfeV4^msYeCF(12Q#0WglR0@aBWdY?q}DJvyv>1Rr_-=3LcE= z?lieO-F=Ic;jYWN3;|Y$qP%Avl>%E2%ffSb{e- za?@q`!rGU?KZ~DEjLOcx^l!WK?|Z9u{kp5Z>9YJ)r%V=yP|Gc=m!;n~m)X2wkH&wS zAFj6dD$YH+>$-DWN$j;-vu%EU4F7ucR8z^fdrem=eR2=5gm3&_kL`nS9{i>`iU2bf$1*+ZM_M^L*=E#35K&{!UDv@x#5z%iG-2 zc2w9oPJb+T?b_**7^^i~L-Yb7+rP`LRcvvXBvB)b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||o0({rT&Swx0QPkzG&TeDVHv+m>PT(Vp&b zag)=m%a^CueEt)CWwU(Undi@+%Y3UoVyP8NP2QVa~ika`gIHw zE=io)w8W%sp?ro|aZ*o!Mv%pXV=Pu5|92WD^*(+7+C1aRmYZ_lIyiQpyZp`e?mvbG zJ(JIym=vD$@HcMze5KTvL;2Fa-O8;UBC6ZAFr>_tY@fL8^OBt^*1_u<@M@k#PY|9y@G zE$1%5*ogxe`%iA1S6hK31y*n=IgV0*R5mhEfszu zpsbQn?VovO%DLa{`dlx{b%V^c*A(;oZ4jBYLP^u@+2$?*U#wE+1T#6lQJIb*_Al%zDZ8 ziK}L9zWJx|%pB#4^JXm1u7=#4A?&+1~#0uy$>&+`~Ub{)NI&w_uhuv+wc7SEZ4vv_sVd(sn8cs1_lNOPgg&ebxsLQ E0620}zW@LL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_1.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_1.png new file mode 100644 index 0000000000000000000000000000000000000000..9c1455fe84038896e9ef2bd5ad4788e4df338281 GIT binary patch literal 860 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||7}QOV~EA+(8;#> zGNBT!^M9Ml&;Gk1=eStW0Vk&84vyZ8yb7~KN;-_37BPq{_elMyuJK8G!leL3S3y>; zi8`}yaF)HPczfjAy6d~ko(Q}@^XAOn;`St0mgP2AtIz$G`S|&LeMnT}^jTNi>xI}A z-|NObT~ORGNwJ&zy+MsB%YthwHg4PHw)$p5V&cTz`|mpc+4ONmRAgkLiOizK9Tps! zW_pQpoo9Eb>|{7#eSCkGskBVVZiW{ZBn}y%Po1nzv!Ic zj0SOaTa~07wZ)2T{ohqx;{rlOGiN>M?z#MqlgU5wNr2TPlf`lClXE+L&Yk;sEit6y ziq!P}6)j67dM|igwzWD|TRr#PL%|@g7KW9kZ`E)6#LaWGtJ`IKPKkwYLSoN^CWXG2 zWxHQUoBzz&-TSYu^WFmgOdc<3HU0Ap3is#L3$H3X7T_f!TA1)c{`-Xce-CVJHk&)-7cn7>HQ zyZh+YKfCDLw^1gh4zVvvG^RA>Lp39jX;zYi%F{@3RZdvnh&IO5iHr2b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||f#=Huu0^$SEpf;Rv9;QvVB z$=;)@WlH!0j8Y08%C@ae>C~zq! z=8#ppnV@G8qr+2~|EsR%6kK@Aw7@x;JySs;`Ak&g-Tju8&S5~t9{PFUfMYn*3Lz|%!SChrE z+iw@;-}y2>cYEu#UuJ%o5ZN9w=~U#ib!R^QycYlH`gi*e zdmZJAUr*b=ZNL7uZQD5yaZFfJ+2!ND_@kzqu(oGl#JAhk9Eufp@;)E^wJX5e{LgV| z=|}&X*>7xGvPNc#=sC+J+HP}7tQelSI_4WBBvsy&x2yNd;PIbl`}p$N+>7^aFTR

    VNPcQD1sQEkfe@bd-&erb%`;KrnYIDVeKD51Ivi!2GTs^-6 zhf>tUhoQ5I>K_Zrr_Q`__wG_L_XOE<;R*+)ss?E_MR}~gno#zQ_lakHLpW1()tapm z!W%a4c7McruJX{1HbW`ds|=1Z?o+lY_32-HDWjAf*mBk=ZjX(+!ND1&@fTN_U$`m} z9X*9ZGr&vn$c);xDtrHFR^|SE_?mB$&f$!&`ybAk_ibi%_PoW-e8)J>TqrQ~v8exP c&hVeX`a|x9LyBpJ3=9kmp00i_>zopr0O34~oB#j- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_2.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_2.png new file mode 100644 index 0000000000000000000000000000000000000000..1822ef74bacc48b984ad0ff77bbbdcbf75305b56 GIT binary patch literal 829 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||6E97V~EA+(8;^= zVnQWa_t#qgJ~L-$gz)jcRu2UMV@1W16Sj{cC#(?caCa!_V2W!r(q(Fy5ESvTb;1e8 zg(`f;eX`9wkBjYpI~gi9g|2%RpZ)Up(d+j2I-?vX%-UVO`-{-&uP>!#&hZ6aGP+wc zw`L;q1^I6`ckVu1VUki@e9HWOefN&Pm-p`2yVrN_^A{#dr$-z++@n`DWsAsBONN7% z|E^Y;JSnhacZg2ja4o5KVQ$p1!#vMrG#p=KHSsGj|DRgicSPk+kZS_v`MbWM_BBO>^u~V3aR7rx+VuY%`ltVUPOxVy>Bs)*RL7 zHRCkfykpy8Q(mjn8Ly>8OrEnA8O)ooL^JoY($q({uCCrwp5OnMo&SKP*|qB*=hq+P z&%giZSxFb4;N|TP5}zJo*=Z!Thv5i!WA{Y&e!0sgyc~_b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||71vFV~EA+(8;^= zVnQWa_t#qgJ~L-$gz)jcRu2UMV@1W16Sj{cC#(?caCa!_V2W!r(q(Fy5ESvTb;1e8 zg(`f;eX`9wkBjYpI~gi9g|2%RpZ)Up(d+j29JM)uip%q-$0hBwt8G4fQ_(AG+3fX` z^@|vO9k#PBFPG?V%gOWm`RsST;P(1m$G?3uE1kFa@|3tFNq*y9F9I(Gi9BaudHy5( z@x=*;f66fA_8yGtHf`IMDamgBFph2{j^k^TFZl%tAv&u;b`m= zT*^DSJDcG|`1(COg*O9_b@WfXd2!A~b@}6eHv1oadwtze>C5JZK|$f7xtA}5ifW6y zndG*|#KtCX+QlWfNFYM9^ITw=tVKVcu2t2mMF-j)dL|xO*03bUD<$&!>DO+HrzF+Y zH2r(<_s6?;`y%R}8ht#y{z&=t{9|j^>Q+Uv88)%h9I$LJ$vyiqhppkmJe%{HDP5by z7Mt8sxpC&vExzj}FLV~K%?`LQNBqRW3a3fSw)l33bY+LH|8#G!?Z*EP7%h$;`(^d- zv;GnO{QF(z%Y#cgX6$3-*A`bhG4!#|FEf^9I&ka}2vJorP zw^7$}e6H-8p!ozd}ejsnR4Vyb%rXZ@9v&;D(C(DE?WPt);H5w#kKhAf4S#hzO+o&i+}k2 qu;ek0bH#@%;|jiAzt8Z8`Q!Rn`CZTJ*D^3LFnGH9xvXb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||Hc-OEW?gkSETkBHPgnLP(9tlYQ`Cp<2l zbeg4Mhw$dl3GH#)4<9?$uzuf8_YY6k@2;z^p6xnm!5URA-o1X^r>=V>dR*3Kkb3?j zd~aU+#~ii>qp0MbgBiY&Q@&W~&M8)4o|WYoY_1^nPy4ydLcX7$pGY`vFuCm7#AA~> zX_7d%-Z?#snj#J%C8n+<$54?I%hb*m-Fj;l8mfG$`?<+fXU}GB?V#|7F=wCF^xe7h z_{ zDsDQOBqadp{pm#{@QUzbM&V zp}2A3(o8iba z=6QQsEG%sgpKe(7jirH)*Kx&9ZT$~&y9&D(-(Ooe2XY#8}YF$x2%g+aF+!|7O zE;aOG*CN%|`xah*7o;|Q$<0ZEvhEt18C^w^v0Q!r=L4YkcS{wT7Rd7aSN&`F>Eyticd&+u?|P=Zor-BAVx1_n=8KbLh*2~7Yz6l%@@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_3_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_3_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..503b6a63a33d812b5f96105d7ff8ecc64a185631 GIT binary patch literal 843 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||_M&6v^f@yNks z_nBvS>YO&*wY9xlyIa3oQ1Hs8u+XK!kGkK#TP$i4^!dTV^G7B=J^N3(M@@OkmM_=i z)%W@^dRTGZ=HK?R)OyYO?>}G7uI|vUznhqy-Ca3r(Ol&|oxOhDT30kOPj1p?kb3_! zd~aU+#S*TDZO0PU9+h&Aobts=chC0)EWW18S4vOd{Xg~lyb~^eDr;I?bk5|=Tja99 z$M{pyxt}jB+5Pz(9D5dMJPUDc%*xsn>9_mtvQ=3rW&h?Z`;?LTG1c{%_MY`S_v~=U z&1tdzYiIrY_mRRLlSu-{J=R*@s6O-QYv_~w-}{*pS{S4ku1&R)3%>i;AVjW=ZTA+t ze_%$e`H#;2xz>XWZ@_AT=V_i%Gu98HvTBgZ@4U|p|Q@WWcPNTCo-vlkGkjF zy~}9F5+JlZxhA6{)M;A!8{YOEHlL%jaF3Qo&;NyFSlY(eVLTAE#ZiYVU*{rMKLbnlNL`l{_;(qKR#!|Q%kqi z|7D-QdDAjIe&^W=lYzopr0QVVy As{jB1 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_4.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_ice_4.png new file mode 100644 index 0000000000000000000000000000000000000000..765defc9833a8d4daecffe2b84e6f75ff7c56973 GIT binary patch literal 862 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||nHp!eA)m!@Tl*HW?AJZkwwZvxq@b1a`!>#9AqIiR?(^T=O z7#GiSiRH3fTTCt(9e-cVucx;3{JY9Yzt7EmzU%1u?()T90!yCV`&<8FGw1bX_m+gM zUzl>}$`es3eQ5>}FV<=Ab%W(J3@t5>-kEDJuz$^(V@sE+TJ^G7`M%uD`83GB@{31e z=GLl54`kLavk6$VZ998|Uyq`vkWli8U6N0O?9W*SG}&YeJFB>~JIs-^c)sD-r#}hu ze_!2uV`5QRcIMzeIj_uP?(P$g2^G7G*|>S-Bz?5Ikh4`&tXt-Z++7_@Ezo)BgSvcIjE65pZn5mc)t@9)`-FmsmR(8y0?2khhI^eEp~8rJ4CZO47Ui zS6QoUj{kV>>vjj15A*iiO)E%g$eX6DJ=L&HTeM?>8Yg%8|3w9_)#SsJPuZ^Y3$|o!?XD@@c%7XLj-E zCj&Fzle;9txTb9N@tO1d*eR>+`{%i>IKi&1eJ3));m)k5f3v2x|9>}W`!1e7p2h6! zUF*4pnD`7l4_$kwH($E>^Sqy}tY^;na`f4-d)zxzVa7GSn#E4Z9>qu3F1Pho(esFEc~MR@NyT`6SYS;8z%}Ws#NwgEV-|C!|7Do zTf?_$lNU}@tab{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||m+ag zIjItD>%ae~hg;9LMDYe&r>Wvm zF)p6v63b<|wwPQnI{v@H*|!hF!|n zwr!8RdE>zUACqV7w-a3-yR)l5VY0}CExUA6R$qSUYB=kKt(@aL?mgc#R&p3NnPseW z^qdl=z$jmEPBHe{!v%5gA2PaWi(1*&=>OaIv8*QKcmLt#?KfV&{PFSCt{s1$EA9NA zGM7)|#XPf%M?V>u`JUV*8OAkbtB=o|=f_U%+VS^miHO#xgQvQ7Y~IkY!&LhI`mm#i z>&s6@$FjM%U2JAPdYzS%k$r|rVs`oT^Sy%Ss-KCA85o-@ADr0kaPL*n{pw5EN)1~z zpI-U!=m`rW%k;-fQ%aMW6;&5MKlkz7tyvR-zD*DpI`vfO@nhi^&4-t}sGg`j!r3@c zNKvJ-r(wx`wHr>S(%u@rO`E)MqGHXnm#<$hkE?IdS)y6F`|Rh*$!j)pEG;w)(3^I_ z<_`{11bG^7ng=_l^n=ZFK j+;Z{Bk0-1Q|C!BpC*gTe~DWM4f-`kuj literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_0.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_0.png new file mode 100644 index 0000000000000000000000000000000000000000..e6cec3783e769e44906ee29353792ec29f660e41 GIT binary patch literal 629 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||NeM;abIxy$gHKT|ce;?fP|-x4rj&+dkD^#CG8IW#Rvi z&cA)@vuTBn3v0vQuci!V&lnhIcvW4vz2HQpde|zi2CWI-7fH67J}$Ai;C26Cs$FG^)WW2N{g3( zpi1(HgWN>^nWISB-YJn!nzw3_g6#ql|YS}v-Q#^+b`H?I)r zRz7uP$pkH<$zpPQWanKlT)>iT6g|m_>srAXp3ubD;`qxooSPm~Qo)Qc|+8v-4AD>X2H@uVnxA z!o`m~A`4w!FVdQ&MBb@0IPNt@&Et; literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_1.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_1.png new file mode 100644 index 0000000000000000000000000000000000000000..b6e4f88968bc2bcc8c09154731ee06dd5e44a149 GIT binary patch literal 747 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||juz@M)P3Pnr zdE0Ln-mhLAv87XE<&sJ3UR|+#E?4>OzI7LkJ~GOc|9j5tMB>!ms=+_U`OrWS#R@;=hgj{T>aB@cX!FS zucPtOz$-{KMD$(Xu?FcD<=|e&k3kZ0avXt<$3((>o28~qk$c(QlrGJ@b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||+>#nMb6oOdR^{C2}|pGFG*ttDdpL> zvy);sThzB-eX1Jxs_Sc3>(rhMh6VTE{`kKpKYzJ*VF9x!L)i4`!WkTly%R061q4^! zcp#D1HnnB9>}h$&wHAtOpDrvuab-iHi;G6shBplVwiwldlWO~(x`*}C_NB(@&%+L5?O2=8AiznVa>-&}B$FbaBO;>3FW8l%Ev^Uke z=KuTDzkmOPx1Z#l)?Cm^vRtfabL!&H%dAP04db{LHU9fI@9z2f-<#$2pS(M7Z&4!q z_t!j|zR7pytbE2h&G^&F)8Siky`|V>mdEGc_*?Y$jPWd`66I|j9h&F&SL?og%loLW zGA$y%bLEsyZvh+0&6k7k{eS4BlN#{j``hSU_rw3aSv`GIoNnh?o+Er-# zE_}<-!LVrJF0Lty<^9i{t9bu9d{e%8%d;2TP82$@%(-zU!_V(R`(K0Fh1RO7cVq<@ z?%lU&$zc`GsR5xotfiRq1p0hT*^YWA)>J6Cu+9vMFy+k(2&!75&owWXYl2pLoj-?q z@rTaFna#et1(S}fEs&^M^|NPT?#85ulRbauEu3xhga1%}jgjHo$N&Zg1_n=8KbLh* G2~7atN=Zrp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_2.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_2.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4e902926ae5e29b08ef8b33e99b1a49f65a67b GIT binary patch literal 735 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||`D!D83M}lzkm7i_s*%* zCSz-hO*%I>?f+l?RXzw2O8 zQ9ZWKU1h_+59;mnr|+;om8*_6IGGrUV6?cB{Xm9D4NV-Sj>GUg}Oc^r`>;$NO?0 zb24I$=lMSoIVgL&RiSZ`@vK==7hO)W9lUw|d4;BMbFdn}?KI<~JtYr!h%VyFYYn;X z5xP|TdZ5f{* zKWUeBTOQ@%*t2W@^4hAV00}?cuTNDk&Apwz+R7kP$1vc`jdTAUog6|t11;7~^AOtO zutwem3d6Q_&L&PXUWA3ZYD_3rd;WjwC!4>W9T(>Nzew9!)~5=%Q`BFv46T?{EeC6Kcn>F0-J=RD?!PZ!PC{xWt~$(699Q7NUs0@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_2_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_2_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..f862c84c28e6bb44bb59605d567edf33aada4e85 GIT binary patch literal 742 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||$>|d_XmwSIpFL_$)lqpk`ZlFf9Z<@01XbhxNBtn>71>2Lo2Df35Pf;ox^+ZFu@tmtk6v(o&XX6?!3I!awc=t0^%x za7=i=3^KxB(tDX4qi4%^zt8;b{SUO={hOl{WzFMA=2 zg~v9$w)j&dZsxEhU{=HA1<$^4hO~y;@0NBgZB-i&%#(Y^;Gt!rANT3!ZgVG= zRZU@{moptgZ`AyleE0n84i1-=s*N)wb@cRJY`?31YInbOhl0|DDH@f}4CeY>I93y+ z8PYv%;qBz^&BdP#4Chuc9Q(_s&#K>=;#OSQI?FI;`wOQPx28=Il4I4EJe_(?LiATV z`>*)$hrNNmt#vKe-`7t#+rB@*xFq%i#{>tPg7P&_4sCdUVb`-azl`JlehDi`|9kxX zk^Jw1I}>~lm)J~L%_2DEO$XOJx4zQpc%%}% z$RhOeg3{R9Usg66l}@?~(|VqZhTaykT%6{j`k8I%h5YRdC(Q5ffBN|T{|P}!GHfo- zUnX^~*59ABJL=I=hC|)6rGFiF7f84HV)Fd?l5YJt<1e;KP1Ad_oLKJ6eYin6(b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||*TY2 z(xC!w{-JmGKS=EmNIKZXZpgtacYglc zLjT)$Yu~Tcxh0tuy2>@Q_W9~b`uqMJJIc_q`>1M^zDGYT52sjCDu z=Xq)-zuRHW@J^w9nX0u|PwnLe>)Mm*OXxylhPEH zv-#Y+&Putsan2QVTCjH~Te(Y%#q8dMbanL;8p6iP{wg%wr;IP zJOSc1=_gM8nZEzWm$Tj)jDiPWH*_~xJo3|IJ*#=yl>L6_M2*L4!4*G0YnQzi^-+8q z<;7H_xV)*mM`)F2Z(G+Sqsfzl|)hvHJ3oPwZ^#ZXcJp s#jd7){EeBkOK* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_3_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_3_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..2fd6dfaa18051a942a5cb881f9f37ee40909ab4d GIT binary patch literal 745 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||*TY2 zGNC+f{coeU@2Z|LGsVO)P)vhMNPC+G2j{{MENd#*Z)|vASs|&^60zZtqf|@Vym|9| z{L4#2!>{hWuCt0WE;8=MzjNuQkI&!h#^X@2eV3c|<3EokrEPX}e(>cHXQc;221m}d z>n#z5b%iIhcB*8E?ucLe!9*#GVasjZ|3?p3*{UA>_^5-6Vf9m?hJ>^kk}OM?_=qYU zHP%c$BU{dXK=#RvEh)#F3Nxgxe2tJ{bEy3BysOY-hj`JsDTJ< zS@B`_?DHH_CS8zLWVy9Fy1?C~qx&dJSz%e5kCCDAC!ZZZz6sylyZ0l%-u%7omH)5L zFR{P>`{ic-la|4{X;Y?LIQpk0%WS^I6ee~@pM@ei5^vv^_o>~H<-S~EY<KYw!>FSh>@ zu}0%@N0{i2$;T$D>&I<~UVqY3`CZGdq#NZ|)YV@seA~DDRfoltrd1P;3x4b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||SSPGn&j!?7-DhSb#ipK zOsK%|`sJ@mzAu@6w>Mjk>7LM|#p{zEd6#_L%wf0ULDzgQ5fNs`4@cK4bO}i~n;35{ zzPa;DiGTV0;#2MS*8E?-XhGNirKfBw{xcVIJ&5pK=CN$fyt@md)(gJ3wA=0bhKb>k z?dzK&^V8?dyPIev_gM9_j=HeU7mGlKS8u0<@0fMAO-XVZk2+t&$qJr^@X!#^JrkT% zK3lp;r6u*xWK3XtSC!e-R`oO>wBuyy=GP3z|7E#$xOsHGyO4Ns1IszfNs>Q$1gf{3 z*qGvxW7X5rxqNL|&i=VU`p+UHN~}ZYygHyFDaQ0@O4dFVeeaaLvzQk=l9;>i*xqjU zEB@2I`1U@tG-OG-|JcPMBs!?W;`xcwMF!h!ED!P;akjVJoL^t?fA#S@vZsOW$y3w?wPnoW}=hBsc83<#nB8$);;}Da`w~v^gW+%I$v5Zed}%8jqfYI zyLhfRkzh3;$-zlxixOXaPsQuc?QizipM3RmhPmC}3E!q$#%^`q)2`uccdj69$&?8a zO1Y(TcNd$y*1q@Wk>Kw4{~mt28Gq;ZC*g1QaYDQKJO$a0OfY!P#(8svLya4kV0@25 z%h@NY-}nFP_|>kt`F{Q5gXYiQ%-8c+)bV|V_#DSD5s!K4=Hcm@LbKS;8m)TTv|V5B zvQ1>tw2JSKWU7?E*&4ddI-92O_ukLrWj`OqhfLj;Td1@|;Dc-9QkTlA*}t+{8Qs&@ z2kSojap&?|>8{1fPXf%ZFVC{zDdc-U^~QIHMR#)p-v@?%J8fBMc}OT@-o-a%9bHM9 zmt^@m!V8*rSI&DZ)FQy~@c$AWo_ZyvEnnsK&pMxH(-FJl=eF<{uWc7kPM&p^P2KBC h--WGTa@h~mGqx8P&M1E1%)r3F;OXk;vd$@?2>?}FXJP;V literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_4_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_lightning_4_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..d739791ce478abb3f2c6e27fe656c7ef16a42d83 GIT binary patch literal 783 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||*Tv# zGNA&;>qDQHoPVQpvp4$y>wcj}OSdOI@-6uo$)X=paCEs4>rn@RJs(9?7O|K)o;~yC z&6{)QzLfZv&kug;x;`r0)lu~S`bodv@9k${cvxiR+&bkpI*);{OYbws&LyR12{%7vNXYt`BPrKa=wdoA<&RxlXYS~DxO32-Pngy^Jp zMLfE(VRH2yS%&fnvlmaBE5N*al~ZhfTP!=r?bY5vWs@ZDt~F`H7;PG=pDo$5Va zcVy1`wkPj!yOnkL*X)_s#kp;G_o%X{v@mvB&J)sV%-XnQj?aawPnjAP9QyG=^xZtW zDZf5m`n^nTimIh*(S7ArZ&sO3Gg5N0oXK;@kB@Icqgv*5ga3cc-_`!~Ftb0mXV&=- zb2tq*?TxtbZ_AhHOC)i>e=o6fBxK*zw`G|^38t*?{>ZpIL$F(@VgDkpkRBFiPPy#KlDrUW?nIAS+pQ3 z?!&d0%9(Qdckfm_|Kjpu?w#*X=47s0&wkb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||s3Kp#r5D8^su_m6&BhvtYkee>Ma zVQ^EHVb|T7pE&`-Ce!n{J4;d% z#@oBIUPmzMS=GK%tO8R`v~?t;J!#LZIC_%Gd+JR`&WH8 zI9KR$w5ma6v9Cg{^lK@(Drx;wJLi75d;7K4=T#4qWuGa3zdY^xW$RU5+{t}2r-?KC aV+`0XA+GV=z?p%8fx*+&&t;ucLK6T;&GVuF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_1.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_1.png new file mode 100644 index 0000000000000000000000000000000000000000..f9172656fc22a2af67ceb82377d159013dcbfab7 GIT binary patch literal 703 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||T6a$W2>{@8wng!yZ0zsHSBPGuE(f97&f+GuMxA?Q(A?eV{d z#V1X?VfVk=-Pwh~;<>W^E!k}hE-W4lpJ)GW*Dt=D(za@mhFtHIOIvsBI^X&~*k!@0 zp06&SW>}l8S9v+}l*>xxRh^fNR=;aguy~ek)@^;~w#`keMJ%@@IyqRDx++f>o*(z$ zce$oW}5?YU9p#YDy;gJr^zf&g+Ey{Pkt3o$ktO9>~f`r-4Nk#Z~JUIw-AE!wXZnKtE5*1241y{cpK>b*YrqAr=Q5lYW1_^=h{#IzWQ&h-Q^x?`P6u??uoBH^VwXc%)ZLo|NAX#;i4^^#>rYUQ};U* zpR*8HH$zgb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||(dJbUQNw=-Y-!&1{& z+)Q%?%Jy{heBV38Jie}7%f;MI_P^WF9lP%qX|YezGGAT2%bY=|^X|uqQ-r>6kCv0O zpU`vU-A{QNDU?)qbY7e~m{ zOMWW-sY&16CY^~%&(dC@mNkEe8I(Z@=E3 zbm5GC{=MU6pSyzk|NJ`p`^Fmc8GIca`l;tLvP=GdVrl3|$eJOwms86td%_hxwltsK z1A>BX(aa0BuRi zDEwUgr{ss@uJThM8TTYEHS8{)G0#JB>gN~(U!G~1aX00^tb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||S$o-s1R+s+96w= zQ@(q5Z0L55s%t`XcAVS$d``8O-M*hoRypY&+xDMb^zq!UrpGrP4&50M7pTPiz+(14 z#`5P`wP*hx&c0J%_S@V=w}XS>@RiSE{dd_KqO?6&pP7H>U;lhzUfZfg8iCyJ>eQZh z%=}@0B`PrVSj~~e=Y+jeeCF2fU%HXiQt0(JDOb&{XH)_g9outLDr;3m;*x7!3uKlv z+wc9+T_+QG8|5?>FgQ4K}P|Z1Mm9N+ztZaJlfKNk}sP z_OuwaAg?vEyz34!_FuSZ`>X8B|!_uNB%dhzV`SCD6L~51R_TT!IZ?^5Q zQgb^})7jx59lIc@cp^if;?yIPxcBX?Z=J#->N9si&`fKF2fG~3il?t!=BLNmaL?%e z{{Px(eXB0rXj;0yL&JsT`0{P1PCuW2?d&_b(52GVQqc-ZF|jcVjq-1mMYAYoDJad5 zTyC;4O6OzdEDi^!%sq~-E4OZXUEaabEBUVPidWZyuWcb*X>RskSNxJW7Qz;i^Umtv zp{NO7nypc%bi{4{^E%G_)L}2T?KzLvlVaujk7lsx-7>vb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||22Bo^z1k_J{JYuD|pukbYzdi_?~MoWq5fWf<;+vR?nG6*sX9k^5c|3j7BtTO?jB1acb3bJZe z|1SAse-}r{R2x|jxz9&l2`}q>Tj!jtJ6SyJu4z}$;&TdtHZ}Khcmtb4PP(u(6-ku; z`SIxdjpvLPS?}lBPk)=}y>jNO%|}v;Ihl6<@ksanQuv*v;M)D_hp)}&bFNHC<5~Lr z-A(zz?+^0}zyJBZBW9g|pj9-}g4IW#)_qhzJt?M4W;rKQ z)6K6BZ_JOpyXUXnQaMAeu`Kd^osX(4<9c`)&Ov z8}CmrNle;tetJRqmWyJdvzu8uxR#2E#e6vXce&D5hlb2UoK2R@44%U>}kdpYQ?U}KEYs!X%wHOyMZ z76nnS9h#!F17G`y+x~A`&=Y*jXO^%=M}fuMiz*L8+9qYr>Z^VCaYab^u}LRWzdev& Y>g1VIlaN1^fq{X+)78&qol`;+0Bz<#761SM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_3.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_3.png new file mode 100644 index 0000000000000000000000000000000000000000..6de4425d4a1ca62a17ccb030d37d1a465cb59bed GIT binary patch literal 685 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||}2me z8FvAf__|%yZOVcFa(E;RQYw-USjQh@|KM1{ARYBe?N-La*BmXrSss4pzbrSp+%3j= zbEEbGrGTGCUUk3TJr8Q-dVKkZxz@4MhqcdL<_v$DRqmU@e4y~%vFJNyf zR{Z?~e`I3^L%~eb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||h}_%h~h5>KaGdjQ#J&NdO{X=@Lw`=>oOB&vu`+9cy*(+xQLPb=y3%-jNp1;%bfA%V;(9FLr zX}Nt9WhXZVTW?yYEqQd0iQj4EnVnsis*jf{C>2PXEnW~9%Hh@DdO|duz0ox7Uj6Tl zac}v*yqRG!QC9Hb#=C|$<@Q$ZVRvweSoHDV-Q%;CbuKmEG^v(n2k#EPEp;v~0)lF{ znHRL*UH$)!nu^}JgvV()jjN02y#M*(U4K>a4<;kY8kJ3pFPj+hGIOP<&g@#Dv}lLb zQIGTI5|jnG*Uk^T+AA&FU%EI(X@$m&q*ZG+8vL3UpI0|&_hZ>?9T8?Vw|~~Xlcs*Y z#9(0f;^gxa)n{zx$gQ}g5-WCR?wPl9X1-XUtmPIKAkrax_2teFudnaF{`9D7-ub%* z$#Ku8i^jO$si|q4G4;(N;fW$g8zxWXF;h(XQ}%!Jna@sPMOAsL|9m*xf9GEO;#G5= z9lL!!{!>YvlJ<@pu?0EqM#91FuG!uiAHT#^au@+!9Z>*$!PD3zW7!U!-5}9PsR(!Q_XLA?LTewiHz7 sJeQp;q1Klht!*^(x?8k4+kb}5_rqD=aoQ*{FfcH9y85}Sb4q9e0Af8h-2eap literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_4.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_4.png new file mode 100644 index 0000000000000000000000000000000000000000..406c0b17f03914ad15a38a74604a4ef82bdcf292 GIT binary patch literal 723 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||?qE-IN^hV4)>Y! z=kEN!9qU? zVbP{Nr;fgwBhj&@e7@oN4i1Lg_|Lqzvv?bJH(MC|-5D|0-#3|Kg;rP6yiP;86DM<& z{_(%-TXkt^TZUcfnQ0wS20Y9stGW#AeV)9Vk?JxvM>#;qxv{@5&FYSJcv!^eu|NZ!&?O*p}`s1UbXLtn< z7A9#31iG|DM)>Txef@pa-OzT^GeYO5y^2ff+j*P1`DL6p4>Yd zzbCJ(=dnkbyQ`(0)v~wNtMX1?mR=t*jkV|4{OS8Iev{SmGg>THcErX{Yd1&hG!^L^ zrq;I>K010nzhY0N$Atq&pV^+z-}`L+U*%c*e!gov?O|QQ(6jUS-IJAEeLDo55AM6E ztmM%#LpqJEVdlctX)9RHeE#ynO;Ab8i+7311wK(%4Gyl)NqwvQ6fX%`TGu|1H-B!? zHuLd2k&Q?0X0&&uo5u@#9S-~#XTK;*OJ@1cSz#bWuTOJ_OkI^7F@^h5_+p@u8qbgHdvECAqnY&Q-EM28L+ft(l$Osqqcg3?QrKz1yX=t1DsJV!Z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_4_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_necromancy_4_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..7428d44d4fd855e9c011bb60e911297cfff0bde7 GIT binary patch literal 727 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||S1Z_IiyrJFI%!aXgiNeMcN~g3q<~5o#u$tNM9G>vy ze98U!yX;dp?{IeSn!c?+b$+qV{JXz}LO%%IFwGC(oU{J@g=e!?oVxj`DM^@N;)!iH z1(Kg6)waJrD{3fkQ|?|;oPZ$1u6+;x-?$#la7Xq?U`;tR0yd9F>>)a5QxkoT(N|Y<<^n&d|Y8nepT2C;k8L=C6O!&R_ra^Hug4 z(n?K_k4z8DZZ=#xO&2))pt#gt%u*q%~barm)Re)|j`#Q&CW4T4v{}b845kDocL0 z)R%`_w9S0{Zb`($yb|ZLr`gxrhO{lVxo$9w^x_le?b+EOQ?0hIStWXT z?Y+Lw7mvoC;Vn5i|{xxFfcH9y85}Sb4q9e0C^}yU;qFB literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_earth.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_earth.png new file mode 100644 index 0000000000000000000000000000000000000000..cb5c70b31938172e4c0bcd8c8b117caf5ba0f48f GIT binary patch literal 737 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RZq;uwy)-(0zq zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%+ABlCdB1yc%6ZPDbLfzF~s7u>15j? z6<2}Q{bx?SdU?_7cXLv!l0f-^14j-Vy`7y+6I-HUH2Xe#>DPBy0>t%Z9!pOQ`V!h-#yg@r9at3SLo%) zvpqTfet&O${(R2zS?pH%+-9nG4XbL7F7FZ@jL!KDfN>n#``y#LP? zK7IYhC3kY>{djtQ-oD^($*D=l^X2bdxU=)7$-VleGuH0hov(2q?f03wIh_J|X8txj z!nZ{Gf*&vOUlQ?{@pikoTstSrHhyM*ePOHVZVFqTt=SZGD`=WedIJS<|yMNIL&~)s{*HZeu1#mMrcf^(#>? zd?v(!Gk;2e~EPq72x&rx8j&_N@)`VugUC* znaagPSW%OBw|oX? z(}kxl+3`voo~_;Gwq>=uohM(CnZ$MZ%@wg3Um7k%1w4DouA_PIQsBySr#CK|{{Fni z(ns%liVsiH;d?#v+MKVaJd(O29D-C2om^J3?8dXY{*DPDJNHW8c)R@Q$*KP4)_uiC vtDgVLOQ@ewQ9kYG^ItOyS50~LhyUyEn*Wo(-n+)Yz`)??>gTe~DWM4fdDl)F literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_earth_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_earth_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..8974ca8c204708e3c70580a0317514e9b5d403bd GIT binary patch literal 6570 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 KelF{r5}E);#Mo#6 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_healing.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..96799d5fdedab3f35e35392a65f1ff11e493d05e GIT binary patch literal 769 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RZq;uwy)-(0zq zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%+ABl!#(9>;amm=ran&>#}JFtsu#WU zWI{z69{!(Go%dBaknMz9U$1iH8+OA)VV_M5Z8?k!JvgQvWKr`l=$c{R;@~v>?$wno zM~?KrTUCADmgmQ|4=4TOYlYG{gDW=Pyr{Ip!hYdTANzZSWqaH{&pQ3qV|8n{dVgS{ z7I#}>`=3v5E?3;#ulA?G{m`TdTMdsg1uJOj9x(Y}(Bcr18F%wval5IJ+SC_eYjhY3 z_Rkm4yuczTu)x%yR84$|65t4eB^LzWDteY2S6_@?#sQW(em7mwl z4AzT2W(zA1E>SH0sdna?%NxN$B^C~srup;#9$3Hs@43tC_b<4{oOa6Q{-sj>21$(@ zpY!*#d;a-Y^x)BA&{(jy6wz*@8h4{@`dZa{GE3BxO`GtPP-uM!&g}e z6`$t?EPh}8Pwsu=%)>E}nrCrTWvzu9BnV8FvX{jsUlb+?RTdpCIWUJ^>{>~O#0 zv4z24k!Y6Y3XTg7)(#s!UUlGBT4(NkeRRZS zwHOW_E^W*3S$8FhQ>3%$S)OB@jl#+xrNvyUuXfFu{)XQ;IMiXs&by1RZ9LPp0=wpXj9O8uw%pC=@#D*^+ireYq5Dx_5?gTS zDt0C92`$wDtCf}hzxPsy9b-#9G@V? zKMv<+>amt>t?uraFsZQeYuCT8ywijxR9t*-;bW|MFzxrW#G1pCAGiN0{n_{N?z~5x b{~5%XYLewebITYQ7#KWV{an^LB{Ts51-4a2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_healing_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_healing_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..8d7b3ed056017b7637ebc0b747b3e201e91d6dd4 GIT binary patch literal 6610 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!uTzEy=plmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{9z98CHSeEv(Kse2nXI{47M%TY-G2E`_J1YWmE zLYjYYE6-j2A^nY+)BcFv+W#vIX8V5o{hoWb*l9p)T zWmGtHi}9d9Goy4Tv+JglJ6%|0SpSH)yt}cRi%o;&`bnRH!!nM2JGPqL^W2gfTaYfb zmeqwt#EZ#PLt(9Ampm#m}x)B-m?Gk=CI{ zsvc8Rlp?*#W?nqx)Mq(U$MSj5hK$D7P20J3yjHF&`f7S5B6#Yo?92)NpLMs~2%0=C z`sKP}_n+TyOn!N(SihNViOC-h?CxL2P%qo9Lrp?Jbb!M~8wJBHUueqrI?B6`o zplf2ub+?!DXV36^xog2yzeA6BdMy1DY;@VeilgR4D!#v)lvkLx**TDf{hEeOk(KVT z0}JGz99nYxZu`#tPtUUakN^1WpKx(n;P?Lt=X738*}4DIH}-2)H?6tyo5Do(e02Ry zw$1CF{ODCj-J+XoHy*Gm{nWT8;r*S(0(-yYYTl4Mwasan;hXjqbp;#McW=4&_~Xt~ zC*CJ!&eY6fw#Ygz`1ICwrGt~p|5_=1P5yW+lKt$~dB<-sy;u{G5x9Sz(v!_@Y#$%D z$XCwzZBSOLc-ms)j~Cm7^Jic8cvCq=@I>Vmg=?QryvR1FDtx}>aT~(|CcDQS*0qw& z>*DUjIyPBmD@_qz@{DI^fBI+ZHP(eMH#G6^%89)ZyWJblK0B4|kF@Najjw;$oxkC9 zr^{yBLN)eU>+%RJSDmK_u5JUuNek zZ+GQ}J0&mO@aVKyXr*h?S;^2ZS+%Yk4={DLu2qjc{b~(QPKU*oj8FFzHH_5HKV$!P zSvs#ZDH+AcuCVR9ND9(8j@|M@L)XG5Zv5{ZM&s_^9dTwp9Q?9w_ zblFaScSO<-jnuh1A2JT*a$J}_Z9@OIX?uKMS{#<-SX+1RoJ*v$h|GjPUbhqC$^!fx zZydZledeM&Z0EAfk56!CQ%v{Kd$gc*`itc(%>j;$uz zuWH`;z4x1MKiwr7;ui_Z6cTzmGAd#`fB`kC)^FJBa0{O!Pt_~)l% zw{Bk~epb|8aa~lHK zlK%}}YguWiDnN{h89lwV!HN{TKYZv3fUm%jIQaKbZM@n|HABoK=l8VNd-1aPKl^ zgIS+^<#^*huU+vpFf=ylS9WK{b9W`vPq%(ux_bRmpN9XPnWg%xkD51@oMTFh5S!Vz zjyt2>{>eFhldgMOw{QRc@o@H^UxAljuT|UgQR>0c1Z&Uvr$V1TI3DC3zB4cPrd0Qq zMtSqKH7oDG^o^E$!CUvIrc<7?;%e*9a}Ex-=HEJI<#=aqgyP2S-Rn>2W#8~$$I*UV z)A04NSwH4hzPeX*D%|zc-5#+&Lf`d@GEeEB41M%iO>#|H_f_*h>B{xp>MyKkf6F;` zcJ|IQ*P}Mn?-icDTlLT4x4(IJS^9NJt)I6@Htir+?32|qS@+kga~xQI$n~J^kF%wQ z8-4!F`F3h~?Syl;7auZ<3(zsM{neB`C?*Jxar)p`yEHp)~Wwo ztHQv*kc_nk%q%EL2GxMJT?cs&7;rHE_qix|Ai{T(-^u0sZFcR?a?R@9u#s=~_29A` z!D(|JJSfSkJK9r}a`~q4OG(QozMZ~aPlBwsUU8Rr7Jm0FtC57r{ldvxf*Bb2Lo!1m zN+NuHtdjF{^%7I^lT!66atjzhz{b9!ATc>RwL~E)H9a%WR_Xoj{Yna%DYi=CroINg z16w1-Ypui3%0DIeEoa6}C!XbFK1 z^!3Zj%k|2Q_413-^$jg8E%gnI^o@*ki&D~bi!1X=5-W7`ij_e|K+JGSElw`VEGWs$ z&r<-InV6JcT4JlD#HFC105u#Gw5}B;a0@_uu<^wuDf*rTCCMfgxdpBjCHh7N1{S&o zM!H6p`pEh#atnNY;kxsRp`n(i=v~r#I+1zA66a3A(aKG`a!A1 z`K3k4sjg+Ic_qromKNlc79-nPTAT_J0=qjWB~8B~7h*HA9(PaQ0Jt7dFs5hb7Jzkt zR3ocQNrtN{C@snXt4T@LPt8fqP0cGQ);H8MMDb8XZUI~aR_}lf2M3guOMY@G$P`Z( zTP2VKtWxrmGgGX# zCLtN&UzC}inU|P@>?)8^DVZr&7M6y|7RiRjx+$qf2D&CDNk+OB$;nB&siu}j<_5+l zW@+X|V52|*YvmZ=X{%(UXMhk1$Vn_o%P-2cRSM6{OUW-UMo5KZ=B5UhB!Ys?(A3Px z(!|8X%*e#R(%2Ho#IV$&;>`R!kg0|SdS+nVDalrD`9-;jCALbLxryni`UQFEV2O&{ z0xRdD)WnkfqLBRj99t!jqZEwv3=P1ULBR%;tX(TgtbFp56G7PltT;8r4xAIf`OPUY zT_4P~(Z{D4!=&Jh{PH}oMo6B+V-7+o+!V*6lJfkbZ2uzvq^#8B68z?1Qw%pLC^bE^ zxTL7klYpnt)Y(ANrAKCQNq$i!lKsJ{g%BRZTREBFpi)o(XJ4ztWKbyDDitS|rKW(R zKmjI|oROH9o|k-< z#3UPi9O{ttgOgo8LG8%OAiACN3o45;(=$r^%k%JBk3}KG1fR_0)VyN6b|Wi+1Pf9H zV#fsysvs9PJ1!f2a4iO^(I8;~s!?c(p{b9SRwyWpT0&Czjt19gaFG-OBq<(EU8BK8 zQV5Wwcr7yJB3=C{Z-tI08{S0voN8N9(+{wVez**oC zSiA`K7! z&#BJ)svO96!mY1YIr0s=VWP0lCWf{g#)Tdn(+;wzc^GufFmQ2jntu1{%9bNX`roap zK5xtOW7~(5{_(X}-F=$-S=u)Ew}K1X)_#XZl8tS@Cfd~`B7WX`Fk#2bqH zZGKOg{x|y&e}#$;XQXtnjsfeUOH4k@{LUOMQ=d(JYhNCroE+4dcl4AH!}s5u6PbJk z7#X9OgVT!~XI-ATVZMxXo9^t7ZO)rJ* ze!8){zt6z?%U{*`wLdF$ba&W>Jdi!V|99XW?b`iMzkF<;A$dE|#c{_jDT#Y~)UUkw zJ#YW<>V#(o;n(IeWk;#BeT+AI%&Wk2_`uVO-g8?8XBFz}1TEgu5~=h^&{Rm5p(mp? zic5>h$chAQSjW7GC6*C<-HS?j%H8Kug?DR=1Io~PQj%=eLlPW@X-`L?b^=e@S$L? zqSR#Vtzk^Aix%vRo*>Tev1-bR6^F96Dm_>IefUg>s6bxc_Z6i&o0T+;<-di9&1g6B zH(qNwHzdf*rFhxPSy!_N=)3|MfJ7KOIcLnzF6~J_VLYWU|=ut^mS!_%+ABlA^lcp$zKKrrg@$&jv*GObtj$8 ziw+fO-Cujo?)rBtP2-TIOsQ8cbaBWvGb)7E3RUQ`**LS$Rho5d<=Z1Grc9czma8Ii z{oBs(Z#GLFdA#)NYSsOFD;|1^20s0o(scFI_xAQDQ9rBAlK($wDCF2P^Zd*0Guj=r zS|=Z6`uX>%x4oUE;%?dxnc6;tJGW_v6#4+0CVX}6=$lpCfzBGSo_Ad=ETvbs?M4w zhDJLkyL4z?%H4-j20t{t}aPHTllRI)J3MjCYm6fk_I6HHp$f0XGC7K&&3mLi{GW*rMF8PW{P2BpGmXFi^ zl$RgZU@$NS1kCaYFh$8l9k?D+R%;)gFMh2OO`E)08B)w^0K z_|UGtq+@>9CvH=AH%{uwxsw^JWWrljRplk%n4DrXzqqv0GpIGH(st&CTR9oGr~NEB swcp&l=I0B+%a4=o?%sQJ_`v@L?Y8i5t3$RjFfcH9y85}Sb4q9e08F`OT>t<8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_ice_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_ice_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..b2c4faad19f834a1afd58411aca1528a9db7660b GIT binary patch literal 6510 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 S{msC@z~JfX=d#Wzp$P!!9zkvZ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_lightning_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_lightning_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..02c27b7b7e6141d056e771c0cf3ad78e5a955bcc GIT binary patch literal 6497 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!uT_E&{OlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{9=R!7o##)wXe1NUkqt6@&Y@)!o-SwP ziYude%^t6}U;dN1{#<(k({dT_9t>=tS)@#5`7=+u*-EdoD!kqQ)!x!u_woDl z2?0IlW_&rf3(e=G0{L{I$Gj|+kT>s|o`t0;~A68eCe+jjYPQ6z@ z?a&PkwvVgbjQsz+zV()?cHuJX`WnY~lODLgefFmET;ZnGii?6SdIZfnC3ob>~y(#}wu^ z3te-*ta{*b@A(6(7)|>#%aa%G&A<8E^wf==!aA}CB{%%}IV0Zp-}L8Jvx)q$7l%qV@**mcv%oh~g_X%B)0Esq?wb!eCot8U!b`(5xs%Jy%^X1UzH zw$b|X1Tlt#8BDHDLI;J`;#Y=DLl`dcHnD900Hmvws*k6C>uz$^^$@4#5Vf(e^ z!j7ZUqVkqreYfj<#(%kLBirwnUN2zO>NTi1GSN*g^$O=YU;D#PB-3YAPK(sfYI>!f z^`-UB`#@#KTt%^Mu~iG(UQW5fs%!bMRZ^h1v7sW0L#Hrm#!Vl^9j$i`oe^tamcV|c zL)>DnSdxPQPm#^br0-7ew(pSS`_E6Mo$%58hA{DU zv!d)3b1wJ3Dk}B=Akb%e%D`_fQ*egjFI%Rw2fy03Z_Zm+o~E_!{Z`hX=u`7bR-~-B z?cH;3{zTWU=N{e3ePe&urn;qL(M|3PxtmN1R^G0gYppx~?TTlMv`rp;GBuFckvlJT za><1o$2ERvH2(Z(`}oSV^H~Pbhm)uMO`fw{M{(EesIBRYqHCw*rDq>czvJfcVfLy# zAESlcYxemUx_@(VaddKaF;WtrDLOyGRLx~cW79clF|Cg*!gH%t9%Mvt&HC)B+9|os zn&ZKrlaF^tnctY)ck}w{-b<^af&#ykZr}4f==j9;xC>W(y{?-WXD>{a8xyN_!3oZGfx5`M`!7G|-WZ=d zedst&zadn=GPgVUlv@}v8a|2JP=I%2`4$B^5hX1lLJ(){10ez~_=@-H7W zEvw&Wa4S=we#yefp6xn5KYSivJ-2-JWT|G0%zwwODLh}Tw2)W!R^TJ;i3>XeX6kPf zImukpf0v`lvCs8SM1Yag(Q7 zRPTK&t4;f*Uq~j$Ep1bOXslJ~`n22dk5NF$W7E;snfoieX-0t z=JQ{IroVXNQP$>pR7le0WJA1UNcSGmR@F6Khb~@SG@o~C>Yt#R)<5ji59M;Lwzy!N z?>%EtRfzYF^0l{xe>iGqI-PwL`qA$A>?;dGgH7}IzPeZRy>`Xg_T09&6_ZtC?j2V@ z!)DpQx#ZEjJ*%?>r@Z-j@pi(F?Lya%t#U8tedmxdYxT0KnOpONlpjuRyCM)IR_h}5 zJi=i8W=sF*Epy+#xs$bDuyXJGu8c?5IbN>q{&r6-#k!DJ|5<+Yyxco&pDr~rFfb%y zt;#YBN|HfUnXTtZ-Ub7n-|1X#9&a3OmwMR$so1c8gI1$%{HECN!P|6IdTb{uFJJyc zIc-X_?^fXww)Q=m8|Pgr&XNr(Qs?sd^Q;1q>iyV_#8_n4FzjqL7rDo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7 z;3~h6MhJ1(0FtBTx$+|-gpg^Jvqyke^gTP3i$R(Zu%AYpwa1+bEmY+I!W z-v9;Y{GwC^6Fn0>16|jO%rYY-J1zyAqLehNAQv~N5k)C!wn`Z#B?VUc`sL;2dgaD? z`9tB&H3%7Rq=pw#00(xT*4*Rs^S z5@lpd3vx<}k?kxkP6Y{p-JO$?reBc@u^Cy9yQgmeTn{K1(=&4mz&b#xkyWN7!_^g( z7Uh7|q$KO7=A`DP=9Lud8|oRNc&H+`0ImV6cff{&1Io%JKe-fSil>XM6378oDf!8n zDOM0>ih+@#S&F4@nxUzQu8BpmiEg5~k-2Viib=9*lBtP-nVAKWQJ#6lC5d^-sUV{& zatrh_GgGV#O^s6xj0_BPjZ;%nbWM_s4RkF`42^Wtk}S>5%?vHfjZMsvjPNhYOwY_q z%t3Y)$f%Ue6f0v>gA_w^!zA6*#N&$mZaqu<=QHRXXd5kmlq?XLNaqxgG&-Y!DeV`W@Kq%Vq$4*WNB`0 zZiG-2mReMtnV$zT)zCoC3@nk7Y~_|;l$%&$tCX3Wn4YR%ke3dYsK_m_axO|uEXgkl z$k(=&@piYh$`cnVFO z4J2K9WEPj?7gZwJADmhU;X%BWlL-zg1qE>SwMt9|g`%xeabj6&3OEWBU{c8$iFxU% zDYi<`Oac?n#FAbO%oEcLlZ=dX%@b3SbWJQ16Ll?3Op?NCl-K14Bz)19M$NqYy(gD?<}2Q)4Aa zY%AF4gGxr2Z*4$jhp(>{a(LK)$`&h6P=X6CEhxyzOf7a z+2s?|j;su#+d03WvM4h>qr|^F53luD6hch!$xKeoE5>U#vJyzJAXOlCT+pBja&fcc zve5_EVxSrg5*DBug_ana`em^`3!&fi20~-G!l_A&%jw`^}X*85kHi3p^r=85p>QL70(Y z)*J~21_t&LPhVH|$Lu`(e5UF1__i=GFok)#IEGl9ww>giC+#lKwtv++xydaem5G*) zNeUf&f-G)k`zDy5oLa*uuhf1*t5BtTiAJ}`eB-;ZQ(4(>i3arl5B>Cc{r-t(1dOkh zZ*Q?)UtiPSzB&HP%-H>^D>udJec0HpwdK^i!qz)`{?Gk--CBt$zc;1rScz>WoJTlTrTTv(TEA-D1E1`y^3Ny! zr=PD&WVNPjNpvV~?+-5f{G46z!R_hwJAb{D%{rE5`26K2|xNxWQ+J!lumWwqndL@3k zEBb1!qSE5rbmhHaEE-#rV%>#ne+sV`mF9mN&i~@**JztZs@di0N-LI5P#1O)ZFu*H zso~c5Em4Vg0#DDhxzrUT5W4H-lsU#vE0%n-Wmx`p+LA6`wG|wx5*<;2dji`T%iVYN znb`SAR_%HzVru>TZt0f5roM*F=GSlh`X?8v8s%)VH$X&?<-@fFVFHRX9a-YE*NVLQ z*brCupLwg;p}A#Ni_(_N;e7q!+BuysH9Aqw!H1MREGO^cyKSq(=os{dUHx3vIVCg!0NXPU AW&i*H literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_necromancy.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..90b51c8851fd2ffacd916d67c96703e7cbec62a1 GIT binary patch literal 713 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RZq;uwy)-(0zq zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%+ABl#S)}*x{HB)@ybp`)rr2{P}Bl&F*~@XS!Iq zYKKbOnstSFoZ#sSvypWa5L9C7?v;`hS-HUTsxrr#-@Jm2ERG&6|9|bu@8Ae!Uw6CH zO5b?)*_>@g+t{boJ-*S`!tN{^`HPp|d8>n3#|5v&x81IK{e8Il{)%?5oK81Y1EC2a zb#wNst3AIy-Tub+xsL96r+bfo?5w?iu;th3FOq6MUVl=TpKlkqwP@D4KVQzim)SP) zwq2t5kIKJ3Eyc6W+w}Th3EHVA%vCUR{fzexMf1+BF$>H|c&&Z>TSJd$iosgr?D>uf zQE9t$Grr5Jd@N`yI!g0^d2T5RtVY7c&aUqZSQ$zp!zzoPxVGV=r%0i7O4_A@;Tc~+R7P&xF`AS!pur5V?Rf7R5e zeYTSjbYV#``rcV65g5qww6I30@vhmK-aYB9*UGmpV(sqhGU9V@Gu!Zvdv-3%xze3M zA(mGJ1ry&}&udHj_4gb{l;k@drO0Pf3oU}SHXR6Hw~^ugegDJD53FD3zie6c=;aC# zv-=xNPB|`UUVb^bzW%<~qzH+-))Qs_e)zz+*)MIwEvKtqm)$li%bmN?m$BEGZ;sM; z-ssFNMgi+jiwZg}EtsjFQ?}bW^Fvu}>U(Ww<>fzHexJJ`S2_2e+U1w`eu`ITb~fGc T<>+Q$U|{fc^>bP0l+XkK3nV&T literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_necromancy_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_necromancy_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..da450fb8a30d0e775487031db53f0579124229b4 GIT binary patch literal 6436 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_sorcery.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_pedestal_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..4747ba9ed535b08889f5fcfc0af466204c62f88f GIT binary patch literal 709 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_0.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_0.png new file mode 100644 index 0000000000000000000000000000000000000000..973f908d9781910617ed67fef5b1f911444a2e0a GIT binary patch literal 521 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||6P_}#FsyXM= z=bcwyb?Rk_(o&X&RYrZvzLyK^=1aCUu2>bbKKx9N029MylZS?V$_z_IyfiIt81OK# zgt~@i-WC&Fm?`C@$uJ{Q_ltGI9OG4|HtD$R_t9LqYRQzWO{ z!H#v=OP>k3v;=Xbx%G%Lhpye(f4q6$d(Q8_YcC5iEfsO%_^P9{WQx|R{oNe3_w!4S zKc4viX#V8V*#E!GjCZZO-E;r__mbG~mCL8B;*Wdq=?-`3S~d3h8#_W))qQix*HQX< zZn@yup6|b7&;HW=HMh_Fqxp29TiaYi4L9#H*#GYN9K+4O{&8R0_V(HV{_W!=HO?UU*K7;ecOW(O!cFle^CD`jr?f%?^ zo;`8v-^QP?+^pm6d&ctdrJ6PSCl_7&Y$N{Xv%2|D|Ufq{X+)78&qol`;+06Y8UJ^%m! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_1.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d9e317f4553b14ec1df5e57e8e7a014d7eab1637 GIT binary patch literal 636 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||g|92C;RXH!e6keSyuY=jRfyk2RE|+%Dd#1Uw(gI z=Q8zuoKg_Z*|-V|6cEO2EJJSfo|)Me4fsmSnP&TPBBa)x`=E-j~@I+?_MtL+c! zTKAem(MMNjy7!*%!KIIH8%~t7*H~(BjN!sIU9HfdWQ@7`9bc>(bwB-G7YbD!hYo{z)`fAMPdhNOJr;KL7sw7c)2BUalin>=)|$ z?VsJzxy4t$8qCa)@s&BgCOmuJACJsf?-xurHPuh=Fuu4$_?X1A&z6CgO)j%^ZCbEN zRI%lx!Qw}Y{U@m`d|$mtW6`?TiQ;>{$LLLe`SHg6jN7+8E8nXhT9(;yEO+b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||}1E{ zTLuEH`=_Qz3Z*s7{MYd1N?Du3Wk0^Z|BuhBdMW=Pgx%Wg#0?hjR|mJMmE=cxzJI%~ zR(tkYHbKS*PoJ``HGTbc*5i*I*JeE}I%&Yekg?WMhA$=ZSk>ON{r8i%ToZ9^{4Tdt zgyEd!G7A|#h9eT4hH9Js*6}x7idww&SX6h%gj7jGH-$9Sr3Co@s z@N{roe?3(qIV*8vgn*OBRo{GdCDU2~!8KbMzSQ=w-nMb&{Kdt5OP{pGYP!Z=Ka*x0 z5*nJU@1?qN&-VnK+p&tv4^Mv)Gn-*bPzT56n>jZ6V%+!Ii~E+<_1s=RHRP(czx}#P zS3oALEmb=4xklvQyLWvy=O|Fhb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||Bv zEB`I6yZZk7+#s%oj}<)~7hZpj(3{@D(ca!Jk<1_Vy&SRA@Jl$<81Xe{k`Eb&~1;o7YYFRB@QFDoeJY>!sD zZ*ok)RdDy+zD+t8qu4|0A~ju?Up^=y%;#Df%bsy9%4{}o_a9|J&9vLC6^!dxdAB4V zpM9{$=KRUebHY})TG`r`>IZI#%H`wxw)6MTuF2o)Ev&4#LZ$?rNi*JZZO!#;hDCYX zrCq!yv1If1_xIQA3j6b`*6rsn_P1r$7d})i$@B^heX)11?Ijc5MWU_;jpQe!N{Vmy zf8u{Xa&1_~+K)}$9y6}rOI|ACrTOjq_nkX*RvdeN=l=c6|ErEC-CM5F6Hp0-(A zPEJlDrZ3{Txs1F#JD2Aq0aZ^S1yNT=%YQwAQk^p0a~bz0ZvD}=PwMl-H~N*KiEEeY zoK6>K*mCViVNX!k_Uqa%DmR|ZS)8fmc3D%YDM+g(Z}(lbPjyw*&p!YBzf?`*eRE2W zqVMGoTT>(L(idh*ZM&T-kvEIY|E$De@8z?W9b6o@{<@1@ZrzRLXRoJiUU>OsOZMV5A%wh$-SPtEFUv4Ffe$!`njxgN@xNA1!g7^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_2_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_2_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..f469c0b4626f55e2d6ab51d97a61e107424a7d47 GIT binary patch literal 678 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||DHQ39T=F3N5_vjmoExE$qwu-*JvtF>8?XY35S{A&5!hc+<}Y#-{V8yEju zKk;EfM+bw!OrL;Iwr0lFSGht{>+9vSbs1KjDzQ@a4Q6X*Tzs*^B~-HixW#jWV+;Y; zP4CY3Th7oTz@d2LyxU?y2Di|_&`mndE*_Vs2rx06+i7v*D#M=dE3|IEowh_fD%*2X z%kA6Ivz8r{5DqLotaRwzJH2bSegqbkmy0j7e10RxOy~4=MaAQJ@{YS&E->@|HTm!; zM=v!pXqxKYIDShjt4E4maqG`NK3*O3w?=5*zJI#x?CcY}It=EYH$1i>ZvFefxpU^Y zT(sH|8d_LWb7uYf^M@usw_kGqy}Q(1CBcQc(Pz$`{;99&l}gA)_?fngF(=VO+6~7H*u_7r8Vp1?}VcZJQFIj59X|x9^brk#);YG^-FT1 z=MQc~LUC!~9o+g4|eiu*?M&IW|KsHknf|9)~wU0GqQj@bY9nvi|g zD%rY~^NwFJ^DVCDzE{2Nc5cqMdzS+@U;A`H^L_1^GgW)tCaZLE?D>9iS>DIA&5GxX kU+p?pE&upl<_CV|hb0m}%!)2EFfcH9y85}Sb4q9e0IF{;e*gdg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_3.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_3.png new file mode 100644 index 0000000000000000000000000000000000000000..31f45408f32db1421754d5388973c2271b964a1a GIT binary patch literal 619 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||{K6J;R>Mhu2?Ra$?Cx`Hu8SB0vAzE4f-N4@jRcxA=w1T#qKrb9-)R7^;+Q+&y9W z^5sfO414zNOG;Z4rp?#RoObN+VP;KLhBH0uUT4f|yP9>hYOmT1Nqv3&CvyTr8TyVZ zZ{4+ydBGGX%~q~$aqAfaj1Qm5xGg5QFjLA)li|sn<^5aPAH16(dDuW8%Xn$as-nGd z$4}sS@4E5AZOj|NVZGk}YABVM5obG?0A!(U@N48wO<-p&+whT&#>h`DG%@^Kw z`z`yC!w(O9d>`K7z|opH*4**?MacD|U0!{r5;U}3p1sHymnZx`jvM}CD@kA0)! zh3|hWxZj;K;JN&KSA6e}>gB71SDpGll~6W3_A>1s aqxA&up2d=HH!?6VFnGH9xvXb{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||&|Z6TpYtM;aCzA12~XZm#UAg>i#496c& zth}|2RpGhMxt$Yo&7>KwoG~zdwad+A#j373#tfQEKNZ|#++m$|%z&q*QZm^kbZ6Xp z;ZL)r%H3T8LX&!CNE#k<5;<1*M?v?w&;9Q+BsEp<$d;?O9JqT|mO<&z!-9m35dvkq z@3J3T_uArL?U^12jt>2k8=Ve!w!e?Q`TqL~t?r{t4F$!;!9L!aiD@kRKK=OI|74D# z^~XPde766em_BKWkniOJtGOJjuXYv6NVYKwDn9SItf;glw|nN^x5tH2&qB{_52;@okxRXy_4%!t#)>vKK;D?OGS9H~q!WntvBcjhPc9+8&+Mv0nOR zf1~1s?|;9D-!F=vj~6Q8y0VTH}KH~Q1P cKR%GZk{Gs%_w9}c3=9kmp00i_>zopr07(rN)Bpeg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_4.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_4.png new file mode 100644 index 0000000000000000000000000000000000000000..29a30021d5dfaa5b6abdabfe4b5793e5adf08e29 GIT binary patch literal 649 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||!b$(umX^3LikupR=42 zRPjETZ^4vBxzSD>8cS!Ke{S*ol9Dlxvz4z)hoO>E##+g?#%;NotMY&BbAHNwufBHC zy6jiG)Xo=|godi?=>M2od_>~%&&X*DYo7eNtb9uLLe%0ZO6NZZ->wH1omU<37uS+Y%SN|NTEg&U3ck@|qpi49nm8zcxK4;l#0=aq+R_ z$9dbmTVmtlm^MVMy$~hrlwdad@A9^f_cq^uZ+Ps232*ybekM_~xWcc08y9I*tb1>m zt!DdvW_CIMo7lgvS`8k*dh5UF#}VF!t=~)@%sJq3cz(RO zhMLCGxGR;a2Epu1B0ilpUXO@ GgeCyDLL{jG literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_4_overlay.png b/src/main/resources/assets/ebwizardry/textures/blocks/runestone_sorcery_4_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..8f4bc9481b009ff1d676f69c44dd13b3c3d4b5c6 GIT binary patch literal 653 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|7&0&>b{;;& zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||&=PWS(FPUs3*&C04>+BEmZSGg*|JqKdey3IQL z{r~2o%F50Th7TV;G_2Ybwf4r_vK3mVp9(#fVOZrAdp#xcSk~4>tF+dv+7!3`$Kszs}wRQ7dDNR>2nW7zY3Wx*-N7J-1!w!{N|p3h~J zn!elZWprs-_nJddK}ko9drooY1li+;YnQD$A`uwcW7zZ9<9g|q+4&dw*_Xt8`uBRT ziLdizlPRg4H*?I~r>WOHmoYrHrEXekNB^AqUBZR7$0S@@HtF=2b{}n;zHn7$Y3R}F z{_X#F?Efp#>~Tn^i|M^>nb~Z^KIOv(dx9#3a?NIce7H*7!f${4`i<9woGi>{*v#W9 z-yJLT=F1n6hTFHJdkk9yW}JV%{?3Mb)!%;GUW>Z5ZR!1g9gVz|Hjm%@?hOe&np`Zq zwx>gX=Z?AwyVePJo&5Y~=GAJq?MUHoO8@0-h8Z=F1(bK2loLEY6;7gzP2O>>T%RcN z=Pcu_M4dd^%PnLAvfr-eRr|mESnd5_5!T$_XYPNujlItJL4HGjl;ERR%N8;)Ffe$! L`njxgN@xNAdzmY@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_0.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_0.png new file mode 100644 index 0000000000000000000000000000000000000000..d64a4336a576a543076711f246c3cd7c22b9a7da GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lVATwT3C4TmxM$@vFfcH9 My85}Sb4q9e0L4X(c>n+a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_1.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_1.png new file mode 100644 index 0000000000000000000000000000000000000000..a646ebc67eb3b8cfd7974e2fb562f910cb6bb5d7 GIT binary patch literal 506 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l*X%;UCY+n`;+p_Hb}@b#%BD7G!0-Q2xUEi-paUo%QM!8Ivs`0!mZL)-Qi}X{xuc zuI}8Iw$IDYeg1c@@&AwACwzW02Gkqx**^8KL0!cKlmGq9>_?lF{g3Q9*Y@JbhMJcz zSH7R%awpRJDD$>3My8GY3|_yxLss(&MR9X{h%;xr@Hx{`N1SEr%aRlCT2!p$wzV6* zc8qp++dHM~Gt-24PR;`^TcS_>{;WIsPTGx!E7tSgs`UAM+iG`WV|%;R(T#^5yS`qc ztn8S%CsJES~E3f%wuQp^E>Z(WRKBiD+RZ;=b0q6CLZiy`oJ0Qo_l`Ki;O^-g5Z=fq&cMKA=IP=XVsZNHr1RdF6J?IapTBOoJi6G^(bIX( z3ZH1_=Q3$VSB`BGbV@7};OgO1RFYLWl(FEs-;^-m*M5ZA%Q#+^?tN8UL?Q zcJxnGHoF(%ctQLlw?q7UyVc^avNjt`%$w|RJNJ*rEzXi1x&^V`d<|>oM=~r*-?M4Y ztdQNs(}icwwF*`HuuW>m-7wEwxio$C4WXKB?9v50v)A0ba&*QEt26g2o5VPOt6G(L z1f9(KK_ssp+gvX!Fnjg+cndH~~;O{BxEE~Sprbo`3N8e)Wt7K8IyQ#zc zmywaDDZ^`dZ@XE+vyL!rpuWS914t+^XR$f|GlbfJAoWi<% zK^wBKU0)~ZZR{Sr{icqJT7!fhkCc8- z(Uwg|R|+#(u%-uJTmSv-$48|{3*Y@yKX3W`=ltiE3_fy|ag0LxtUu~~dU#h#^5>mO zz0^F*$L`$D-RD?sxgnbISF$5(L4HGQQjV6Km)n$}sdwhG9t~iO$k+JUs>=9bx6GUzkr~Xj zQS1L6^f&jOG}j|@>ua-O`M+wlwQpaQm0#X_{n@Rjw{>f*L_>_HEi&D<{k)n$!Mw}i z`vvPo{r1fc-R}M3rRGM}3)hmq-@7fjRmYxmR-yC*}l#_`a>+c>u^wss`^Xn@6E%+O@$9nL(i#|9t zee;Ie-ZRA?Z$j3;b$Xw}eBg0;@w-cF7;e~g$E?$sy6NalZeyl|8;>5n z+b(u9`JAmtw|3BalLGs{4U^ydytu~K?pahYzw5f7z44SIJ?(P86aL)LTYJ;&*x%ec z(XmUmt2?RgICXt`xQZbEtHb+WZ~F7vYV!K_t5p|{+FwmwW3|V~rfH&F=gQrg4>s~V z+jpw_{PUv~ul)Zkeaj$YGeJ${*23iWL$}sM#{9L>pIgTq*la9cqjv1h)}|}7y8d1d zJO2N$XO8y<>pJ!alV|EXybtlG7#Ji=Tq8=H^K)}k^GX<; zi&7IyQd1PlGfOfQ+&z5*!W;R-85o$QJzX3_EKY|`j?I`|Dsrs;zq$O`@XaQ{IoZh( zoB1}a<@WAbI4xlFq^(;^m=~TqsOQq&(POkn!)T9;QQ5KT^5woTbdU&vT0BF&{Y6Y0D%~drj9SEm@sOh_jj{ z!J;sNq0jG&ht9LitCf?^C}#ku$tHZ`l|A z7G*ul@^3pXYJ5yv@3VK-4|yvG6QMha&x9JDq&P6#v$NINI5&p-u?+3ZmHs2Ho-g&IzPi0=+o>jACU)RixS{9Z6>D`qT z3>j~$wO8!wT)L)kUcv?aYi*oAYt0$NcF*LV9?Z2M@v`Ug;#DzMEbCv+I=En=&zif} zB<)lGIO}a+mG#u>*>X9fzsF|0DU$L@Ixj1bYT7qnrbCdk`hW1F7b_b=qaFG&XtK5O`kn8 zK9#n4k?l|OZ*TJ$`s5{#y?&dRvMGF4=-ivHC9mdP4_H+A@2|Gk?B9B;SNSgdm>|xe z&vz{2MOWKrJBIl&zu8iHH!baqd&9I~W%ifv-7rwDekyo!SVPIfj@O1TaS?83{ F1OQiOv}gbT literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_5.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_5.png new file mode 100644 index 0000000000000000000000000000000000000000..fafffc974afff76bd92f13be14e4525dbf84d855 GIT binary patch literal 968 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lrnx>v+U|^6eag8W(&d<$F%`0JW zE=o--Nlj5G&n(GMaQE~L2yf&QXJBA9@N{tuu{iBJ+27|jtH^Qt_t)*WOetL&%+ezI zGUAfqnt<%)C5b&EGg<_F3$n@r#UCHk>1IzB>+g;%`>|QJWZpFzAen-x_G%cBA z#M#^`7+{{7mwY1Q_v`ihpD&dD)u(^|d+q!uzvUR1kIxHk_|aYWw7&F7L_~5fBkPNI zSy$&BWP2;Q;UWi!9ID}vrLl%Ve%^~~M;_0!k+k|# zwfElK^5WXMNQR*IEmu>ufA<(nHV$TC_Wki%e$lp~^oyKQA)bkR`uu9&@FX1mPKzjWq~?@K>66EWW;8^aa(T93X<_w@YJNIty!(byhTRX*CRAmfb4-HC^)*)4ZUb%f{S~G|K~v75uICD!x3L$#CbX)279)jC%F< zd|RcL#Bsm;F;&x$$2{%algpR$S8b8!&HNe6r?zj0s{H&n*DuPe74Cku^2YqsPp3^g zk2Yn^V%3`6{6p@_q@MSwKW-N;tG_3}aQN5Z<{hoqUewuE*SQ!K-+p92M}Cpl|9kk*p;a?(GM!6*_wi!2d&&0oE|V%&Mjnmj zvcEb{;hNZ=_d>t>+D+qilK$*$w|?DyCEWc4+qIo#nW2wz8TbA_kW!f%&2}#%)f05T-R;=lGN$f z9j-h$lYThKC+4ijy|AwO_iPWQ_OZBnYy7&#@FVMu^@ZChv1Zr8cp0{(Ubu9F>A-&G YS6*+fowS<6z`(%Z>FVdQ&MBb@0E@@EumAu6 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_6.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_6.png new file mode 100644 index 0000000000000000000000000000000000000000..f4b8765c07df49b3f2d690e6b12db382ea0e29c8 GIT binary patch literal 987 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lL-blR`Q6e*JhdOY zW$a}yTsb7wSuK6(^4(Qp->s(jm<4A(`pC;@;Iyz|8Mi>@=d9xk4TOb_H|^ae+)%U7 zW$9)A?}Ghof8%<*4o<4?dt1LiH)g5$x%oj1yY6RS*|+`AQznZ~r|f$7?(|oFxPZxp zFI>|hM_~bj{G7KJzp2|+T9te;oo_d1V{v_2AVX3<`<1YuZ_>D=jWaKZ@lIY+_FBPfODFSj%skkTGJ~sIz_*aXOQPZrd21-+vj}a9p(D=c^58{{4yArEGZVvmQfLvaHm8bH~=>j17YG=ZLy5?cLRE zDb&g9dFCkNhH$Qn=fqege&zAJGVj>?>iWjn!buWkpKjXBkEw88`glpac6s!UuRqs+ zy127W_Gg{U?z8S!8+jhbuk)~YbG2rlL+NJm>s7WFPsFk9msI}uSa{+Ydzp^d3|`p_ z-r;SkmV0&IIY;V*Wk)XanfLF7_nn>Fbe6sniSPBDtUcw&kC^#P64u|+CpNXNe6oju zrMYgaxbBPhyBRiEu8rAcrN-dee)7qaH7S?W#Mk#s-{)9N!gZ4V?CidJMP}bE1xf!dYx8NU zm!4g8e_bgyecRI`uY0rBg>If1d*saFjpy`w=B=9$<;`Yx`N6dcCmBBLW5)c2c~_YW zUS;sdy_c(Em)bhTSaRpg39^37fz93X`ML^UmjxB6F8xvdlR5rf&hiW{*Xvvi*WLHC r);b&uJLGenF~Ep7N-CP+hxqwpQ7zWjofa@KFfe$!`njxgN@xNAfz-6D literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_7.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_lower_7.png new file mode 100644 index 0000000000000000000000000000000000000000..9c4a5ef000bf6d6016ee86e192a63a4ff0847bb0 GIT binary patch literal 995 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lbne*J^L5j|pYM5fw0m% z-__`UnWEo9>n-8>F?+N+cdn_}{prS=Z?ZFsT;15?pFCT-Bx0-PzFD&t2Wty8rX*SEUCm<-Z2m0Y-&y$9&53JT(7)|%(c8r< zQy27a(wt&j&bY(or|t{eB0g^8%Nz}mdKI;Vst E04jpdy8r+H literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_0.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_0.png new file mode 100644 index 0000000000000000000000000000000000000000..9a25c6a5831a8ea6f624c4883ffc4b81ddd99fe4 GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>llllRd zT31)}Us6IsqNkU|;7QjdnTI*Pr7euEk@I*!fT6RVZTI_k{l^&?7#KWV{an^LB{Ts5 Dj1W91 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_4.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_4.png new file mode 100644 index 0000000000000000000000000000000000000000..7b494a8d752c371b1fb524f034eecd919599b191 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lgTe~DWM4f4=#bR literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_5.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_5.png new file mode 100644 index 0000000000000000000000000000000000000000..a07c1912ea570ee1caa956add2938e558c390837 GIT binary patch literal 580 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lO?#2CKeZA;j zZmQ1ZaL?S+@efw_Ts&iG(BdShd}NP+Wb7C5lAEC};ick^E*&L-7x%nabcCBzhoj3- zK+GwecWdt3imTE2w_8iz?yUMzcmC&`&vTgDKgMq?v5mX^;(fNA!IHOg&K>f3)Nf!V zJ?UWMu~{c&=ekWzi?m{xcmGhgdt~Tyd$p|$|J3xiiyx11R;mZlxm+;<`P{hqm;d*U{{ioSAhyV~(H`59~S*M0sN%-Hbb z?1YGEjyg%F=l(vQt)KoQ%7fvJw&Kfo1~KtcGx@qwcbf7$)L#;5_&hgV^|Qrl2A=tg zwm)CQz3zSH3wP!a#SWzt5HQgkG9RP=8s>wfAaMCb%DIk_!yj5Hdr+D^3R{T zO6K9s$?LfkY}13YPVBa7J#4l8S@NgP(-ZtzUH1Ji{xq?3fs1n6lIM?^3MvhCoL5d} zx*(k^-mosunJp;oD_@dl@E%tCr<>Y$^T%m5+?lNuwb-rd+_duS*;z%ew!9HL@cpp` g!^>80rVaczLn_z2nZ4%+0|Nttr>mdKI;Vst0P#%tV*mgE literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_6.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_6.png new file mode 100644 index 0000000000000000000000000000000000000000..737c2a6685c53b6a0b02ec9d020cc1a5a38dbbe7 GIT binary patch literal 699 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l`Ki;O^-g5Z=fq&cMK=?CIhdVsU!yB!3T)LXqS4#(rI@lWzve`h@$g zDY=tVCZ+BzyFK@Y?*9wZmS`SiQxe*wBWG3G<0ot7aXl|~k+VQa#|rOOc0rw27Y_2h za$Fb?aJfcSEp4WX#*6Z*n)~0s|E;_K_~8GF?Zx8%I_(W-@w`%E*pm8e-!T^ zwV5Yva(|j;ruw=2^_{){Lv9Au>=M-%Kkp?Vq@l;Q_z%bH?%#|V@;#>xZ8>)3jmUfZ zHCnlTi!<0+4qtG+{NUV^$xeUnJ=}F*YxV{=hC8QClgwT(oG5hoqO5lqe3s(z2lVcUP5yy})srM$<@SQb2wIyhxoMDr5%RVu|-*>B(F&^*t%^X5k* zhD+f!e(CY0iJg~?=ZmCPi}%adhA}+)+LrS!n#1+)t|p%zwbaM$5BNg6b;4WHJyRAX z&A+5-|0@3G(T{8|-&pG~^xaiqQ1^{J_a(G-(#mbA9-EeXb%pb9+Pbvp{lQ|^gm*{F zw{Z3T>Cn!zopr03Aaw AM*si- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_7.png b/src/main/resources/assets/ebwizardry/textures/blocks/thorns_upper_7.png new file mode 100644 index 0000000000000000000000000000000000000000..06172a8397e887ee7a4b3514ec006413006f12af GIT binary patch literal 804 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>l-z0bko$+X(zuT^#&-{tnx zpKsn=-pU!pvps+LtGO^&*cdJB>SpzgR+IexykldBzt-!zjfZomy>eSD%Oz!*!CLV6 zoAcD?*UFB}dp_ySTJeUA-JyCsDyn5SCLXr6dmO@h;PM?6zvYo!F3L44q8R3!iwaDY zO8@=H$kzD$)YtqWVVMj+_K0=u_NAVt+CHurs=81D^L0#uwHfNP*obK&n$Xf@bg$L>jGZhY;dn}x} zbQ<^0^6y)jKA7!@So6bS&27bp0h<|W{wDr8uwGTM=8)c}otHR1_MfgPeJdBMzj~U^=2e%&@*t)@hM|r*c+yAquQwws7#J8BJYD@< J);T3K0RYVFVetR} literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_0.png b/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_0.png new file mode 100644 index 0000000000000000000000000000000000000000..489e93bc8f000bb1785b65a0999245a41fdfe450 GIT binary patch literal 1860 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-{#1oTlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{9=+|c2G5^#(akJJf_2yp<``SQcZoz)6V_5yszD2?)v?` z>=Ny*f!YhZ)O0_-y`?2(eZkRvi`@O(C6N-f&1Q$1-)|I7|IT#p=I#Xb$6H>PYqXSH zJ{W5-t8CNv8>KCJYt~M^&$ecI+`IX_yQBEmZS8rpsLKlT{l1VJp{^Y~T1zYsDQ;!?z1p z*}Sl1kqESEHs#%H_1&rV?uF~8k3{@bsL*mUIMmbcen;~E`C_(JTc_$xd?Kv<#(OK% z5i_acx6*M6Ew7GTDXaOdylvM+>5Wo6xA=^e4{BWIn5eTi%e#D@>7O+wPJKn{^=B9w zII^R2+Ds%S^ledfzoh-Nvq8Cee#czx+z=+_l(kkKAq9)KGFz^>b!*1smA|!Cw@F@N zQd(1HVRna4;Dph!MRj`;uLNwlC6&0g^jh?`gKo>`7GAS_9(#Gki>>DOs-Evnm#;}V z+oo&%?Tm~Co2ZG(88-1f95PNFg57Q{eKTYq3ML16s!z@-I;rlbc(mu!NwwQ=Hl3g2 z+}CdPrSWn7j>Fx}{RKyySeJ(QY&H3 zdKw*rJ#Kobm+L><_epKdPvv`8go_siem9>X+`H@K9rb+kHL@G;YwQxf;+J?hZ@}1Q^6LzBe;l`_}Dq8(-(yAKc zwL8D7rpn%se7pTl*qYk)$s*}3RIz0WJcjS{D^X=->EWfYucxJff>*778Hw9;(`?JpG-Z5e02h%G~ z?MW&2JbOhuefg%$3;PqxPV42C8h=bMcI{!-T`3Ubmw7MvUfGXoC%w8o8ghr?J_=~R z^u6#|bL&q>t?5r@3W+^`wCGp*3NI0~tGgE%PMr z^o+!P8e;Ed>P0T|KA*omC)(x2^4A~vqd%6+)puNYeUa-RN>`yV0eEGIhe&^^!xD?lI@MzT0Tso!wsb{tD}SCExk>2u_=j zntX6mg?g*8qk7ThH8Udh}e&W-s6Vc2R}{lYQ??+%VpuQ@Xcr zZlu8v9)_8|W^((c?en{->*%VS;Ip8efq`#V6w`slbN4YE(9Een$<1=AZ&xHU1M_dQ zJ$vdMK4dJ{U$bN7q08FZc|z%*qzh7itmD;x&vGWkqWQF9(k~xo&Btn=AFlpuJN0IY z@`dDdu}x~{o-i2fnPV|oID~~EKKEDf)Ln6#A3ZyFv3%3D#OMy@zYj}qh%FLi-29;K z;kt?^UsoMXm8{(RE9vXJgG((8n2xRNo`3T4mld;P-<(+#Tqb=YByi_@ul-BZH=kVg zKBVBe3;&Z$Ev;^kNsM8441UD4=Q=J}Bfri;?YsAiFUAT|9c!JeD>l8n?HKO;aQOnE zg-!>2E^s{YyQ#}?r(t#B%pIK;^fW{+ ze-n1jcy><8{{^d470gZ^IseZ}lRsX*bhBBW5qraf6|?7R$XD*2)bl_0&e3x^ZU=Vo k-Bv18n|{Gl>OVu*H`V;IWi#I~FfcH9y85}Sb4q9e0DOLa0RR91 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_1.png b/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_1.png new file mode 100644 index 0000000000000000000000000000000000000000..de7dc96abefaccc995b13a4cb11819d4ce449894 GIT binary patch literal 1876 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 Ib4q9e0BP5FqyPW_ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_3.png b/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_3.png new file mode 100644 index 0000000000000000000000000000000000000000..5b2701ae0b87b74f31743b75590f1b46c9ff1c16 GIT binary patch literal 1879 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 S@hI|kJ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_5.png b/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_5.png new file mode 100644 index 0000000000000000000000000000000000000000..2a0cd2ac054f792c7f66d5561ae01c8c1342b9cf GIT binary patch literal 1878 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-epZD;v3J=J=W>OO7Z-A_gtyV8%PygX@?QgJHt?&=-aRI6{D`(>Uu!(z(% z?`8}=j}%PS?2s~&y1%d5u;YNsWCOOE@9MEiGopL`{${i;_0fMIyP3PpN_S^vyHnf9VbnD&Ew~gLbFFrqSiOqJ6T3uXzvP$9U)mvBgO*L$O#HMjJ;#nc< zAL}!RcPQx{6f<_vPbfY-Rn#>p;nso8%xqiKAD@`accziUg6oH8$DH1$ygU<%V?0a?l6%-K58XAt#v--rO+{B=ltYWL z+;O*Gj7*W&te*I9Xp-?dXR&%t@jX^`yWTKGws*s6ZSHr?-{D|6e+gwZwrIJ_^0nxZReC~?ZsW%bk`7MA&waQfPtV6JI|OdDYYC z7~L7WxOumDaeQU)xqm|We~!#~b>*-8nU#Kblip3&K`fKk+ zJM#Xs*c^f-kHfSegR@`T}xBbm5wK34aIxd^J=sAFWO(QO)WsuKh|fWnw#*htqWxi9JsUhh>rTliE1D1Y_Ih9y!E+o z@}O^>hJk=T&w?o4oqQtixBpZKb9buWzAfcu)4Z5^U^=s|#h6tw$NTH|yeq4p9tmczuy|0Un`1A2 zirspzY;AP?s*d?HzlE`io_dge|6;0H)Pf_cRoCC!vpp=AZ-M%Rip~w9_JzxIKbGbn zT)pMn{N=`4W);1&u6eEddFNH-w#EOrt1W&nE|jP$*s{MQVo%_nLz}{lgME2z_wGMj zv*pNj#@ZG8C%es_S|9ww=kfg4=5^Iug|6=R&b_U5`MIzK0|NtFlDE4HLq9_t!%_E} zD|a$5FmM)lL>4nJa0`PlBg3pY5)2Fs>?NMQuI!K5xdb&e-u5xBV_;ys=jq}YVsW}P zcw^r!2Z7qnH`cH)NmowX_(M4B)P&VRm*NW-`Mbu%&hMJ1?~oVl_Q%zWB`haVo+)$V zhb0ceKQCy`OnYVm)RNeii9{UxWL$ON7tM|Aae2)i?emFAD91RaxDF3HJkAOuZ8&A zq|behDZYmeyj!q2ovmyk?<1+wb4QM^iCq)z5Pm@a)IK|-G8S0|yGx!vwG0{O1cT#e zXsmzbtCTIoAaU!UQ&mQ@1jDAXjd@IMW*wcG3=DNoeM4W)+s5;Tp`o+?Qt({;qm616 zt3EG%vx2ommSIA#@yFRE`#&w~`K83Cu_7VmY*)j_xb)2nWp!r!@Hi{;W2(9Colorl z0^_dEp7JhJ`@Pl{N1IJ)rR9tFF*NM_RV>-J#?$TEniO@GtC?QKF4>!1yo{MQF>ee_ zS-s%XJQl-EY9CkKd%`v+HR8sJM@OznmFBJccV}WE+j91~`%gEjguL-C-6s;wdO`56 z>8qF-0tWjuetQMX6}zCiY~P*x|9gK|zMCff>+4Tx^Wbm$yViJqvzk3~wf*^9M}Or{ zIeT@!@yFRIdxBrDf3&@cD`>91v-A-mE6>OBYcmBVTAs?d$-uzC;OXk;vd$@?2>_6L Bg*^ZO literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_6.png b/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_6.png new file mode 100644 index 0000000000000000000000000000000000000000..d6133cb375125a096ca832c21b48a5644fc73404 GIT binary patch literal 1889 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-8LC1eN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kKXoJgXhn6tu)S#?x3eLS*Fx~#>X~oXT@2ryL`Ah3RTz+E{DSpKLy=a};trfy*i;m^@tjXDbo_(vDf6=bEj1C?*W4YRy zzc`D&M+m%`B7eS!tMb;w%#6r+Y`&k@7|yIR;+3?0Vl!X!TdcB#K z;c(sxU4loeiO z{4$5dZOh4ovnFxtB6j@ly&Ip__l=J9@+vuTOju40Sjj1DaK z`3`PiWInaI@J%G^T4v({kq?svcAACBCp65xtRBp2eyn1G@~)r9W*vwPx3)c!p{sC6 zvVYUWFb9RxQSE;?!zMVNluSQq`8>AZ(IW4A6|d)hxBGEzagf15Ht`w`M<*W7o`}Ln zsvRCvL`qFE67_ybXn6G)s#^FO%-vw+sJzr!{@I3h>py~gmX9VHT~fdOX482^?>@`9 zzf9Cm{r{4_AoyIxvO}yZLvjj_P7hdeWRh0V+F4nvSMO`nGQC!^(JZnytv7zg?{iZA z*QAoSy>4aC7HHq#Q;@B`u8{56mQ({dDQ1t1yB5KRuDv=I^Vr9=cTs`Vnuo#+MSgib zjgHX~yHAOi^FQ17$?e>~4)edAmRVQ+@;+M;Xg;(0`P;Uw#$WZjUb1Y}%9)`ReDQ`r z-l6?D+EyN~`1i|heLY!uhO=jul2@eY=bwKszs^^F%e3y=#?k{Ee~M>!n;yQ$*!K0q zBAx@1yDf4(lM7W&20gphbyrzxRaSpadC8ZRQ5TI)7R!-?QT4y7JyqmNef77FP;m9tt)aC9}VHbn`o_o?GCTtjEW`Z`yEFVEgr5`ic)M zMNIXTHw8?7R37oEBY5_V#qxnqC#icZDKk3sVe+Gudasx6_xrgeUbyL>0pr^b&jMVc z_so|1>+(OkOyJR-Y55;^#M(^zS?2P}NM?~`&b@vF{PYjFPt6F|FHbprEO>Sy?b!$*0G;mp3smXoo_R(?brWYSkF=^HLNf7Zpe zGu6!t&mM?kP*CP)Q+l3r{L!;_x#@*Wr+tzekLYZ#edeuQ{m!oBexF#!ff(J@b57U# z&;H9{duFZ74US7i`Ps}lZ};c7pE?y6`K9q`#bx>Re%7ZL(x3L`2fs*6*U`Cm`lxH4Vm>=aw~ldEe=ukx$Zo$}gs`j~v5?eCX&1NS`t5v}F(>#bFG?k)`d z3~>xc-EXek$-uzCS>O>_%)r1c48n{Iv*v)5v6p!Iy0SlJ=MvP?Ie2bb2?GP;BTpB{ z5R22LlMVA9IS91wk9`v@+aYnNALfaNwWrK+`E9d@Bpv}{HH{%z`*_GwCe69?02 zi?9h|+ViyEsTD0snYHoS;_dnOsv!*9bc% zj<1^Br@vaWInUQ)z4SWJwc?KYdluae9M?v9q3Mtt+`JoLI~ zcY8CdY{Rn{ZmYqWq+2Ket9XRVEaAo)^EFc%qfWcSi z`R_lq-dfe*xVy}p^{GqGlT$8VEh6jlH@p=q`SSn7a&24twxd=T+81@i@3qox^c9@e zzw1`?l*wAN_8sa@i%IzWgfIN%PIKd=M|)3;*UFzaEtz#}Kew%d{VuQK)eH;_44$rj JF6*2UngEZbkCgxb literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_7.png b/src/main/resources/assets/ebwizardry/textures/entity/arcane_lock_7.png new file mode 100644 index 0000000000000000000000000000000000000000..a2a2234fa3caa93bd08a77facc4c0dd655595b8e GIT binary patch literal 1836 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-E?0#_lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{o_*=D2G5`Kn%_7$6a|hSlvwqQt@=-{T-lr>Cu@wi7A9?A zP~0W`aK^9q>(l-nJU+4Fv1*owVnj{Nr<186SI(W+Ir*zFp8wklo115EK1fKKVk7Sy z``7r*CkcVSoAS?>37`J7`1Hkxm6lKJHan+&z5KM}?v~3{W|_UG|81J{^|3|FoVoGy zYgr_AA2@Mt$EhP?-!G&mx*X^?<);%(UupnrGiU~kAB>s={`M1a>JZu_eLJJ)B|fG61Lqg*~n?T08rFCMzi;9QHR29pD4~|Y8hF@f+D!a?8wn;2LCbD@`l_;-N zsA;C3o?+08B@-5T&I&puIXP{|If=O!m7kx@-Sg9T+lHgQ+qXPr`Y95>q(!KETF9q& zW%oAz{l39{^XqxvVpckNT@7Ek@YpKTt9KS`J$BYSbK%itx?5{DZHuT)>y4Z7`<#^S zHLK*hFWvmt68b(CINHwjc+S&f>7QUz#-@;Q-Ey{U;r zWBf_a#glil7spo`Kl+O( zzcinT=Bte#CB2r)%4_&@?SJy-pC?W){lA1E{etQpZGGcKZ|*YA@GV~0m&R({u=OnC zyvK=0PhYW~^-Oq9VU+U;lfBVz)*9YO64%puv)E*P+wY=QRi36N2|MM2zg&`;8Yjp2 zbJg{uvR(zj8qv4D+Iq>{%=4Rg`P~H3zK11->l6R7X0klnaDVxvU$gJ&oL&7;@m5WN z1OM4++^50|YG*aM1Wj;$G^?vF;<5RXGZmWqipypg$BF1G#xm}k_UzCPL+?x64*wcw z@4haw-lRx>mh{J%h>x3RdTtN(e8#!4*syB(NAbegrwl#&R(^GV`YC-zyn>U-d(wOM91o!VGnhb+gajQ(rVW za_5^lXRg*veC$>|!|{jEK8~ChSI$_Tzw=-5c8#A=yN_@Dg+&Kn1?}Mf<#_S>-%o3V zKQkZvdxZaATCM26*og9%`O2SJ{pTIm_}4T?;MA$om%7(yE@!^=Zn5$|$Cvz1KeJ2x z{krV$-;2*r*x;_GS9E1A z0|NtFlDE4HLq9_t!%_E}D|a$5FmM)lL>4nJa0`PlBg3pY5)2Fs>?NMQuI!K5xdgRj zo{KNL!N9m@ZP>#4g&wu&Znu)=aa7VZ>X5OTGM$&(5~ej>-N8La;+D& z^%uApYMM|zr4QvU4KVl|F-Xc7WU`AE!}Oy z!120$`GJ?>Y-QDR&poo5WAsswf$f@(WX*(X7STJ5-;Z2TT{e%Mp|$>=n1%l@vw6%8 z&&2JYvNE|<&ppeaQ1I(%?DEO=0$*}%$_s9`+wHU5aV8}2(2?cZ1tyC#zB%MQNfmwZK487BNby3F!INMI5B9p(cU zW^KLoy5!jdBZeJJ;x9AR<2#wpJ_J#2OE+=zGq@DCX)onp8)>{jn7w1=?~Lm6Tv~Q7 z-k7dC{8DsBfHAvs_O;xpw@o*s?Y#c-&1KeLS5CvPA|X0j?xhyz{w66)78FPd%U|}} zr<8DoXS#aKY}Jrik^;O(!WO=5{dzd~;r#7~`W|4!YU8K=9#_Ff}{ZQj2Bx z-&@Ru=eI-)d#-%bw1CM{K4SBfzlZGeZ8v%<{Cj`>@6~qx z>bYkZS;;UTNT0IUO2#-wQ!@R7;~%wUdACl6FY6NGoV(;B|L$11_@?hZZVU_z44$rj JF6*2UngF(TdrANR literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/combustion_rune.png b/src/main/resources/assets/ebwizardry/textures/entity/combustion_rune.png new file mode 100644 index 0000000000000000000000000000000000000000..01ff7e71a8fbb861009f16bb2cff34e90e6b5640 GIT binary patch literal 1512 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/containment_field_2.png b/src/main/resources/assets/ebwizardry/textures/entity/containment_field_2.png new file mode 100644 index 0000000000000000000000000000000000000000..03536e9b66461182e7fd52c6d60d4223d06bceb9 GIT binary patch literal 587 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RZq;uwy)-(0zq zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%+AGSYW2c6QHz0r@rI|1V~EA+(%`*$ zj~oR4rM+Pil1#pK#G_L9x+ece7Ln^qz5GR&I(=vRV&m9nW}4qr@}!_=djCWFP~ z9>q>1((qt&1uMh#*L@5MKR%bQFy{yq5_$T^$Ga<`_}*8ZnDy38 zJ8Y-#=I^+@+v3#HyR#fpMAw*~PcY*0Q+lfVc*6c|@4KFrhHXt}Sj59Ht6JgI6i(~O zJyUndei5(QWpRp8AtHa?`ZK+YWnB6h5-#84E)G1Wm{%{Rqiwr$)$~~o!gE$vy|hg- zdU$ls;ireU&NF+vcY?=C&I=z+N~lQ_UulN%(4S~zqmub1|)~x%#lAc zTWMEZ`4bFVdQ&MBb@0NREGLI3~& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/containment_field_3.png b/src/main/resources/assets/ebwizardry/textures/entity/containment_field_3.png new file mode 100644 index 0000000000000000000000000000000000000000..9245b9a5cb480051d2d7bacbc99300a4dec03b03 GIT binary patch literal 583 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RZq;uwy)-(0zq zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%+AGSW}tlf_ICyb#w(sKjv*GOOM`dj z-F6VDHC7Qg-l!qB$i<<4QB*2NU8CR<@27TC7oPHXeadxLh^FYacT6w*Szavh;hJ{$ zjUQLG*pvl6#w_I@zR7O>^7Z)q^E(2z-IgreJAZEd{OSA*%f#D#J8-706_=Rm# zMn~2B+ZH+s-&~&`n9`8Jut;(5zPrB}9^|fKXV?&Ez{Zfj^XId53S2v~mN7UeS;y@? zZ^dTDb!|CW4JTc-X(XSC4*c)|rq!m%v`f&*#h-U zfeJ2yGla_J+FSp9H@n)rp8x31U-QGCd%fWfKO3@iXQYWU|=ut^mS!_%+AGSZgzRIe=`FE<0(%U#}JFtrNMji z9ytj7OS>NQKtL^9x@U^{!m`S+c?zypT2-rrLrZeCzE?IcUi!>;!lQ24;}JhI%hX*Z zviYAblguvv^7gy&vfKCT>mJSC^!a6&z1`F2_n(V0G<2Wkozb80ebubT=gvLiox#uW zz-PwA-^b^kF`U@ANWw+4V;vJiK8XiaO(p$Y$u`?C$=`nR$YxNlWkd${(u6=UQgYpRy@4=*tQ9 z>A6B{Q*QVkm3$@3s#))b{4kBFA z3w1U&?cCzIh3i-1v*!6a&ucZM=BU*vrjG~>eWXe)>l?mz8>}m-YWU|=ut^mS!_%+AGSDb5&K6wJWDc*E1hF~s6@YtZh# zTLA*L#$^*X99px}EaH*>3eDzk+#OT$w10(kWKA^_%{?M6uzlsp=?Whs9<#FSK0DX5 z@fhP4uVs>_?X2c~UZ8)!uI`ZaZ!V7RoWzTuSMBK3Q+&+Ib!7VctV z$h@*!;Z=ymB9G1_151Ie&I}LUp5|ewnfC04?5~5Lzg2(bUKX|C&KE`oE%$rx(!<4n z=$u`+izDoOe?aVyY0}PH6s}I{F5-G*t-SpD_T{&`4|mBP*lpFR#IWN?qsAuh2&u2@ z&R>#YsJSF_>zl4Q8-w1dms5A@nujftU{L9+Icb`Us5<5PW~)2VhmJ|$oplN$>+Is$!R$cnXfzU{6A#xCiPYC zJ>O?7mHS1>_x;rDyo)>LF*wB77;HFy>CX1aos~?>ZY|w%VM|=E=gt=ml?fYXn%q_RG;zD`QnD3zG8OED_sR)^J> zU*A}kNp-w;5V={Nd1d#vdE51kfBkv9J#On8`^TG2_@~X@x1-{KtL55NI(l*rrTMbg t`{nmV-AgDsxJ%;aH0kJYWU|=ut^mS!_%+AGSC9=7;K#PHa@u{baV~EA+(#f`Y zw;cpp@1GIs&^fs2N4n4n-yM!7jiAle zdWY@?v>Bfjcv4XItUCYY^Y!-jA6#F&{t&n~gn#~g`*wDQWAgV8o!A}2^X}^B>@=r( zHf2$U7bfQvH)F-kjRj(`0HsED+P`}9Ka{r>-rhiA~X`QmZ{r0qNr#r)i z^~@hTZr^2ltC&3Z*iOGiq6{-G%)hy2aRMJh%=>HU1&b5-78x?kSbbVL?EHF37cPc| z6Zg_WuX(R_*uPWj_0r@cCQtbMzJ7QAoVI!Au00ns=QL|DGAMrfTKc2HO!wo7&9S;q z_i1JD&wQM$?)7-j`YFp7C-5y3aOqque_w>X ztUh40VbiUxH-9{iz8$E3(QA2OUO40B3oMgg&fIAg>AA%4V9KkVNy<~T&euMODEYK< zQ(RP}Eb~r@JBw{oR4!TEw2~{a(LG?o^6^Bi|KmIRo~P~q_{Mdk?EmuD|2|IC-QKRg zd)DSnoNB=xm7C?-PlSm+oy+-mrohitYo=RqJv&!2SK6K-{GRTjnzQFa7#J8BJYD@< J);T3K0RSvW4yXVC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/containment_field_7.png b/src/main/resources/assets/ebwizardry/textures/entity/containment_field_7.png new file mode 100644 index 0000000000000000000000000000000000000000..7eb0e5c54f29f6fd7255867adc7eddf06abccdf9 GIT binary patch literal 585 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RZq;uwy)-(0zq zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%+AGSWiBYi7{S26c+JzrF~s6@>Ew-h zj{*c--`ni==y>$u50Bd;|Da&KN8EcZm4&)3+TZ_PbL)l3w(`eqtG27R)0b!X@$OsPy7h93o4#JkIh9!M zq{PZ_rEp7w$ExoME0~SU6}VbX{9;J>c9rdSR?PRiJPc>voj?Cf*u`1@>@o(0>*4+P zPT&49xoOw?w1ks;bH4LTn={u}A;{@RLRXRR@yjv{ulCJ$OsQUX<9pm^^|@simoMaF z*z*2hfcw-LR()bxa}U3Bv9_Mg(4cv$v|7%3cEcH7hAYkYPE}-@v3m0{2-szqS8lw* za_g{foKC5GiOtzsh6}yTPh+cXU#wNwbd|+HD0#pl-adaC|=zdqYb1r(ZQ5{wSbMz<4Krj@74C}mDI n4@~%!bn=`UZ;8CgKh}Z^YOCGDyALujFfe$!`njxgN@xNAC9D6Q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/ember.png b/src/main/resources/assets/ebwizardry/textures/entity/ember.png new file mode 100644 index 0000000000000000000000000000000000000000..27e6e197c84da5e1b9ec30b55119e9343d672696 GIT binary patch literal 1244 zcmeAS@N?(olHy`uVBq!ia0y~yU|<1Z4mJh`hLs=Z)iE%zuvLXblmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{o;_`i4$q(Yp?6d#eBjVwublJw?Strlx&qb5cD~&cWvMKc z92C-e!};z1|5kqwD#|cft~XpFz{58^W>Qag#y92j#?t2Je?Po-Cf(Xrj>AW6^WFU9 zh;MAW55!N~yT(GY?7v<>*6V|1brZrBI<*frW~gr3qi&#W@Kp4~sZ)Cd@_ujf@d&)H zzfkA@zIpyqk0PY}&aGmRkB~j**OTS3qc3Sr({`(dsJTDoJMHdWeyDXoi=4YnG zL=8mh?;UacCc&w!6x=vR)OA~;h@Z}cjhi2znrXe=Qe3a$#gfh>G0mi%0zHCBDw@H0 z=4|DGCt`A2Ua&q*NSw+pHZSwCPq>9r;Zu(la&894wDoy^^##9Ab~c>-;{n%>ln}E3 zo~JWT8r)gH@!fURd=~k~j}1$<23+u;r7Sk%teKL-zq6mC3vX&}XeRie=X?3%YQLO(o^bd^qGE=Gtm*2|<#Elc+d9 zUoor4@aPTji@9~ z)$oyz?4MZ?_0nDgz0Dn<|cBP(r0nw!>b z{Be%|?Y$|VTb5OJ=dmb0;d`3l@tybSzpHO&W|^MnpF5YUH`l_$RBSgtW74!4)n41Q zS4=9*wmVmrZK7}Pl6lZ4+suC6Y|cWqS5Z~hR+q$|ZD{VyYcyuQ%gCPbLd?R!dHVrI zsa>pm7beuH-&Mc4>+wss=-?}ae!4v;)au&I4Kr)@ zEJ?0c{Ql|#YyC5~-%gfqxHCSiR{PgfXJz<}DX}E!4eKGl##h`e7blTB+M3v@cNe|3taTNMogNX_l4_EEq5Nt4`+xgf-Ne_w-1Y5u zkdd)M+#~T{O(*k(-PDi8DfH~yslH#O$FFCvgGB7MJ@REXRcjCKOI+ed&%en>M z^xyIpq%E+1(BrWEz(F4n){Z@XeyvMAql~Vs{k2Ea=Q1!buqAoByD`M|uL zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%q%X z5(ej@)Wnk16ovB4k_-iRPv3y>Mm}){1_mQf7sn8e>#?U585~ZEtF6AbDI0h7vY52pA7aeFfcH9y85}Sb4q9e0PQv} Ae*gdg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/fireball.png b/src/main/resources/assets/ebwizardry/textures/entity/fireball.png new file mode 100644 index 0000000000000000000000000000000000000000..138e68c9a988681d74298154ec54bf1464648c05 GIT binary patch literal 1764 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-6RScZN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsG((kKFV`gXhn4kzy7V#-_&`+`jNW`!QMKO;p_8t<`GBTxP}! zc}*;u`S1Js#D9klAG&C<-f)S4j@7E|MLrYRlUf@?}={5U&yX{%|xny>x} zzKXN|_U9qnpEEUq~IVDlJTybMXd*;Fe zHJ+0KtM_>RiBWFaHo0I=W+c~^8xgM7bL;;8_<5qJc-B6}`i3uA7p)(cd(1w(@Og`k zqR6^mPc44l-m$a&%YnCk#T?V0wSSCR?)+|^@YbKwi;o)qvWhKZbm#jW@I0_j?Ap|q zYm>tr0{`sky?k@C%9IZ6K*n_E38GWHIwcJFimqr}UQl;ss+Ld5oyb7raIsZv&4LLk z>)7w)iAk+t*yqV|NA#hB#M9GaR#%oe$1deK+Plc{i$IIuwm)Hp@sTFS_5`??#qDc~ zwNaK1^Lf(IqpHKKWU?*z@52Y1ZR~}^8JqqU6dz&StQ*YqK!0A|K~?q(O|5cYceyXg zP-zn8A--~wwF46+zE>BcOLX8Q(}DZK+M7Xn})3S&CgP7 zf=nFx2RoRgV|*K)&T;>~F`;`MIriL84JsSm5%w=2dRKvwWw# zSk$kW)nj;cjs>U0b@e;PMS{I7oip2>^xT!?F4Buxvg47rMpTlgYPebGs@412R+(N4 zDSoWR`+Z02GTm)gik9~Uyju5LZr8UP!RMJ5nx*V`=q_RP$Rq6u_g3E5vp?}($yj`h zJ*aqL+=|4IuOg0<{r()`>DZ{uuuhm!=&-RSqkd7JdXcd4Y&F5EwuyC3mot>uSYp+` zHS4{}J5kAe>5uXbNrr>_Gs^okXI;(chEb*5P!AngS?pwBMid9hL-iezN7TSurrQEvvW6iXE z->1C0>!6ffSgLHd_Xzvu63fnw(`$9g4)5b!6?J`|OyUij)1@NkxVPHr-#2Ev-+n+w z@7(Qa9U1vsr|KPhJWimSDK zr95kH*XcX@JojJxk z$B8NZ&d=7dZmF8klOJfxd$DYnoArt`?}``?+(>>iu5z(GI zW9D?lOe)xN)4S(?)bq}S?|)i;AGwk~`Rpdk9DkGcBax3M-SB>8TYE9ZnOXDg5s{T_ z(_PEr7ll1B*=ywX;iuk=)AJZYE;9YQuJ>`ffQyn}cD*i>Z>jg`t@jOkel{fCOP{hw zb4jyCmz-lx++>fB=9@LY?0&GbKliK^ULGc z7w$iL=h<%e3jK+*uh0CG9{J?||H#klxut&O_&$^0?OB}o@7d>73=9lxN#5=*4F5rJ z!QSPQ85kHi3p^r=85p>QL70(Y)*J~21_t&LPhVH|$E^HfdYW@*3TZGfFi4iTMwB?` z=jNv7l`uFLr6!i7rYMwWmSiZnd-?{1H}Z)yFfiQrba4!^IDK@IAzzb&fa`rBD}Bet zu7_;LF7-7Xniml@t3uG*`w*{2#@anioUN_PHymv`c=xEPqwr&Yv&na7{!cIezaq`I zTT*}_IDzpDBj1M`3)H;p*i5Hnl&x;_Ff(0o*|k@wLeN=(ZJm(!_6brd>TZwpoVJ$> zp3jnJ%yd83P%O=C$-VSgLwc$E9EODKBWq#{*Nc5v`z~?&$trv0B*(-nJLX+b-yy)y zc_q!L+@N^H7U?|kzSVBl6HfXTEx3?3Wx=;wtoO5mW^WUnAYv7sDSezbNQ-?w&n5H4 df9h=*jT@b(Co3A9U|?Wi@O1TaS?83{1ORu?En5Hp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/firebolt.png b/src/main/resources/assets/ebwizardry/textures/entity/firebolt.png index 313161076d8ab8fe4740a1aa3a401828f120e790..a01db1e0ad0edb65d3597009e510aa38e49dac0b 100644 GIT binary patch delta 1209 zcmey*c!X<$ay^S}RY*ihP-3}4K~a8MW=^U?No7H*LTW{38UsVct+ip%(;jQ_{JE}` z#yRasvE_{8mgVf_KZ6tAEVOXXBQcSKbxVV$Gzf;ZY zkb=(b$;W1k8{fOVx&HC`GAla{pRTy&`)7aS+I=8?neF*fp*Qv4@)kxsZ~ywb-9&tn z0rQ)VG=-C-Qqe5bpJb&5;d9M;)6uBT-p z6_S$=w+frDTYP>F<3$hA{y3Gz*NhHID7a0rd1AJ=P?-NA_Y$$QH~6?#%S2SP^wulK zJZm`6%A8nkAokk&v3svwVb)r4kl(a&m9ccKlQGuiG1oYhJ1L9(V0CrPu610j zZx>i99Ne;|mi5H`sC~J5vQFAEy1&-;-I%_UL4%2j+n{H2kNEMdn;##!o-l4c!O$qQ zpj#?Zkvm$ORpICgtBz(ZhnzDXZDNj|N;_8X$f3B#Du_QfV3xpXiSECTeGkZag{|Fq z&FXdThKp*;*M-k0zV}twwDRk*==XcRA9SCukzsIK043oLaRy^6jgz{cWb}G`UmHs@;CG>Ad3cIb9;UD;_`U(qDLFl2&-m(yUc$ z*Zq>pT2sF=akXjgvYXFlet%XfZpXY__9E z3|PL$GKLAgoTb~?J8@mi^_$e{1my98S%+z;s6 zRU)tPJ$8Hgs;MS=Rw1;F@#+MXC3V4e@1-v!)q5yzjd9jic-xvDdq=`_ ze)K1Asc%m=s-LawzIh<+@EY;H_fcV`&%N$b^>k&U`Tk2=j{WJF-4_ySzF*4u z^e>}}`64rIo?VQZo2fdxdE&HfKGv5XHUyU~QhKuaq1e82A4Gh-KPFk7zi?Udj&{aN zo_C^K@=yK~k)1nvXJYftdWo1F=9}kM>#yHw`FYmj=O^dBQ`x26>V3#QY3cQZ^@&S2 z=hpjt&t0!%A~WarA6?cPx%yGx*O#u^ac)~_fmz_rho`MQJ0~_;+PiJpGPmbm*s1&} z|F)=GrvJX28~5Upo6XCYKVMeK%GDnH&Rp?j-m&u!F3xuPwIlBZ*Y@-qFOnwiuU}L6 zi+7QA*sevNZ^k;BVi)zj$fs=dUcfwO-Gxw|sfrUG{CuAGSHa zo8KDkKA(R}{tr)O)dtf)2E7eG#m)HIpKaM9U&O$`z?S6g?!xeo;RnOpZ0(ot7#J8h z3p^r=85p>QL70(Y)*J~21_t&LPhVGd{l~04f;=XE*Bf^+Ffd4#xJHyX=jZ08=9Mrw c7o{eaq^2m8XO?6rxO@5rgg5euPi(0M04MWG7c#Sir!*Ae$KyQR1AR lo12YWU|=ut^mS!_#3muGEWf-qbOr+hL%pYqV~EA+)^diNd2#T*4a{_G;%EOq8xQ5I3ACTzcYOqLS&W3r}Zw q^p^LWaq&qI^f|RdNYF5mnc*RizY&kod~pT_1_n=8KbLh*2~7aEQcb4- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/iceball.png b/src/main/resources/assets/ebwizardry/textures/entity/iceball.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5adc82bff47e8a7ef089c6eb6b2a3e45cd63ec GIT binary patch literal 1803 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-1FAwIN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsJ5kkDT;IgXhn4kzy7Vho;9H+|KYm`!QLkEd1-YUBCCv=-;@Q zM{M>9AI|A7|NpT)6Tf4IYY)GaYG*`@-OnSEQ!~C#y*_zO{Q1vG>rYL-dxw{2vh&Mt z*;A6=Z!rG#dE<3s|2A72pDDjGHO}+?^f~fTr(kV`SkV^o4e3df&%5-UKUKGX`d(da z%~y}bUcI#U``yH7Z!CXL(_0{@e|h?9EzYkeu4xx!Uk+TJ{kMAI_4m(So%+zZTRHvX zl$Q&ef9vh+F?!(XmnQ!_pj=~l>$c?y-Myh#F1NmZem#BO?9*SJe+n-x@3q@tZ;> zAiTNy=!82@cb9SLmwonl`RHw8>cr}&>DBWaY+}T-KbyOCCx6+y`weUKw9PBCwO6;* zr7qg)#+i3i|AxiEdF6*>1%*UQ%sSRQSU07^@v(w`uMzL7)oVf?E_!~hYtqh5i?b4X z6qE~NOMX{gPGJ3b*7ZV+B0IbG{e2gr%+@~Da@Dz`A+@62Kr-<}{@rKVbC1nnbWM5O zEBfcr%A5+rnaW1fF7WnTuvpN>`k{3HKDG6HJZ-GSN7y#&7PDQ5XWH9wT6dAG726c+ zK9Aco83YbCGo%a1&08~pTP0=cO%1_@9tDlVrDgNDGZqT$IOzF}PjOj~#(`TBi?{45 zdXVd;#3FdGvydxKV3xw^-wc0O^j`?z)B7RN#KLR1WWv#tJqChPX9jMz`YII?Vw!a+ zXHmCZn?_)AkLI%@Clw#JwN&^RE}dd5c6Nqka*12}9B%RO8cx@)X%Rsur}~y&y&kYM ztJn1EogF*dEb=aGIXW%s-4(^9@2X#1+IoCmmE43|1&8|$QeJc@&zzWljc;xKyZjAq z?WS=)XZxx)v#ow*%6hg$NG&~~$F{LxF3$wxGn0*_Pgc)6<9jY=R;Pi%9G=N@+$I|u zys$2mC@KDaD8|6=A5T7;%ZK?1=X_r6J8&oZ-o50tPfIWCJbHoWFz2e$j(uzF1pG>u zv`<_;w^T*vRPJoc&}mneU2T~)_0rv@9;MQ+?d@HP$>suWEz>O1^!DE5dvV@-+sV@C zvvs+TE*PJiUg`CJfr-8BkNJKkU2j)gsq}Hg>X|tEtkv64IFD_&q96zRoP~L5^`DsK zXdGY5#3G-4 zbxW$i=51v!Uv4y6&)cucyRg@Pex-T)##lA;=0`;lD;&0^o!+oNvh~onEkEDMZ$A)y z;&NbR%blDv`+0Z1?&V)37Z@>nZZ%?GWp>< zHnZQ~PXFkU-fm>yyM3*AII~G&USI}q>U+gbv!51JEzskg$ud2j0Y zzU8~{$E*KbeGS*HEnIi?x$+O5srHT59(<*Wy#o5L;-=p^W4fjygd-`Pv`ufbL(ty-t@Zpy{z)w<TkFrc@QCZm#3BYg$MdE| z415P!C)99jd23F%6yPd0Df#%hcL6^XrLBV;oc=t0cgFm`&6G7OO1O0zq#y8cFwT4M zp<&kj&*?$W?d0r@BCDhtauX}}?F$lToOPsiF{iC>OoWsF=PHZdrYk$2T&=mZ@4c6z zp3Zx9>jsP11D7tZN#|=^JwvN?y@EJL496YLK&u?b^3}{Nd92@GOYLh~xvC-2cCy;G z=LJ)@Z8y6T%Ggx-)D8q)e%XvfZ-=E6uvNChK;i|L$H1y{$RXOIB=IY{N zq&-POyL02GY0@{}^xM|tbMsb)XFWRfB}{VZve?J2?OW!BzLA%`l<)WR|5w&!<-IqY Ud(|x&7#J8lUHx3vIVCg!07h(24*&oF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/wizard_7.png b/src/main/resources/assets/ebwizardry/textures/entity/wizard_7.png new file mode 100644 index 0000000000000000000000000000000000000000..69ccda2b29d4a99332f1cd424d6e2ec6c8cf6eac GIT binary patch literal 1599 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9VF$wshBhvj zOX&;@44efXk;M!Qe1|}oQB=dLfq{X6y~NYkmHiQ?EUzl(!ZU1K3=FJiJY5_^GVYy? zh|iF5mH2=5-J5%A@lEdBN9%L5|wDZY}coXcD2* z!8+Aug-5a$$D?58S^;nE5FL)*Ya+T?-nXZ0S+Y&@YtioQ)#i3FX-1pPf4|q$t=n+t zUCsS7XTQJyUTe(4S@P^le$KBymJAN}SJk!L-~X>brD)yrYXu*UdrtZy@6IQmRJ;1u z)QvAcKM%OIwfRiU?u9-1JO685k!*I9Iz6qgZsmu5-+4~$lbIPpV)&otyFV29T=4u< zL02Wu+k5LzTyE(#)jU)G(}E#pht=}A`xh0kM=4gmU2|mW^Y>3#DwQ)G-$~wGma_iu zU;W^DIwmH2I$N&mzrE#nK`k`K|KmRE@N;Pm3m^J=v7Bg|a5+(P0Ni78?M+6mBV!2Lmo!&p^-Am0w#o0gX1(S8I zG0gGrld(H;sjWWbM*H#2OWZTB^C>;AuwY%bJ}$gq!S-m~wbAn{mgqW5K4f$Gcg(#MmuYb%8>AkKgn^%1N+q4PAJ`4xm_49MEmhM=1SU~T(7Q?d6CJpC; zeTw;IIr*H))!qyZw)1ogvHt_(e4srGCygZ>`V zrVSezA27XDVhET$w~y6v^LBm)0}G24AKJSequCZPBp4}~otrwr_K0Y0kO&a74H z`w%$Q;n`$m`8OhBg5q+3do~U;Q`E zu1}bLveWqNjSo+j{r&Oof}hN6o1;%Y{}aDGUwq=!VxKQn-#h!F@ZR!uB3@QvN9SMHTc|zVeS2(x(gUwbKJol% zj`{9>TpwO%)UWM&ooTCI9b5PR)%Ev`4Cn23I8J>0I3?k%6&pk2`=%(qX}a+%IpY35 zpY(t+;D=*?>sG7vCvKOiYiwn`zeJ3KLqg)!SB81fe3I(?haVG{{kAaYmAzS|a&f7J!m@MkPW-ei(e#p%%K53+sxewnA{5LA&9!cR?ndB^QNRt}gq~Klyoa z#f#71mwc|1+Lw6Y*v|TgCu`JCEN*`6P*FTbUHgz>L$K}#$CbLz+IkhFHDp-t@A(*1 zy|?b+%M&jWdR{6wR2!Vk&iv>c7B@X>>w)}l3K6e@X1Be+ZYwDH$JU5dW9#faC(O@P zKI%N!r?7&{)h8=c+54HHK_jQt;w71@OaH7W5iD<7%cQ{Y#OhP->Eoe|A%9(+L|E2H zRjOw!IohDJ)Nmcwk+YADc5&pqKH>dlS$9yL$gS(QHyr$uWBV_u#4)d+V5d>tmm_l? z#Y$Q~(Go~yh>SbPm6cuS@NLJr-@bniIlWBgtaX^u6dY{aS=+$VGIy@4?unCfQ=g_T zom#YVrCR3UxZ~S<=6t(*AXg#MbEhB|vo`y_B_a=Y%7${L?2G??@Y&0h<5- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/wizard_8.png b/src/main/resources/assets/ebwizardry/textures/entity/wizard_8.png new file mode 100644 index 0000000000000000000000000000000000000000..38e371a1185257735e9fbc113773240e42c3218b GIT binary patch literal 1598 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{W7$=lt9VF$wshBhvj zOX&;@44efXk;M!Qe1|}oQB=dLfq{X6y~NYkmHiQ?EU%iL{_6*e7#LVjd%8G=WZXL& z5uYLBD)Im9yEpgL%9n*t4p?|mC`i!x13!mSgyymz0hu3`@;6;$_hwz2k=>6muG%# zep>eYcUs=Q`u*=`D|##_POnQ27C*<#@GI=A@}GZa-FGWJugc?Xue0);^e_3(iNtH$ zSH(-t-c=yC^kQzxuV22YHJAVTFFq&1b17n5$rtU``ZrH9ODrrI9FBes_?IU?CrR#I zj-;Pq|3leo(aKpHHmbG$)R$*(=)Rt|^>et$I|pr*^>e50`1EJ*9EE%p-4nKpZ%=u% zb^rg=Q>c_c0%n_;a8= z_h!oV7vfG8@u#aEFBDO3S*+N{q4+Y$AuQtG(-MDw!Fkb#|946x zZ)AH=V^sIVz+3uXV4}R-`AMK4b2<01fXgR#_reDb?~S%@$*cQxaT`x+i?qPc=<9R7 ztbHZ^_>b)zzK8Eue0^-t__(P@aAwfr8U9C?2hN*p{_Ec~-?NslXHK*? zXWq)q>}Asn63RIlHhliveCRT}y5E8Tdu=tbSLuZXk6ISlFc{j)xIWx+^46C-TFi_L zH*NlK%>K?)@@&P2H8S@YKHT#@f7nPTV%h#12|pZOZgzGOtkZb(xia*GrP{N-4Ep=_ zawjG;A8@_p%CMlUR7;HI>^(b%0~an#I20exbIXWp3s$Jj3oem54%dD&~wP~5T(mu(2 zf796skDt%l_;BUKy+8haD3h_SoOSZ~U;XX-6qK}|&v^0mo$&8soi3~76>O^>%61=$ z)mYn>GjYd-lXq@eEvuL|>Cp4P2C=htZ>nJXz%0>nV40ds_n~FWB%Ze|cql!o@t~>q zqCGvl4>zhv?O2`uabDuHs5ckGzwLW|t>FD!?bbBIYoI!iU&^(+5Ajo7(lD zw_cB1j-geaB{XF9=dL}uPc`E)|zCxaeWdjXT684DR*-`9QE zrF1`3LxX+R&LYcc`@cP8_ehfDsoB0&$}2Zy_2&;--Lqf3h!NAwmkLwXb@~*Oxz_!* z&HLs11Ru$rtC<-XXe+RkNB+Fh`2)A?-rH}?TP~HzT`ZCOQqOg=hq$d{KrYvRi%Prp zcDs6itM|(vO0(t8`7J*0OnH-yl?7jm`SHq4N;1qASDECe+)B#3!Lh0FP~eBRv-P)M ze=R<*vxo243_GSB?34FQ6SGfwTDmff`%fBw(^9>ynLq083Qs(EUpcrTX!ptPn#Xh0 z=SjTbXj&C;WXUwMO(}BB!ZQ{ad(GMwb-dq8yiomy76X&RI_3M@YGOn^uEwjlI38Fv zvAoGGiswX-)ZF0mDXlquBJ)1)9kxkRr${d}*iiJq+lz7D?ZBxH&wiKs+w74#A^Ol>WLmiQ UL6$>h3=9kmp00i_>zopr01FuV-v9sr literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/entity/wizard_female_0.png b/src/main/resources/assets/ebwizardry/textures/entity/wizard_female_0.png new file mode 100644 index 0000000000000000000000000000000000000000..d3b871371f50979bb2ecc0cdaaee14d5789828b1 GIT binary patch literal 1544 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 Sy~zv=3=E#GelF{r5}E)ef$*aM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/advancement_background.png b/src/main/resources/assets/ebwizardry/textures/gui/advancement_background.png index aaa8b52c8f37d328621bce85bce193ee17caa7c6..c5de2e8897710ab98700065f45a577ba369c4a55 100644 GIT binary patch delta 2327 zcmdnbx=?6>ay^@NRY*ihP-3}4K~a8MW=^U?No7H*LTW{38UsVct+nB~lisND{5h{# z#G)e5@i-x8RZ+8yJuksmz`L*`5r*|hTJ{w;@|FfR?=EZ3l(Pqtw z6=^&QGep{k;p%PtIsez7V}{%`@_N|_dc_NvqND@z(>gs zeIFxCjz7LPW8(ac#pyqI_Za_bo4ejj-fm%m-OZ*iyvnoHe@gD|ykLH9+w*>Dq1tcp z@$nm8|Gjo^{?yoBP7l>|&$sm<&p5dC9VDM^YteojZ*cCj)(#O(vxd6nv)tjuAsvln z%RS6PUwt`q-i=q$tAak`v8^PiNa z&Ha|CJ_c?#KAwJBH|vl7b;B#aHDZ<4vuhtYx|l)mSVG>OWKoWVc{5HODUW;SU4Qq7 z{t-3<4dFD`rmOL%kEnjR7B<6%eT}gE-1w({Kh2mMIQFp~3}9fkTR1~=;`uW(IV`k( ztn8TM{Dhll0>}L)Ry#Nq8)cq8l&&^9yH#h;GDTelCnqk+D-ReN*GRB_oxFHa+bWh9 z6FXE+E(%(*Y(mncDM5bDi?jGF(@ttWU$gT`{VK=BU211nMQst&V-!+To%*J0T2NN& zWvuv?u>6&G(e7bDyma5OPc{2a4@7}yyHGQ|;mjzSi z{Wvjs-k%r2^KJ!Z+kUyRbosp9-!8pQJR9*hrFWm<_v&jWBBXnc?$q1ACeiA7Zd2Qw z6AyTL3RMi|)w45eWXR2_Tq;p%U~cg_^~6+z2xZA9cT6Ohn?EW}^K0Kdedqm8&s6?t z-}^CtMsf45|IL=>D~zAjJ$=i5?VXji*9?~4U<-q<3!QJs9f^#5{dq&$!jApdX7y^M zy-HTFFe&V1@ap?6!`7$UbM}qb$A>f9xHhGO^Ci!S@z7EaQ-%(pr2 z^rG^O3a6j$xiopYzkpPp{rBrCS5nq~_^>UB$>wymYv`HTei0h$bu}hrr+;)idG*p& z;agl{pE7^9d7HCa@8kFv=27>)X+P^if9r*c6~$ajWy`wWZIgZT)$sSt4INd|epB_m z?I#|M`Ll1QL4nv!E}yc5)Ti|lE2bo@$e6xon_0itMh(|%b9OCbi_ZT3Y>()zwm)5c z3oWHRmaz<k-saR%N|fY+K2V2`o#VWt&|}o%$e0uleWlh##BM?lLWoY`foN>YBb@tIvJv+CxUEAK9y zJegzows&_=ROGt5U;d^k5-aCHlOVk)y*X2ycE5Pxa__LzpRtIb#}nwaEw|Ldt$vIcEuFX|bWtl7b5w(DKQv$nflpCn!{WkzQXgS#jbLIXB(A z7qv=u^OslMY1>p9yt24x@|-1G@=9LYDLwJ6S$syRfcefA=`gGIgR>aqzIz+7C#7ht zy(MhZHs_eZfq9Q6tj-iMIUaAlbjNL(+56@h|EhG^tK(d;r~Y30V~xw}g@pXCZ*VEh z@!IyN^M`Ixm-bublGdtQQI=Xh%RhI|RlBz3>4Tm4v+ ze~6m=y0s;zR`U73FXyDbZG3fc)|VeQr<9qx-mHl^xa8ZH=a)Bqv1;g^`bs!f zS7TS)d-v_~QBj_>VwO~Ep87ZU8ZWK>dR@+W(-N~!mhsmn{is#hRlZo%S}f!F@yn%B zyVJI7Py1ox7FpSIe{1yBBR>0c8TlKJ{^eCR`e^v)#AQDQ1_rhyZ+91lsSI@tMGObs zLKzqsI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_Q%Y^;v)S23hZPU7?{fIJzX3_EKbKx ziqDsE6*y9Fe7Sh@?(N&lKR#7jq7cc!q#DE(uQp!2x@wi)*Tb9TgSRxf78g~y*$L09`EL9Cwr)2|eC=@6NHS-3RM@%p2&x}Cd)B%nNUGs`t%J)4-}di~iTjxyBo~&5H5h9C zGI%h1+9sWa?Z^G+fn~Sd zBJ27c)$NZD&lSj(HDueQ!|o7r$Xqvtb=wKao&)s)9fnG|JUQF*XPnnoDfI6$OlUi? zum8-NqnbC$|Lxy%Y8te>8OcT#^95YyCknEx#=CM1y z@{2&M&g$O}(yo5mS9ta-FGJ;4C&|MzL}rQ};z-{8{Oz}-P3#8S#kQ`=IBdatRB7o_ z&dY|2MIxsqw$*!ZzesZ281u2>GsoX|ueuJN2}oR!pXH)s$o5OX&@1qXWLn@tp)2<` z-^;nMH+^F2pW4dCCo>QKZi|)B__VUqP*d&N|I delta 654 zcmZ1|w4Zf?vH$~HlDE4H!*mej33~B%au%Ch{Ua830e$8S8<+143`{BrZfB&tX`_jDI$I|vhnLlSxDeV6J%5IwGiyhBzxbZ1&iuma(mvx+>#FqJH`S+LK zl3MbNw{LO%??2r};JDS%qx^q%%VixG`Ly7rBtzQ#{mzqJrc5h0C}C_!jbupid9mZU z&6U2)YkmwIk3|{|ynh&1$L!!8+XVwL+$f(9or(Kz&R{fqZdkJlgNSy%TmHM9%Ncam?2(__ z+OKB)Gc!-`+l0giij3aBzPys}6lR>|CL#GEs;ByAuLa-5l(wBqb^jb-PI%xtCH{?4 z`w2l~mqh0DV+-GZ{qMb?{;tLB4~a8cuCz>gH|5$fquuNbCfVvOb@Hb-d0tTarT9dc zRUy@7b)AdSG7e_`*cPAEQArjXHJOLwEZsP z>n*_(619xy#g643x(n~VQ+n$o)^K~Ze20l!hUPN43+w8YdUU$FUvH647b((OukP_~ z_3tU++m5THtvS=ezxK6qSGU(p`xpHlZN0LU21a^3nQ^iL$t!j!m45v9OMO@3idnPG zetvq@A|%-&Xckbjj4NdSk5y-kSChJDCDGUq@ N44$rjF6*2UngBMlD$4)> diff --git a/src/main/resources/assets/ebwizardry/textures/gui/arcane_workbench.png b/src/main/resources/assets/ebwizardry/textures/gui/arcane_workbench.png index 772720ef0b8df5a27f33bdc7317819ace2bf107b..29914ec9583ed974fff8b37772aa9023445234e0 100644 GIT binary patch literal 30590 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 literal 28839 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℘~_$T!1cz5cY_h0uo8)}-iFx);G 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/curse_background.png b/src/main/resources/assets/ebwizardry/textures/gui/curse_background.png new file mode 100644 index 0000000000000000000000000000000000000000..f81ad1b62e8c9dace25f701d2b6ec7054321a72c GIT binary patch literal 621 zcmeAS@N?(olHy`uVBq!ia0y~yU}OMc4mJh`hM1xiX$%YuY)RhkE)4$}G#MCJb~Dal zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifv5N}m>R(M-4>IbPr;B4q#jUq@75ff3 zh%`KW*~Yx!wS^0B`OBA8;y&jc3PL-y-Xv(Ktcf&RpKDb!--Tz1{(JEWJfT%5JA*>F z_xj&^@%-7_#^=lOYYseJGpANOl(1_w~^nMpC&AI+IB`HAyCZ-jyU>W|kMIvSonKg~R0(tZy8%54n88XTCu Zo4NYG@4KI8roIPx)YH|^Wt~$(69B47l>7hy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/element_icon_simple.png b/src/main/resources/assets/ebwizardry/textures/gui/element_icon_magic.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/gui/element_icon_simple.png rename to src/main/resources/assets/ebwizardry/textures/gui/element_icon_magic.png diff --git a/src/main/resources/assets/ebwizardry/textures/gui/elements_picture.png b/src/main/resources/assets/ebwizardry/textures/gui/elements_picture.png new file mode 100644 index 0000000000000000000000000000000000000000..263b4ca3ad6814a99883f3c4ac95e41e392cdc59 GIT binary patch literal 7821 zcmeAS@N?(olHy`uVBq!ia0y~yV8~)%U=ZP8V_;xN8F-nvgUe?PPStFDczueJN}Z?FIVy%*oh|0{F8Y@IImC+>QE ze#+11KlkgZ^xVIG_EY)opMUTF*?m-A{Qu+kM>&tJw8^x5l6_L?zuDgIjZD&JKVRP8 z?<+p@7==}eeu1U`=0Nrl&h@w)cobAZ=Gpz z&?@p~%GnC5{~M=$+57&-z5M0ptmhw@YFW7Xi1xpi)_+#3|JT1?f9Hkm)I6_v#eYY- zN>fD@P6s^uq8~nS!k4<_sQo|c?mz6`^6%%;BT|xU;%8V(&nf(SC+X^!^xT`%(;x4W z^6s#II`7Y)dkq2~?@c|bqRhNeb@j@nFD$FQj%=Jf|KzF7Q}>*3SYz_&b^wwe(|}qwOejQeOBw4 zl^3_Cs`&f6!|B`Os@|@xeqZ~=@{@tWnm#j|9=l^RCY#T_Q}yZ9NzvkUdvd0RhDY!F zC6%3bDt&rv`R#qb<*Mh^yt(jixh((k`GwDXrw8qNdhPbQ`*p|X_D5BJJGFYfZT;U~ z^ZzGq<%j*Bwe<`C%-`Q5z4u23A3Ie(_y0`Od1e1^>rQ&GL@PZ-XS&O=SjhzoHW!Ii zYpH4%pNf=eT0QGz)GDuYo~I-vb+CA?qU3=+TFvm5SXU>81%6Ye5 z*jy_UGpBCy`j2vfo1{K1{Pmfs?bmIyn!B%}?q-;NuNCW@vsUlk%eU8gJ#N46yLDhg z3F|W1b#0rSt6#7E^e)l6wPt>y_wC(R1J~VVnw=P4KlN)w@9}4KTi3F9=^eQKExNQK z%KSzmr`zFg-m8V5hOD1&^j@LmW!dtJ+vi$Ndu}DKeRK7l>#ukB-u-O$wx_T>;{kiO z!d~<5ua)%{+gy>I^7O0a{Iy>hURcMN$4pNtJp9yLSggpAW&YHHV>TgIb}cWQe)D__ zW43Q{y1r-P*{>V+@MQdsPAL?4uzP;snxn~zEAr<^XU$W7JI(53$L-!LXM7I}MdrU< zddB}<-L*LF;H9k{lP(@zq|2CR*f){e*ZPy?zO0#_H*&skmWWonzZXSUPrVucfXW%O4)v6`E8^ZC5+-z(l6IUlLAf1mTc>h8I{dD$U` zuTu9rGv3RpJ}UiZ!_D1hP07~{-#=NmvRCxyf9;juUufNbJ@fACqh_In)4u-hxGVc@ zMQ3%`f|bA1Cg$9{QD>c#5EPbjy7JaJHa(6gv+uuqww29WzCtdu>S*T8@Sl!7&*nV7 z#PYjx>*PCgk(!_Ww#97b|xKS!>?zI42)JbM~@1a#H8T4VtQ)^ybas ze#jb9w&c>vweHI53=V63TvK(uvsZ`Mvx;4vdROzr^KP~!!nYQ9t!;Z|+3-?Y>p&%VVA!hCO<7 zJ3DZD)qjyYxxSs&{N%C29%tz0#M8SbCq#oO1Wg zzQXFb0GC%=zAn4KaeCUjw#siImkXz6-({Jt#~gSI`+XvL6h4e>X$^O4)|x ziv9XN0^cpC-mdIgzWsJOYufLHHv>0q4DM^vYGMs(5Eg&2T2O(d%&4;^Hke^?+QX?+ zOMB-iN(q^KC^vClTE#s(ZYk6IE&Sdw7x-j-`}S}#Df-{Kmp4JHaO(?;^RJezxG8jY zOUAwE#7S(*QaW>$TR-3BKHB?X`G&;R&u;$uW^(9GZ&m$);?_JdjYCfHPvsV*X0=Q* z`dC)T!~AN&&WHvk&rbbZeZOpzWQMCN915Ctr7TtVcf4QK{!Gc>c4hj5kMH<00=|7# zPv7esQs`@ zTxKqfZndz^BlTqw`dfw7L+&bkVcD`ZU~=#R&e-;%yZk1%-bvp$y*ngfUbk6l)Gw<5 z#z`Oe8e^_h-TJ-dPKlD#0`*lV?mI^w{J-yfTjJ}?V%=t$rLrt}U15Rq@`~n&5b9>bXTW+!N!cT}TS~HFd{qQPa?+XS1?Ih|Ke9u6kKy}NyJuNmRW*&A$^zIAEYjPbCaFbv-s>~ZC<-g z0<%}oSCL%U^8G~Fx$gT41}+aLGAwC&tJJ$Be?f=OkAM`$ywl6Hy*KlH{kz6(F87n> z8xuH9SF2h2)=M{JYah_j*{4@--Tda#mW1m$Nc0mOC$q zU*79~X3B9zyDKjfU6($e@7cn^W4SqRN=Ced-YiM2Mdv(xjtbOTbm(N72VHA^!mF#o zq%5(*%j$-&goF5}jSWk)?ZftUtj-N#{$asTU~)hqeubz=zMks2g%gjwJfJ0)q!8in z{4;;S4YnEo7P4<^7IN6;CABy~$TRo;o-@X~%FW)s+T`|1Cd72X>4V-{Y;$>e%Wuu) z{`OD+8o|F|P@-3E{h< zR>gQKFT${+`D^xj6+6Y_Emjwz02qUO9) z9T%>Vw6D0qd2#YV%~aMk)-Rb)U)TNpAY!TC$|cV{GEL+ksvqAYz&|-f-)D>eU!}{d zw_MTVn_rq#BJgN=ch5?OdwTPGn7%XaWw4k0)D*3s>J?w8zC?Z=)7wS80=7MS1Mf5L zI-y%~GAphh}~;vYl3-xkEj}SlaINDFM#p$BCZY7Ok4xrUplg0_+vj%tNL) zxp+PFxugC`!~W_I_3uW#ZU0XeIYgg-;QC~tVSkDsYs325&lA4Xthi8qfNcizH^l}P zVUD`(B7dZfvfq5`G&%M7ngd@b_Xn=T$1`=7s-`kpI=HIcS+F-Xy+Bgnc|*rVudT@* zN9$HPzx1%rGL-I_^YNxhYKwJORsPY3(~sqdCf^7?#3~}%{)AIbFhlK5rH}4J?c#*w zH75giU#&X0>hk1{*KGGL92VA@A!7YunyR`%{Sujo&ip5HJG|YNC#wP${Lc;SKR0T+edDZxQovrCxHIyZ%!I$hh@@IqHb&P$1x!OPg{v_VwL zO?Fv>74M}?dZgD}`Rx%>q2BQ1UEG@QM`YIqI#gxmWt%Q$3%uiEJKN(sJ0F8YivI*Z z#v3bq4{`Uz*yxIhl=s*6CWKgua+$1Du8R|})Qe9z;Pv3rC9CR1zoV}tY|Jil->!RF ze7{oZ?~A&&?=+lDgx;+`kS=W0$&o8il{#^2ap&^yI}lTOa&8!D;KFs2rXl zwv(4PYQy@Fpvj)Lzm)4(zqY!ytrUA^ykOZxtt5|Ca|HsX{W`ZOe0fmYACn|Ojb#%K z2G?c9Fn2Flx-fXr#0m0_$x9ON-L!sEcInH^$Jh5f`uFp!<&y53hC9NIH}QW}D0vXt z^681ol6M>&Pn|w2J2r=lz> z&YjOfXBbr;MLbxvge&)i*tdX(uDn|883jr+8@US({&N-kqw0{smb&&rUx8Ik`@>T+ zZcfU`^I4^G>xkMSYiq%kq8q)MKe=C0WOUwaoj0xR*(;HVe#V-Pf+&CCC%+3a)_m<; z5#X$RGrcFi-Sv3Go&e$etQLXUB6C0FzhU6#-NP4^lQeBzyrqfP!bEl@kBebfCKx1d zv+taEMN#~ci}&Q7yK#%|&uiQF;%;8b^(7v4H#ilY_jG=m$Qk!$?u!Id!3Exb3=Dll zE?v8kII+;gBjNcA1~10l8FpD~jGa$2M1N9iX2}uJSv>cIuF0JOri~k?-LLq%cge%U zF1;oXFa1jsj-B_TXQqC+dLo0%@=Tep)(0G=zOr9 zZCg0KQfkVy#!KC{D~~OI@X7HkC_OY+;>u*IYnMko?G#rS21sDOmd^%8La&wU?_IeOi7m_+~xp^IM;}m$HTYqI)+){CZd9{QJUT zKE-WPXO6ybJ;c7gt?=&4r5qK~g)Y9bTdpbonI+|y&%)@JRT;48{+=1%o~&eX(&{oX zn&E4{Z%T=bVsZP%11eLR<}6w9`C7xdfa~tpWK~ZtQZBjJAi$v7?q_HsIw`zRd9Bx+ zPgCq4u4CaBS~;s^fn6B;f&`B6$4!|l=Qr+L>TyCU%jbI-x7VaZmx(zVuG`{GU3PPy zU$l6V=eY|k2d1w4{MFAx$IOhO+~kRF>FLt^H8(E5WI3jsEw(lM@`a;SPThgddda&c z&OS2D)h=$%QV*AT83z|IGj^IdynV>#tGxTERqN!Ne=n%MJiy^PRqxQkhRN9syR5!B zu&>y7(ZTe@?c(`*>zM5SES$?wv4`o?T#Y~<^Wf|y(T6RXa;7u|{(t`}cH%7-V>ylL zJu$DCS)TsYn)gR3%VgH!TO#+&vU8lp^*F0-+K#F4PiWB+IJ0GLW|5Rf`lT}*%kr%j ze$=f#w|>S%eWnxkU$|`D*$O2jof3B|oPYjwkNy{yRDorGUS50|?$VOH?@eC9ueC}? zMNR$Y3k$aWI+y?YG5ZBQxx6ozHP5qVA3B=OwnA>os{mV-?l&x|7YnX%gibTrG2Q3# z&3!fw3j=rc*|ObqH@p&)>A7IXw*@oH`}sGz@22g+VFvu<0DX_?G#KFSm4Gui0ZfW4YuKzhLc*byF6^mUwK^?2nwqmobaa&ZJST z!n^r_anniD%asaRS9dH>cK&fz+%aayj~dmRE0}t7Rvul#eA&2Q`-f$V?_TR)%=07K z#B%%bGN#@SHzwDdV|XFC<=-&{XDJEy6?*%0-|V>b=Z3FO=tUX6Gv5NDe%WofVE)2K zrTTJ&>jbBA$-o2i10-|KEq!X2?XmUc6OpwWuJF6$^gI0Znae(*;1!4X0>^yjxn=^Q zPeZ)gqCJ&Qzh0%gBX7ewu7Zn&4oBHt7}r%4Et>z>%4KtWor;MuvV6>-CHG3KW`- z++29>_v7@tS8`@osXs5(SYqScBz23;X6bJMfh+74C50=c?lsFz*_sx&;z7esQ%(<` z!;^O9^Jls8y{K@_652n1W$~8=zdt71+&h*mTqu{nB=Nw)%=etqyHY|01Si^TIdoAo z^UbXFizODFQ{2$6A$O(da^%y0SESc2jZ`n&Tl4vk!rj$QPHhE!bRJ zSQ`A?IVIlxV1%3m`?ninDyJ@nb68uZy?XQ7&#U6{=NCQiO%^n&ZWNW(KX~;;kBf@Q zc?X79M{1^Zi#xUkZ=a&#*c`iy?_8;w^XAQ=F5-Jzr(9HMmsyxR+3)?n$*Mg4!3h%A zg;k!^r*DpNnCuv9wLii4!_sF9Zis>@(%uHU&(vQE)IP`Y=&)2k ztdV}cSdEvXuVuj6%XVLrDj9XZ$?j6xwjq3$-zyh>1LmVLOK<#O@A^}~VR4wTeAgdO zoq*&{n+rS|dM-yU7<60RTA5%!(N4SUSJvaTLXUQ*`R+;V=XF)7m03krak{ezWPcC2l`of9d3Tn(-I{w)orEHVE;2~X3mz@m&>La`RvYTIDRlkgrj4n z=l)AA1&a5klq$XEoXwJuzAMf>;K6GLn?(mb#pW_h-uy$Xxy7K0tu)nj&&3|T<6Nq* zwk=Y>5aGYsK*h)?WwE?s(WdTOR#vyZyNEj)IR-b#^+sLGOS$*7j#akM|D;6ECAV%B zUY-0a&*iGrqC$-Kz6kQU@TcbC_lo%s7FV4R3d((5puaZE1hj=6)e1P} zoBs0j*Nw6_7jk{))-p9bbn&ygRpT@Hc=rwb4RW`?&CL&NVb*fklJ$-6ZRU;D{I(Zb zY!|z2$XX!i>hazxZ1IVNb+Up2)?pjYT`xUpytVt_rn3RHwJ%?^y9AzIvTNxC0q%8~ zth2ZKEL8e(?&8bWKPE^=9ID>@?)_yUVU^}tUth``NXcURbaqepQKuJ^iFdpKW8|Ac>H~Q(@g@+SFUx~^dFMYz9 zWi9o9%_3y}oilxf6FptTUL{NuePpYlGUc3yRMg9aoLsA|FD9EQNq#JvyP?Z(m%;Hr z+{`CT<1*G?USiO8Y6{8SM$Dc63>5L zoA)+Lc4*oyXJBApOY(MiVd!UwV>s%5bLCD31_sUokH}&M25w;xW@MN(M}mQYfxX1j z*OmP-JDZp_6JvznGzJFN08bakkc@kKBW*pBBSrrC9rN8jA*pL(!eW7dDJmyIgty&x zb8<-J-tFiisM92ry|GUss6~Wv<7SBtg@b9kj;?hHQIp^}VGbgSRlcIw`A^?%Fu*qnXD zd0_I!#WfqB@lVpfHgD^JXE(*C#z!uCc9ZShBx#1MACjHV_3rC4YOL8Sv-t9@Lr+V% zs^_YeeO8s%+1oFXo@UA*)>X={@<2N2$W!j4yNVAAZAfoQjR}ZY6?UsJU8X^8;x{Yb zqp$D3HmPmfVaCFs^1Qw4^!jt=YybM+;0_?7&dI)|Lo23|KD~qIs8oGWmkWFfVrSxQ{UUGk54c# z9?0A05;spmCGAAszLYyE|Cw(d{ZuPI{j%nBi;cI#BAXWMVc%b^z<3~c^%|FZoI=gY z_oIGx2W`C+#x{Ye*qkxVi(UP-*Aq#LY{~tl6MWuuG8k}mu1g9N6^dnWP`qf`B)0jD zSL%(W$_bu_udmNfkygDWFx_}@inYH@Pmj5=#gW(|SE3jJ)DyHs0+*?9`{js`>f{r4LfBc4_) zp5rOZY+7E}QnN9QDT`&trBjpMzbpH8{X}wCQO=eI#``rtmTU{}?_?CNtk1h=e%pdSTGXAhE-`fquZi;JmTHrCX*ZY6 z@f2oQ6@NeB-6M{tK2hu^U+q&mb9T!@rZq|B+xAxZFqBO2U@+(NIJHGHXHAltp@-b; z9)-#`o0yi$uyGpCGGcgE|2byytlbueu78(TFN(7~a-`#-O@qP#4hhd)#|#~eu9eR9 zY;_4YocyC_(&rERRyr-}Uj5nk{@0Qcmr-@2c}l z-`%VEv1Got)#4M(EiBA`x2Fg_cQz|J@He%XS7_0}XL_E+fB)^-w6kq;;Nv^lYxd1z zPrZKJD7LsZr8xGCn(y0#8#Jwjzu@2|b8ephz$v4Ulr zb{NbHycyHXw$~!Hn3rh*OU0)iCA-yr^5V6Qj<;mBe3tFLGM{VZ@im*`>U@o2nL^iY z5oHctyQTK!TLC*a!-bmm%d?U<{QLLRT(peG#lmhw&3*Txx)&j}&2cg(e=35^IgqT_ z94z4>6O<&Nvrb>(^x`HHV+)zY$vZy$dT)5seiNIR)GQ9JJ3H(CKKH+McKV3}YDN_- z&uz74XA87XVB5PR-t5Iu&W2rc{2H&uXK-ZBIl9^Uv&h{Oe4Rp0T-?)Mt<%?OdBP=c zIN55g?w5~qS(#mVPo45!*W)+CZ1*1bx23ZZCVV<7weFlb^TvHo{s=H+{M^@Hv#~Aq zX5op}>pO*08@{Oqrl*BurgmBg85&#E6q;CjZK)2L_*vjW&35(0&*UPqE_4eso4+{P zTRbC5;FdE@T|Dbpq+K!K6$R1_3dMS`Ac>@*)4F; StDk{^fx*+&&t;ucLK6TF*T1s> literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/handbook.png b/src/main/resources/assets/ebwizardry/textures/gui/handbook.png index 67a4415fc2b054caa0655f629263d088f6cea0ce..e45749c61317d9b43903ae55d2b62bd193c04975 100644 GIT binary patch literal 23928 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 literal 12848 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 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/obelisk_picture.png b/src/main/resources/assets/ebwizardry/textures/gui/obelisk_picture.png new file mode 100644 index 0000000000000000000000000000000000000000..9b02781944c0d25518fb8e561f42347d7a0fba38 GIT binary patch literal 123931 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 L^>bP0l+XkK37-PO literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_containment.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_containment.png new file mode 100644 index 0000000000000000000000000000000000000000..9d2781409678fac5a2f82c7a1480159904b006ce GIT binary patch literal 12674 zcmeAS@N?(olHy`uVBq!ia0y~yU=RXf4mJh`hOl#e;S3D=ja4BLB|(Yh3I#>^X_+~x z3MG{VsS2qTnQ06R6}Q&T$($xu1g3kCUF~*Z+^a^!wMN((kXCQukcX+#|O?X2rViz5o99ev3OX^*h`9*Yf6{ zzTJCJsh@MJTJilo>-OL8>*Qa1Zhf-8-{9W)_uu~-^ZqgWrTpVfkdGPrKc06dEko<{ z-f_;XoGrED{PTbF&42y9|LpPNKEs_)*Vg|q&TN_Y@b@d}`scrwU)KJ0^LIsDrF+-b zIh98C*ZV8~{;sc=-uYAFSN5lTwZDH({(JaUf0|jkll{F9`y(}K|NVXZ+U#G|-5S%E z8*fjyUjC)>dH(v}kG^eB|F>aQ-Fw^9_g>q@a(BA>y?3s)IrX#ieCgS1Kf@k{KP#{4 zQj6ZNwVzAT(BS!zlUDoN)?Q0ImfJjc+s)kTKdWyX6ljj-v$lHP_PIE5ZhmGnXG^iiGopYnf={-13B7UmH7d&>Ep zNilx&&T6DsW}i*|DIvD;_uMNLYCj%dfB*mFIyvrR#%EjEbNsK18r1iHn_m1gIpaLL za{YaaO_lq^6S^cEQw**pH>yX<=Wg;ZJC~9@^F&jllykY=j=sp8o;)KD@jd<$?HUj6 z)u`Y894LObR#M@Jz(sXu0kKxKV_b@l>@7uVR=CPL_ZS|P@m{l0b-qZV=2I1y+?&rQ zB>P!DpOl@q?1zw-&dMi2Ub<^{y>h%0(Rn;7Ywg;?%g3fl-_NUAu=U-p_Y05Dt9rNe z`n@*e!~F)2Je2#5US(YNweNg9Gi_e#wVTsocUWA58k7!yS=7XY$#3NzMhE z=Hz?}Q5R4-k~^hv+0>&O5+bf0&9%?{e!A%5k1zX^&6^eP{BL{O&kKA+B2TfE068{+NLeJd;J85)pv{eg4bVr}Yj?L-e|g1W>^`aXc1>cWb*x$Txw+SRs<*uT{9^LNsV}RNR^0WMHk)i6 zJb&YlY0JD*k2VS~wJVVC{%IS$uj}UB-;vSrnOW;3oKH+vzxlUQIa}oH@*8D3zjhuu z=uk1;Kg}-cxa4z=iwPfXC*8ib)+<2J^$g=S4Ij17mn07=ur4{X#pl0{ctf`KrOnQp zcAtyc?caNHo?=wbxgSpJy3;$&!mNeuTY80$dqgx}W7*D!6Cu4Dn=}($qVLjV8thul#wcZs)?EU6r#%XK3&$jCMyPzdU_db$8Z=pB5LIR~!wUadXqze|t9UNS~s4Zt71V#@okV#Av>5O#6FV z_3ZlWe_tnsh3o8mysc&bVJFLZku|qYDTldy~)$h@gFT(>h(gl zf0M+u-K^jKnK`tj@9X2Yp2H}#CcR_7|BLlM|I{`V&X{I6Z=Y1mk!8aB?R6Y8<3Y)=KQ}}b%I%jQP-Lf>xh*ntNUyZDu0jBUMuyvXRYu?%kNp) z*CssSs+ripe_W+7A*cWB&!ZQtcN{N%$UA!h?_MA7=M2nIA06B|Z!>GA3MYO3+5T~# zrDy+H-|!&gI})Z3Rvl7&)P66&`*e@q=lK`&3UX5ogl4DhmMf@iXZ(=5iJNo9=edSw zROHt*Ex$EyWA=RIH1{5Hg?Zi+b(w5 z(TOq@=jd#|#b2BzY1c8`Y4K(5^(eJ_R_`hRr@Q~%*$D|eaE!e%{MK-UH+xx5h%Mv^qsV5wV9^L4@KD&mkkNCf7+dX zp?1zVWN-h$XL-Mr-XE;4__qAsk||3MB^`O`dFt#{f!!SJli$5x;(qx&zku7jaDN7a zYvQv1KgeBE_}%wvU(D(mpI?5Cd}ua*-*rv<{r@hTzSBL+|NV`_?cn0Tk_q1CXIz#f z9!e+(w&}fbTezK7ZQjI%#>S$}6(vvHlq!?5jFkT9&zr)MJN5YC$$5`B_dT-tpth;E zwZZPW9q*e$7Un-E@@Is$dWlP9wI296X~s{-TQ?_1?`C3M)pG1cp{=%^Ez6=cxfLHi z6tP^FxcKq@jy*F18S}e#`@ijvTpU}KQ7>P$*KNh~y~{OH4p**StT4U9QIzqd_Gv?j zu-L%jYlYl%#C^5-&)FQk;l-Jl8k2C#gps9fp@7*BdyP=P6v537aZ~gBtD-jSdbCXa z)`Or8M;Ko-@3b)%RZQFXi|J}xu5Fu0;Kv9XiK#(V@{Y%}b0@BNtY&DO^1`(9sL@5u ziEanBt8U%UzxROd-4h+6apDtp?41+vkhx}Z?n!4`i|rg9Df=TrCrJc-$(*88w}OjD z)?>obm<1g^qSucsI#IXoT#577TCp{S<(C*IJmXW5Ggpb77_YZC7wXs;zqD;}Xr#3+y-$DQ4(3h9iLHtc8rJ6r{%+c>T{z8^=fE-R z#zPqbN&CDj`w#t4c=MviQ*OmX2hBURW(G>a!7+2+{5bhQz*SxBXn((>jS!zp6vo>S>jZW7szgME$8#=d2br=&xSdDnM~v5rlXEW{U);?D6sp@Xd(aL{Pv*Q_d5=q zX7kHa-9MTCxY*25s%4Td8o49E5Z=*Pd=~IrIRDIkl#1WLoZ|}Lo zVOPe6&kO51n(AuuqZYBfJHC9^##ycHCc-C9omt)8xn{NEqg7h<)1Jf%1vc#z{^POT z?g8gIohJf)TTNr-i#7ys&PRQEdvEyUP zgOt->lCG}!SReB{CX%aH`*~mG(US=d*EC))na(czyi%y{!AD;i)5BH|B0?uHT}`n$ zqq{=6<)lIWi(b(wLX9U%)xG92D68eN&tc%*dgR@qL&;hxCI<4J8&8WAtmKrn+paQI zrGmRqe(leXPfwIwPhWd~|L?D}_wP+R*L|RH!_9Cv)^$@0^mVqsHFumGF34qne~a_R zOGX*e+@D@9+{(7W)#Hb{)lD@H&W2oThW!_KK3ExKY+=-Hl(?}tdb0rMN}C7i>T>BXO8vvzEm#5JirYHdS_ zTJxT?*RvOt@A$D=WP5pl7$=KCik#);&eBOmBKK#i%#=G=XD&Wjl(93(i{Wi!!kly4 zdwwtYzfrL<-PUnIm#D>*gYm0R@)*W!I{cRJ&H}ck0#2K(1HLD0w2hfwJveFbz;#|5 zUsIXhDj}uR6E;SgPvn}`%Drm7H0el#lF8wxg4uDWE`(08_xE}Az%aCPo<#rri*HiY zszJuQb(xoK<$`ZV#7i~^8PDF?emHGQV&bwjry~Dl&TFv>S+HT-3JsTI z=Z+t$)bg46Bd5Tye~D9eQbEw2nkc9HxlZvRhTkL`91rN*O$a}u#_1{7l6w6)OLa~} z<$->_YzC&-l1nP9Wj7ig<=`riP!oO;w94%2nG^F?v@qDH7ydT75awahGQa#q>YL+_ z?Rh6Jm~?63BOXDQsk`n?=b!s~epGO9YeQrRTll?Ffp4?do+{2_5&Nztv1Wx|{fT?& z|8}@ea&Wc&s+!=`t$gsI?)i(1F7l4vC0@)1OfUIA-FBL{QbR!bAj7TCi;66_OH5yW zSBvrAmAHDV#YPrW!qZwj*=(8hCqLV6VyZl4`cKw0|7F#-3)hEC^wi3HxLV*}p6seg zD-2KV?wG|^*`+$sYf6OTk+l=oUNF;r2_)~42khZ85~DuImb?~vh)|6 zt1|x!i*)1j8#B7{d!NL1+s?Zza=k)BPf+^VQGG>&vopDFxPP3>x`88@e>>ZaH?#X5 zygzNXx;$kzyc}y)cE3f?T@qg{1cX;}ON4&?jPYL+C=Oj0a_7olMQW1~4C-Uv0KfB3n z>vXbzrfHqHY2#0gI|8Rm+=F#RPcX2rsQ7nMGDo>Qm1ow@Qbo%nM_8D)HaHwCOboS< ztNFjCZ_%-N9bpW=8V&~>O<&k6k>#BmdC`AGaq>Is7R~Kh8@?2%}8gV#&OJivC!#0B@iM_|CYv+C1A@*~D^}#ul;df#-y6Nhu^Qy$coYw*pRsN-#XJCy|PWA3%m|gDBbFqcyQ|ci&805 zCZ=uJ#2u3RdV16SQ_+Pg>OxJA!z#+I&GAu-o;Cf<(yC>rEhjdd$ewqerMswbR-})f zXt$Wer!&zzo<2{UdHUQRy>RixZlx`aS!z+c%A=avUQRCd>|XnBQOZ+>=$B@q*(`4a z9|_kgOMZRh-aU28gblH&w;sxBELg{B{CAqCY5WgOM%J_YFN-{p^5Q+%6z?GmXb~}F|~zrdcUvS zsroSJmGC8o)``0(#CNd9HRY?_C~~e#k!I1sVujyp57(}Blzvk%qq4(% zk=oCfpZ+->v$-OB?~sq`v&^4@Ix&+zKA5)Qq=#4hRm;aLd>7~b&|ZD;5{Kdg|E0$7 z%4;~@SbXI?9zH|RLG8D(@hX)CDZ;Z(JSbv)vF3wf0IRmD?#`4Af+yF{Qd^We_akHD z-w7|vz63ZeZ5H#Ml3{mLA$`K>50g|C#X~Ph*)TFpefpenwO!+i%>@(L!dn6!J!PD@ zeP(86Tj2%n1nUo58II`X@4osn@4fTU+MSNgiymLEc<=IDvu)ut-&5W{=gfI=LWzZO z&Lp45+r&fLl@u?9MtG`-hcdran{g_Z_uyVv6*;5Dd)Ye8zZ(lhH193_#8@Bu`4UTL z_lf-iu5*MuRPV3^M@_Sq*{{(2PTjxomWT4|OR1dKKkhW)_ulp~wqLO*RC(T|2{GLL zSvCdxN`obqc+||gcczku% z18<$tnC%`7zb+i&TvsNrO?;7#(Eg7%#9vH&^YGlW7t@y?a*>(TG9|JrW3^U= z<*xoMD{p;T_i~Bv@xM>bth&OY9lz~b>E{ExpPUJvV!1A&|IV>|*VTn<3jUPsTEr^y zMCd-tg^5Z}H2>Z7n5?n;U2o|G-%V$HZJxZ-k?<bS(>qE7AYb~@nT={o* z?O;hzSiaEpKqNWr+*fA3 zGGdnPN~nnwvX|D^nrt=C%&FxKQmqA?~>rlW5imbZh8~8_8#bET@JX5&pP+RaX4GFE-1ymKnCSF3LSCtHD{R;Cx!Q^M1R@ z{&}BlQk?x`(~dZHW;V?X}xdiZH!k%P_8OAjue;J(qq`@6td_4>An0!$tbPEJbC#pj)! z|1r{NzK>r_=0e}@qB8F6T`wlF%DIFed_Lu4F)wQF0I0aVNpXKjgeBNs65)Rla*aF+d@ScyX-lTOL$ zehN+G5tQ2chG$~vxmO!5wT68TSglpdbK^?7lSjgW^Cs(lxPP^oq>7-SgAirG&N~3)#xTeg3qT%4aKq%x~;2 zaSeZ3++|8Lw?;7U+97+r^iEqrVCmG(gY65K)zn4`Z|uJIiO_jQ<`q<^A`UwOvsR{zhBo^R~FR`76}!X5FO0bF+^{r}(ot-|lg@u}z4r+~Cn zsUo*<)1bJJ6PBU3maMv+mMyz`RSSd`V!O{7lNalWlgm9CwO^2vdGo?mo#m+T6lH4wQ1s>8*D$4 zZmp|g{w*$j-70D~hpmW;vH3^dD{nG$qKr5eX+PKd>DnZ?IC)cnNcEk=D-J%s*STa( zXmY>qmG9G{j;&rhBlTR=m)WkTcS;EEZ?nj{D6h#n*Z%=mii!7BhQI#~WZn6?=I>JP zt6@39p0}!a7rB_lY4RpEJYNyF(DnYUUs(j&?&>=;d+qx}i<@Gny5$Mw?(bgH z6vOa&%^D?7gQ|(wRQ?{x0H-hy(POl&KIw`t-jKJq5H%? zPYz0+J@_=s_>M+-)QZ-SpZ5DUH!E^GyL--1ULD>bpnT`b-O^)M^5hT1-uUrRcH&2Y zw+6RuwcNkop2D(EXK7u;u~^wvMIxn3ZT0t5PT}Jdv46IyrD2WST_2My^>CHWnz*J8 z&4yKH)1U6Vwd#ekX9E7PC+7@@Py6*>GlF&n3_N%6&(D zFI+iob8y8ZUX`ScW#WQzMhiX|UEiL1uv`1VLoreJEZ!I+%`-ThIFU zREo&?fMwUxVn3vO^qyfHV0BsZe$13CSN^i>1Zgw#EnE%qH=WfNnM_m;U-6Okc9O@P z;-ecjUbykpKyBSr)xeEh!QXQZMPy!FJt=Qml}5i)_{J^A3xBobRSQTgy|?&uV90xs z4rjF!uUD_W{r_TDit43YlN439#X?iMm%MgA+r6BHZ7zdh$$X_IKP|rYA1j#xuGxDT zJ=?5y`Juug9)n%ZFKc_Fo~lpW{a?dyhJ8BQ#{K%84_9~mZmH-DZEf{^7W={4a1Cq4 zA5Wz_S&ibq5?guo3vS<5+;)GPqv@K7Y7>8)&ukaHAN=V4sq?>fPwDJk_37*EW8W1o zxW7o*c$Pj2VCS8@f;yrajcv&WgHN^iwbS0$w zl%Q9}p$)Q;2b{vRH?-x1KklEm)_$J(S?L+8_SbCj7t%1!dKkUdC~n7(+sQT6T=nzs z@3}kSY26#YrW4B(7mJZowxdS%&OSUWHz!^EWSC6c--5aN?rflL{K# z=6`*?qT7C#W6ve$wed`6#PzroQce_K3_gzv*1;9{k<3 ztNYBHRo`#12C&Knmgih+UAt@hwmUwdZVzY2YUl8;JigjD+PmGR?((7yzxjWz`)T}e z>fcZ`rRr0g9*1eInvi*K()*C_)3e#XoUsq&pXJ%m{J44N=T(}f>Q59NQH^#K3-P}F@8+K_+>&#$?aJn94Q+1c~-_mQ{F$eFLMyk_YPnnWqEM~kjg3Rh8<7{qFYhfocKiP|_aIf3 z#k($^>sU4I^RukiW|Gfzxf-O;)1=aOez<@nllTFlw1 zgLIC1zI^d%g6rjpk$&1O`x`#Wr+naFu;S@Fo2KB)hmHREEz5A-&&u^RVaK|@<@QZ; zulWW3Veqq)o$x1ri;AAr=J`u_R_SVo-;KW})x;ED>zMUU`eE*;H9YTP!meiZw4Zr& zaUo-6hMyF2TYOq@e#R#2B@gQy zb}zf46Y#1sA=hT7+s1dz($9B4=v#CDLh|}`NhjQ!T8?hEc+%9>Zxvp^`H@dAF0NT7#=d8kMh~wT>&i0Lw*d;Js(YB% zx)i-hJoNuprbtPi%++RtU8i{~HlJDAcHZ_vW83z%GkUU4$MQ~X(YmzA&vb(FH`lCf zQVV9)X9f7B_3b@zf&D~WkLi8KZ;PA$PiNYvEa}+z_UX&{wUy7dAKTMxzy0~i)i+nf zA9q>7Q9sG+qv8bZEhVK14tvuq**#bo`;&s@tQz)(IIv&7dUo9`y>ok=tGic!bh@MI zJLk}m+}yYu#~u{%xUBrX=TE$LUHr^#ELYAI_Xgkiv31X~7e6*%dj5IAd+v?>V!yZQ z8SNDlGh5ZWv-HQ}S9|yRuk}*8-XRq)?WVj~qrE2S_15d^JM@%u{%*J)dhvMD%dHVL zy4ylFNKD%0Gpj5;BEfQ1TYfv&lEVdapXUUsG&&zo&`hbz^_^WF$iVq!+DAr>x7Eyo ziMN-x&;H$}b!pFP^~+h#?2#oak~Z|ka6S!bc*oo^yZP$I6B~6D98&%^On19`E>m&+ zyDNs1p6=|J=H5Mvk73o(Ju6=?vB(utRS11K=hm$+N2fj8ZOEzd=uygrsZQzJyez(a znqP6dA#zUC9fxQY7Uj?3s@eCW9=Cs;5WKfGsO)(wugaEm^J|JJ>$!)%!=!kHlOO67}gg?)=i=Dc|Q+ z?aL?H%spnbXqI;L1*uQ5meAOEBX&hP&Ax!+LEqxRA33vYQF#Dp%E100QHM`k`@1c&x&&_OE1t!r~GA6J3Wx>e0I#&H( zr1sXo`Lp&<{&jEnH#b+~kJMqE~JA7hR(s$sJ`~P>ww2S-HOKt~E))Sa}b*)K3n0QmM zmYJn&!^00u>lK_*GH0J?nN+0`fBD!v-8W9$;C5N9Gykr^cJX5?Pl*03+%f<9 zi=B5&zE^$gvQ~M&S4KV}>&}P&d4E0T{NphEyjX}?z~jxftio8?jW3^V)A#m}=k~aC zXqt|Nk6_jP(09jDx@TlewN{ATdZPB4_PXY26YfOL%-_D7^V1RE7(U;%FP<@$FUs!J zOptO54wn4TnB~5MC9YYeoV(D&|NO_rD>&yDEO(u8goiUh%f~_F5BrxN@8>%-NR<8+ zda+tw;`%kYe>q>(SQI!jxnC@{-||1GMyF+&Z_u|VPN$o%E#B8VxzTN1RqPlQ4DIu%*bzgs#{e7R1sNDX^;_JlK-LcXPCk5tJTz$vwF1G&G&Zc?; zPEXym^n5+eCkIm#7kEnZJDcuHc(j6zOYrEWnw3!>+n-IV^=V5kw`Eov zFr8BGYTL6mF>57ddb5xFj{Vh@Vh0sT$le`5S?{ly07V_mA?1tkG{Ly(Zu2MVB{R1~R}XC6+Nxv=DM{lusGrf)a5vhEW6 zX%zDRjHOh?gLf0SKjeIvb8A;`pF@feSK7mG)~k>I7Tm5|n=yOZHlycX6_$%!PAn1h zRQ)WoirfFORlzCusnIRAECPi(TP&*OxA|EH8H!sj+3-%N-*NZt&cnt%QSs-hp1aj< zePA6Pez3|$Va_uJ`-J9cj@f0dz8MGZ^RGSnOn>jutbD&oQR2RLS1!G~=VQ|6>E8-I zueP_z)@I&+#mc-Qp|r!SGjr$X0CmF>^^uPuwBPU3OgxdJ?(3 ze6_05y^MJZr~ky@ zwLc=huuoh(@8X47?l%w1Opp2-IFa@6%8gAPj}H}{T)x$8Yk6De@2#?*gjG+LJX_FO zb+uXMyI$pwns0MjYpf1AJ`>!+8dti!<~Hl)(2kb-I6{R ztACvC_UM1&Me*&|%Wj(M);wWx3SVoV@3+C~s{8LdQ-yhMx>Uda>&f-u=CXZ$E9QRD zm)TG~qpQR^ZtBTB>C(oQ5tleS&ZKw#C`{PKaxUn3nES;BId|okE)zMnzU;cVs6gx8 zo2nwk#zS7tpGzivo44h^?ysB}pLAoNzW#47R;2qLHO)PBpo9Caa6y;cmdd4PTH7_$ zOB$|;={~S}d+~|4+ibT9#kb7lb6ty*Wv0H{QYz#)Svx8Awj9TeN1;nXH_rbrC+jJE z>Jq2)tv6YD)o<6oyTxmhA^7qN_xf+4lG|4@MqYJ#%X_KOPCz<0aO3i7ffr`!!biFP zxT-G8pSxhWpvnB+Bgf5WwwG+%B=E=Y_ulPgm$O!HPrO#U>+TLKB`1aA%wN}@1+HDU zO|tHW?xMwYMlWx?lzt-h_^PJF)~^}78-q@GUMl2jGS3aFU-U2YyCzQtB(*1tkNusUYat9$&CQzptCQPXz0z2@8V0{?WU zk53LY?x|V86#csO*2JqZu8X+ehIj@)eRG#XY0{pnib|J0=CK@HaQMn*VU_IQik;Su ziWuuf16<#LZI3DDeeI?kkz&YD{|BHY9f0JTf$oKAg_V$YG zC429)k6qQbXHJXJ`ZoXX=J;FbpD)+%&9D2>;Lh~p{MN0T&#VrPpA>qt`HbyD)icuX z7WYa@zR$QhYu(h`1>TGu6&BW+ZCRmT=d~5QE68~n>frDBwe)P;xp=SVJ7k6aEEd~q z^H(?a$@Y?ol3w$k1n4qsOC8HFLi`wRrk=TIromzS%{kwQGFBLmwUO z?hus?fA-*TM&zUI5%g@K0ieG1j9}IbRxKMAc`JAnSiod9&y#*?{8avJAKaH?VS+;cjh~v$orb`b@$XAH8KZUd-uIP zVrrjr)Hm44bMCLhtN(7&^1Qc?^T&e!H^T3|b9+*{T|y%J@cs8SW-A^WTUqvTd}WrK z)NJ<5zKHd$g8TZC&07zC%~5nOyY)KswPo!7bn_E8@0u!vFX3JNxy0ej{Ohjgy7Df+ z#sh4xAvp`zFkFH%T}hmUhveu_WSbud+#%My9Jz|^=)zY zgSjW&)(DBa&iRz1Aig@x`NU28cd8x?%gg^;xX8V%`qqDY`_%7W-ps6@c0}}t?^(H} zFAId{7HgeyatfN;W@%kI>*KXdJH95vjrX|D)cpST$$jU7IkQ?;+|3C(QM%9WL)8KE z-`S#0PhF?(NZccx)wfwFmuF^%)U*)wf2?2MzFM=7Z^s4xthsK=%T;%ZDTht|5!j;} zIy*souXoy^6V2O*wSObFXkoqJW-@`0#8^bYH^X1V9x4va(@~{OGdw?CYCt5rKQU^|a+OPe1l*U7KciN>w_pHR0XsSce&l*q1D< zl6%b)rMcw!^RhI>Z3TC~R`zw=oPWGy!ld_(O3x)Gc3nLAJ@ky%?>!I0IPXpOesI~s zoRLpf-IFKRO8zp7snUGkXOHGAmuXPzSw12wg^03YpwcL-6eu*}2QM#Y5 z*|bzNblu%+uBmXdq~+4_MdDV^@|-WPnm%oI+}RgfG(&9f@u3Z(suGntX#g~h%7@l7*-M6>&-p|ve`|gLRhiwZr zRp0+>(bk=BH|tl`yzZVC|7(%NRm@5Xt`8YKyF-=1yL&(2=NrxR=S^plB{jDU*1XZsz$4mtnz*D^P| zsNK0Yea<_fCB{>81h%?YO~@`)$hxwGL+JP2^-F}g{hlx6D`*K@P#}2YWUb6!laM{m zmyP7#dCy`$2(X96e7wPNWYj&7oYHD$*{o9#( zt-Hl7tK#GP0&LZtjtATQ*)h@Nm2Ko3Bl*0ecNn;`Gv;4e?fZ7S_2bXq?_KlQCc8q~ z^QA`h+k53Z=T*&iZhWK>;eL1duRi^-->$L2QB2l*XL)bkepqFF@xoc3qQW2Zy*SR| z_qOe#pN5g?rX5B%5~ugA{%e!-b^FAb{R{U_7P`vktfw%wLUvu?F0;_Ajpo^VRln`* zig?w$c2ekxXV0cs`E0nZv@P3wsg?J7S3iFv7Abps--N|1UuT+}Wcj(jOpJMDhfooZ z)y)V0Sf4Fhs8MgY*Y5siul(y4k3PA=5Z~>`o0&;bY&NQ`p@u>>GH!Lj5n__FfgzsdAqwX^fSaU z9Cg3Bawh`=180FpWHAE+w=f7ZGR&GI!N9=4UgGKN%Kn(0T|k-TnxMHZ0|SF(iEBiO zbAE1aYF-J0b5UwyNotBhd1gt5g1e`0KzJjcI0FM?tfz}(h{fsFDf{!94Frzahj*wJ z%P(2vAFxtr)h^TO30475Rwhqoln^R?-O{iyXp^zg2ew#;%C<9+x0iNXPbki*nh^cx zd!5z&yXlP%hxS$ai)oW!pvvl_Zh{Rmj0?^ri_D*U zFMpNG1bGGvtCfvcCQMJ~Pn@#oOfrLm#8Rn%XNFz(oM-CqT4es}q5;#4;^O|blkEMk z+^$~zr*aXW`%*sl)U)l?CDY@c6eQ>gof5tso~&>#^OL8{iZhS9e{wAT5}$2xrG;aO zL-guLPAOO7e{VZhwOzz_>KsQmb^mAGrq21c8WY04p5dA`_0m--5AOmc)!tsuB`bv% zs+PWbv)RR?VL5m3qOEn!iXFlKUxZ&0KOWRP!{^bB^X_+~x z3MG{VsS2qTnQ06R6}Q&Tjx3U~oaXv}V^ z@|}nII}S5ndh`G9b;JLM?NyiLBx#v$pQHQ#h}i7+e*)fq_TL{rxA*(&&*J}o&Heqg z^z%pV^WKf`AO6ffyZ*ZQ`rqfdul(HQ_x$UZr%t*1>kRAuy4J^@xPF~CZvFmzkvqlA zzjtkTxt^Q#|E}Vie|GbZZ`yhF(^tV~um3*(`dgaqpYbmt=Z}`D;Y#s~w=aEi?EKZ+ z5goTLIXUnA{(r~C@B3$ekG9SJWW6Kd=d7)V4t#Rvox6VCdb5Iu*Uvxv+EpFqwQbMF z*7>)s*VX@jp092Ge(C<8f8Jj9bw%|Rf4!HT<$dv6{9$z4r{mw{6xUcmMrm-)RzmzqP)<=P!T9WKV>r+vm^AtY7t8 z?`shgJNZ2^h_5mH@A0TRdvkYhpS`Z=@zYfct7OE3Yya&3H>3X3vf?WN=WhNI)V}sK z^yV6;nZ@TKj^94fVZDCAGU*53=fD52vA&UKne?+$%w^Ukte5O3{nlAmAS_#v{OI>( z_jPNovvLS(d*~cvHA>jbeKIw@`};BrcLib)9ng}kgU$*b3Hy|**-`Kh`7<@YZ9{-E4rap}b39;;g~ zF3*-so0Iu0GHq_|x2NF|Up}5%y=K>~SGRM$GLO$KyO(fp6H@D^ecIO|JV)hePtVU69u_YAGxv{&~$NK!d{@%^rjM*Rx)z#}Ge#mL2)iGSrl-a*K+wzQ7%a-chH#}7Jckl3yNH}Kk;N-8DlKboq z#R`=iT6Ct+c1xI7$MXIu=lh;cdGK%~#(rxS2V`omD8)oQ3@le_oNYMk z+GVNZ$LE|B)c*bP@w>{O)f`3EE5B@e#do~KX;XThckAr3#qw+A7Oc-d-9LNHx~r#O zDT`l<&q%0C`e|&D|7}s5k;Rqn_h%XB*YW&ve66i>zu{R^?x)-pq5F>nsN=N6o9UuW=4cTzS*>c~mV)VB-isc>MOVJ$3u} z4{>L_&Mj5_+IMj~tMA!eJBm9s=ScaV{_K{LTfS?%|L$|m5x;^@u6DIL=&gGxf7-Is z9JTY77GSKAkb4}GTZkCeWw;o5n7^ZA_Rf~K7p|NV8{d(AIT?}Lmo!=BYs zw-);`Z_wGI`<|7_%V~|Oz{GRLW`Wa|7IYeU7qS?ZX^G5P@t9}c`#4FScSo{Tz5Xpz z>+_>f=a)jml7<-zwncur@~Gi=!ttqxVrJ@XQUBs7rv0=kLG!+>%cXDIX7;z)thi?E zSLhK~arDAGXKI-Is4kWam{zC7i?5t{34%$_(+vs$;+FL=>~ zEsQfnO&m%N$ZS0Oo{7@F<<;G&Dn=I|_`J&((er15A-+`4D6$LM!k z@L=LoZfx;l+#=t$j43W8SO3$-fM0ig zJ5uC@xK8X26y#7-ZfW_odUMyLB`upuctj8HzNPBmekYUbgw?9j@Wt~L+$Xv1uRb7L zo2+G|mjB7Qg5Tljd5A^i{<7?UkPE_QE&g1SG$<`sKeiu-6v%oP6hKgpY>e1$RW_BrFZ!vj|-_Q&KZA; z*})s9`a>eX-X`a*;x?v|);xUy7EO)KX0v);rx{IucE|b#YwFnzZ!#2_(kzAM2Qu{D z%{X+iP<|ClK;E=B(brnrI|Vx|e%sAhA(Xh0J=7w~hq;cwk-ahY&^qBCGS#9BYZEHD zO5Gkky`XV|=hNAFn)yp2+4Cl@+4udf)r2X5kG>>4TO0h>f2wod8XiTa&lh&=4oL2J zk|0n%*X_vTI({qu#>;tqSB0cY#Q3JA6^I_?o@!xVcy!gS#jh_a9S^UVcI>@%pX&p& zC7!p%PJE4%Nn2JK9KO73SNY4v39b_ampJV|-}+Hm`9o;9^%}v60@JoAE!~yRtfI~N z?of+-QsMPeuBvw%KK<}+JL_Ah!@S>;zrnEMaBA%Z3B&nITUuU7pHeFP^Yyzo6VvIQ z4i%P$ixzQ5StTabD0Qz}ViM@$DV4~ey;)H|p!r1F5B=u;GPlYrQR1tvl_l(Cc0K%A z&cNQPi}&ipg-uNTaw>*J(zhA!m_5{vKQ?F6p_?Z=FK`?e}ia-9~NCSP*pj?9_s_+K_N=1T3d zWmhyF*sS%Nlq4q_`O$(J^$9VD&q>Kv!^EiOBXtG8}8d zk1;nsovX(1A#g|e5;gZn3LA2shIyD+$u_lkUi1x_rpywadEu;xe$iAXFUG>S@Yel% zm6j=KpPppb@yT!Dw)R~w|J7cWGkWNGsVRa>{?Vhz-ErF#0Du9l6N5>u}IN~VZY z*RSlb=vscOHc`{zX?X6eUIW2BO(!;3+~K#KngL<1TojpY4aHN zhY0X#Jz1Q|mBqbMWZE6EZysse1!cJcF0ap2i)*^d_|!?ccjCn32Lht4&)v?wu zx&#v$-@Idzp4F<++AJ1ox~uQPt{I01l$-m6b8Z4~*v z%c)ZJOK(X3RI>%;w>nN-4`We^zIWi^@6~MfCEBWunn7w6QM-iiGwdom;Jb(S*XKPO zB6Mf@Bo*)G;l0#-?{O5HZ{yTwaUljR;gNsVF#4J-Y`P-vYv`%Ie(~Sj@KeEE%MWQy z`22c#R?v|(kGDkrx?;np^7 z;~OEvyHc>#Z6d?-KC{-xw=j-j$3ry;)vx0)psRV*1LIeoDttH_^syj+@~9= zY&bJiy4@CB5Eb39;lo-H-^95bR$>p06GUrGekJUZ_jfYV$p}95At&U;vSrgvmc{me zeLgjvqe1=G*WDZIe;hqtz9Vq^%MFuxzCQeR$X6lKuk-g&r>Bb9MN!%nH!|K|$=k4Z zcdV!S;!Of=5*;-gH^miJU1FP?R8v(StJ%2b&!Jn~Oacd@_un+k_;9XkVuaLBhtepj%+rf_jC!y?z8u3L*Q<+(0f^3mUS zTa?9pQ_W=@9!wu@L@oc*@FJqZB!VSjT2E0%%&X7&Pc2u<`WX9}w6ULSy!LCJ%gp}? zUe)`j{}5euK-qNK@zmx&?u);eYKb(sPqn_&Q0QD2aYOu;X8Dzw`lZ21RU!N5UyNM% z=IX2)rR`BuT%8tw+xe5*UaxxAaXpnYsyF=2V&_B!G8cT%$Ym7Gc&7g}>E2hS9lPBX z8stA+3N7%RVs`c7nx;1qXJqqR#jyyJzqo?V|<5rRP+{S#o zmJ!lfPpak`^*!S+*m`WojoBK%WN+E)-#wTyYyU#qRmY#5l6PD&@7(tXM}-B94+;OB zu|7j-;^Fvkmx;UVG7~pUD7tI+Xw9n&OL!TXKc4e4XgtZbMlJiIC(Y&$(Ed7+>DaaXSBruLneF#-y->KdLYKAM%7ULEczTAiG)ulg z|Ak465Zes3gLNS$)BQ43G*743Yn+-O_d9cmNC5FyhZuO zmXqqQ>(g@=yzbq^5r4b#V1Sm0BDYP3|Bu-R&X`OToyW9Xt9oJX4&kK=dndg+Giz1e z^aW<0X6#z>)#n-yYu@g&9TOr;l^0}M-#0ni^iQQmE#}5YTgM*rk5L;AT}ko(b)j|Z znxD0OUUS91=SZKrw&?c7?LR(TObp$0e(sLERTtbeGUC_wc)0i|JWC9SxtTfZtjd#1 zS{DwM*eT_eH|+EHqqbe+Pr!lql7xtg?>>~Ni%t#rV4S?8|Khwskoo)yUa zw(rq`Uuiv#ljZ7r4^LdW&sTo8n(hXH z#Awya8wFpq9$Z|({&T*y9*=Xb9>3$F1Lca1KT2=Aw=W2JVcYy$B5co1me!B8X6H&5l09Mg_#7jt7xc0NBkeRj$3 zn-`T@@`MfFn7^BlVDk9=XXRs;q>Jvh-tkAHL^Gr7RUH6y!SJ6 z`IZZh6s9eo=4rt5YO8vCL*@thgU0MrTvz$>MqIw&vB+$brq)rO>?tNGFD7hvmJ^+Q zh-uY?ZF9vJp4uzt}*;-yOa*01!bH=G)-zkKhvBdca7lnONca;bZ`+q|D= z=20C@3FE7tu|2axEtf5Imp^-V?yH&ZpKMl}&D*}v%4l1`VN219Wm+;5TIWRj?XGQ5 zuRqboR-aJQdo{B?zwW-4k$|DXUZ-9K-2iD7?{4mOr-N+D=A6l7nIxd$%VQLj-(J92Dy zxIO*oar^>1-zH5vzTQn2q-HcV*?HcIoWHj@;MQ!WeN}GW9+j8w{4iA)d{oKSpBGaW z$-QpvZw|k|D@rddDc*K>Y1r;uQVelC~={k!QQRE>Z9Ng3H_y zPh<0+KV^5l-aBjm?!@@RNg~su9ZdtCFtpuxkum3n!S6ev)nV-Qy|WJ7X^ZBS`nA}A z-|+mcX-AzUT7J2{DPomz@z^-0`sE?v&WaxccL6kLKt!QSC66cDX zs|icr*@z!Fe?5J^U}k9gkym`&zG2d;kq>^Eye`;azTvR3>XS^C8P-$RTAnF$_Dag` zShzMI?@sQ=&Cx|u3U^+3IN{KmiukEsQGhV!9g7m`5gtBcD?il~t z7t0>o@`TZ#@-XXC*SA@xe60TMe&-#W@OZ0waM2H|kY95&1C`3lUo?Eszs)b3bS%?6 zeAOD+3+KHy7w+$!^3J8RyFgJ^=4_Yxs+&r;1eH9ErH;t0Z=5n?fu>-mXsdrXM}N{j zrHK73?Vq#X?0t8`TBu?2!$oU0O`gX-A*=1vrPn&$FZsi6E7kd|UtJeBIq2FSYoG2V z3SS)Goz7nMZdEhOmXCQySE~6M9ng0=8o@JnU!hC&&2(kii_XhBB${5_^xbjz=j@){ zizgT>iCBGeYi2vLwXNya^42RExmMv}k_)$MXt(EcI4+qY$7v<;!fviy>e@o~Dp{s?eM+`Tev#wZr$+3AtiDO8B&8_5u2Yl@JOXfP<5Y~EdiFIN) zM=xKBkM)tavzm`^S%*FOIj!=dTSva{`7Q=?DlbKpl6~O-L5091bp3+wfe@fq2;;d4@b?nvY z<8F?-S&=vQdA+!Qt36YkrR>qb zD-Z81OPue=8o;vafUVW!Uo}foIF@xDR-e-1%o4HnF|UK@qbu+8_)<=}uG^zzRQ~+L z$)pGuy^ojP#U8UOZ{FTv6q!Vc}36YqC( z&%bQ?<&Ldv+4f0(7eYgyBu#n$`+v)nZ*woc2(UJh*jrK7v~m`M@a&Arv?-QO_MWBU z-qT*Jf4T6sPSurvmprA4UOj0JjEqr=dZ{#_kGr5);O)B|YYNLl+C;vWiG{WW9{8D| zQdJu^E%o>c39lzNjdvLBJIH6H&t%(TrX?UPKDRlz=!-%~e~X51yHxVjj;68M)9+L3FAt=F6BWns^18>y)q~02W>71 zkZ%uDp23$K5-Dd8T3s$wwWjX%io=~ZzP1wf2ReX%SEQoaC@`*@B1ZhJ>1t^*plG8+R8aQ zb+XrWN|m-xo~-qFpB&?=$9G+i$812AboIgm+YFJ^lj>{ zN$THk>AB2J&OWI7kX!Cp-$#?r0d^ms&tmIkx@Iw5p*^nB`Bq0@d)>;(Itk7nv%N3R zt}CsrN?AT_eR6!{{99J8Cl51DHu-nF=5X`Pi810L{_d_HJFKQJ;nb3Q-(J|Y?6Zld zvqC|l7gt)DRn%pl&-Sba&t0Woe-UAMT2gh&cjtAJ2hUgQU64r5{w}tlMQF0)z1uk- zXQx=G%FaDJ;cH)8mT+Xa{xV;|XQ>QDi;HJu+U4$j#Qm_V^N8{)tBW@#haJ7s(q+_F z;OsKB>iV44a~}fa_EgK}&nw^Ob-Ly6G9-eN3uUB%rS7z=|zBz3lNjI%_TO zSPNh9TbO2&@YuW1u6Orowg)9{y{E2OK3?J z??;^N`QZPWgv9`WUq8%xdJ2OIux zjH$o1BKwB9$~~rYPre4)s9wob+`r<|^SX|=qMN4Z1|_r3buzuaV?y&^s~O&|&u3jb zy|Gt+|IYur4_x(VdGuE{xw%j8(-ku&59<<{7pHe$HJZg~o4oz~bhGp4>IA}XtPihD>bI`XfB%2> z`)AwZU*v=@4*Ji3R`AZ6>#6^p7#JAXlDyqr7^X6GGHCjIUR}e$z`$AH5n0T@z%2~I zj105pNH8!ku$OrHy0Smw;ownVdfJnz%fP@OS>hT|;+&tGo0?a`;9QiNSdyBeP@Y+m zq2TW68xY>eC(gjYSncWJ7-DgH>tx$(CP#s``BQgrWI5!n`NY0Pr)Ywe0!Py11`f@? z!cGbtY`?F3D|$QemBLnm?&gO7ioH=4jTr#dzI(kA(?N4%SY#18!xb=beK;`wQ_$`Hn)opr@- zBKZt13u;yeDyndMJpJas@9nI*;%QAgC+v*69GK{}_)6ODMe5dvmRD`{-tp)}*f$sV*0lF0GN&|n zykQlP6@7JPr;z8}uAD_r>{w16Z%xrLJ8S8Yx9In2_AB4{8$ZpwwBhHXW1ElaZ+W!F V;7!GuN(Kf722WQ%mvv4FO#oddX$1fP literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_curse_of_soulbinding.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_curse_of_soulbinding.png new file mode 100644 index 0000000000000000000000000000000000000000..a45e94f3c51fec4ebfe069d7858793961b699c4d GIT binary patch literal 13480 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 P7#KWV{an^LB{Ts5IlvsE literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_curse_of_undeath.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_curse_of_undeath.png new file mode 100644 index 0000000000000000000000000000000000000000..fba554f8de1073626f5c0879649c332ff2617aee GIT binary patch literal 6870 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 E03UxA<^TWy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/decay_icon.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_decay.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/gui/decay_icon.png rename to src/main/resources/assets/ebwizardry/textures/gui/potion_icon_decay.png diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_empowerment.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_empowerment.png new file mode 100644 index 0000000000000000000000000000000000000000..165092d43698d6d0196a7ea54ca5543a448d14e0 GIT binary patch literal 11629 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_fear.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_fear.png new file mode 100644 index 0000000000000000000000000000000000000000..de0039ab63b3d2f89631b876fe6ef09e51d8c6fe GIT binary patch literal 12325 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/frost_icon.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_frost.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/gui/frost_icon.png rename to src/main/resources/assets/ebwizardry/textures/gui/potion_icon_frost.png diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_frost_step.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_frost_step.png new file mode 100644 index 0000000000000000000000000000000000000000..d0c4f08189ab9b74970365f1ad9e72e4d7bfc8be GIT binary patch literal 14405 zcmeAS@N?(olHy`uVBq!ia0y~yU=RXf4mJh`hOl#e;S3CB7F8h;B|(Yh3I#>^X_+~x z3MG{VsS2qTnQ06R6}Q&z&77pNebbWP@~d}vAF$D3Uwq=WqyBz-R;A6GPAHwvtekG@ z?pC#fIW23ISwq_Y`TyU~`2TbM|3XE#{3I>Y?Q?Yh9~GPZ{?F1|-{bf1x0ZhY{=NLa z&!*phzkc?cd){=W`nK=qXW6gMkNdt~FW~uetGU-N_j7Ok`}5F`zubR|731yYKUDsG z-P}|ypI|R;_P2Q91N-?h_xB&K)|nlxYcHQzcdyz4e}`Sb3l$=*jls&}nF z{y}W+*PMGd4&A?feb>L=_5aJBKYM-6KKkG7X?6e4{yqHKzUIQKJoK&Kzx7E|6{+~ z!d};fKXZQ=zA3bOt$eS%==2#m&kvnovtO2dZgcN(*X=Ro$KU>bUNSklr>^?j#cKQ7 zg3BM0QjKTLFWfW)w9iJnwl!*U$eLVjE<$Y{r26t1}*(7Xt z4o~>)UbMeQ`%W+49>b5%KP!h{d(NaISUzEgWQ?lS>{t&y>*zh^M=ixRZE~C&{ax|b z!EHOH{CT8S%cHp2vVw8`+3zCd_g_t}*Jp0YapAi8U_z+giL|3LHp~~&HoFq+VYqZk zu&3$PE5#>1ZJ6UNw&g2R$#% z+n8);Wws}SJ;vZ(_W7LBBWiEwd^=;-AFguVS1tEk(JjL=gS_XL3-4Ed&wf6M^Jjhf zeIDtD|IN$JWxW2^J@@zTeSb5rhwX3FyCXYEIx8^uz;8c^+8r|IF77icFSFRJH!c5& z8uFSS9dB0`Lv~%}t=LT{_f8GTlb33#!<^K_c;6V829rwUH2l6`5oV4=Jd?@ z)}5ohg40sp{_@z`xVE^zHfiJLABNtSRI@pnmjC|#tn8}SC(h$@WMeV*m>X}y zvi)VH%JqBMe>N`8{VrQ`q*G8j`DpQr?z4Q^v+hRx-8Lt_I6+OBeShrNy=Qx-u8aDu zXS}v4vXm#o>>7*k0VQ>_S+A4ie|OwgnSSln&Uf#Q_x;;(>}&{AoBAi7+n03O*-y-U zd-ne)zQx;bJUsLv@%-aRJ$ZIU&9eK8zW&%8J@M*O$LQ-xVzo=wcFyM0W}jAf+-Q<# ztHhJn5}I4%u1n5%t+*xO^vezZU$3bQ^Lh8=&N0ci2{#{akp0fJoTce-+_^KmPkufY z`B6~MIDM-06x;9%*8W8wpZ~owfBMEz&8z;^4Qm9M?@udQIk{h9%Dl@?Nts^-X9)jz zP^}X1_V!ubT)TPNf@V?XBg(5C zIXEXrpTBUh&G(F)zl<%zj=v_S7k!qzV90zg*ZL(?Ir zKhint&S?+zv#gaLHWzHJWctS&!LG>8z^S&$GeR*Yf8)BmtX`-h;ZKVQ**QAjx2ue zcec7UB635=+|BwfEw!hPv2WNDTXZis;?Zn|Z%_8U`*n58`q{IelwWLqBvW#hFZ?7nZ>@M^2V zwue(5bp#}o#~sN#aAo1i5BWdX0vD(+-VkbbzDj=Y<`;J^o1X6UZ;nbR(h(Ml@1D0% ztX5b1j7v^|sNAQ7t7*$!8)80fQsUsqUEAz<`)#ERlYewY=J8c!$Lx0KC{C(AXv&~g zBgSpV;_cxgw|JwUfJg$*;~o8MHgkBUeYsN-`ECoBGNbRBjvJQe_ijEKmw2mAxUV5_ z-}9*6{T%FfGB$s?DY|UKyY-W$V>%tCL_9sS`AnpaPb!Ur>T33s8!t$3xWX|v|Ag9mM+vVrDtZQthfUHq&(>X&?Z~+9 z@EM`sOk%Nu{N4gv7gl%Ami@@=v4zvun*G2nhQOM?XZ96GF#Nyq`4&fX^YoVc|5&ph z3HNh9G8Ao6m3Wx9bJzYSOXrrYIwUlkQLS41kV(+BL!oSW&=}+t@zO9kkyW6+s z{t|Aw6s)udTY0xf!&1@H-!17=1Kf` z8+qow9NTRLzugSHvlhfKt}Al75~|IyObJ zyN@N?-{#io?#eqb;{zLC1*gQkITKX3Jv4NQEe`X~s#W13QA0*`)ppFDnSyGr>H`>w>YEeXm%G zY-W-;r}%4@BfPmiL6X&oKpG5|KoKVXYHih`?`N> zs+KhcvOKa@*uiYcQQH1;bCpZ*p5#Tj4teq&O2-#TewcJkV7fuxk@s!leNUGkc1zgm z@`$l}$HcvnFX}aI_@vj|Ida74?*X1yyb*UdE*7s}vP|Jkam?{&PG4^wYLk8c@kVs7 z{BpOlXW4vV+xx@XpFik-!JNmRo;5dC`eN@bFOv+5Fhf(xZLY^3o?+3QE#Q6A>PA^n z?&diw1RLgrGEZDM=hR{z_bchscf>@qWhk(1o?={U#9ed$Z**B%$V2~F@rzHaZs;;e zvrPOZ{(F8^mN$!$z(yhEC($geM-O{NeBQL6=7SWA;zY{=_ShTEEpGas=TAEH?_bN? zI7W|#HycX(Yxs5fR&ZL!E3FniqIyIk!Q_Q^i-tnV#id?%%BDx}E)?0e=!>t}+0fMc z8TFpW_5S>}X&<(( zP2CfF^e=m#nbx0)d%2ZduYW&k<+oyu;OraMZvKgSqhC1px${;JC;gdR)lG>!B?bot zbOK(b-g~i8_S1C#TcY!LtCFr}Hc2xGHcBo3cBK7UR@f;%s{>Y#>$|rqpJ`-YaJ_xm z^FsX&On?a}m9zKP)(`A;~@8*i&T6jQiZpz-Lwvefu;&O4XcFx2KTE|G|z*?T*2YQh`S zgNhrC%deW8ncds))myuHTZ{qQ6N7gvxdPeN+q`1_z1~G@d%|=}*7a*Dd0*5`@xJb4 z{r#x%G}+g}>5akPczwPGjCL=+zNY?R?6V!$P%OCcGzOG@kNeD?XQ2IUF(*U6aApELhw z$j;^%Lz~9so<}UK>)#v+_`x^xWYrH%tDim*)A)oo?5OeHW$}h7 z-~FUrKbgLk$*pj9;;hy?WBBc8Wx%sNCarh157ZT`d2*A-&S($I&Wb&YPINqy*_9un zYxDX}%CfoNjiF%!k!J|U`!bA6$ z6PzaJ#bkJh&+EDCc8>YsnpaO|U!3^)kJ7K0KjK&I^^<=l{@O6{{z>soVYl9VT31$n zR{QLsLkFHKh21q`;YecN@w{b8>4%!=Nv22m(>r7DsK?Z;loC-0EaF;n`_PeZ7O_@m zo$@x=>UiyvS;U+l9`RV$H1Ba#ioH9J)-+EeB?+lVuihs3d|KoCV^dPK`QsC5duRD2 zzSsNs$ky={N1|-DV7q3`i3jWA6kDw|U#y7Jn{mBoQOm;pJ0zBxD`v!*X-4KtRqtUk zaXIpTS=WJs?jKK8i1@F3z?u81xuG$?v-+KZV~xhg0~;USjSg7-*XveThG^9ir?U&> zS&P_~y}i1@vwG!O-s1&6a=o!fqgkfsYD-V+F$&v!B5c*vsVm=XstMm_C|~h0WRi^2 z&G%)|WwS%sosG;_otT;{+3|5d!_ADDkt6a zW?jyj9ob4NoG(>PE4MhJ?KH`Kg6HY>!h;`;;@)jqu~{zboDlNDUQlB2cB$0+or3R! zCp*URKeE%es43~RP}Eo;zk2h$m{gG+*E4M99n@-=(4ghyvFTkvtm@3pI{jlx?D}?7 zi)#h!gjHSd@_g>{sj&Jc)2}GTq_FBstjcE7lcrO>A|x(*FZ|(N_}~-w&*-+0<|36D zR#%wsa!MOW@col6O#H#Q?8!Efy_cdwMOrerN((Ebr!{P0*v`I4ZO3QTCcA^KiocIe zfB!2g~p1#tJdu5ZAq8C z{f}Rfi~X=djq&u_+|@2y%CvX_ID$^sK3Ep>Z&|!~%#0h&(+?Rn>};5D&)k2V-ZGtt zhZmW)c&0Y}Td|J)9K$qz=b*~==L)A%zS^z$by_wd=YgyPYv{puDKgJ4?%+Fq^jYHZ znrW`l-#S-6{wVj7@7tLlJ;fTfjq(SIH>_`Qa1>vqsy&nSlkQs+Zcl+pZt-3!6+ig+ z0uQ>)+wFDfP=Dl`=#%YSee0fBJ?W|UJutsQ>(R&X&y~lTUnVd=5Zw1nhtDKjdsV@j zi)wG4XBDiA%Q4ro5;71n35t~Je10%*(>C)L!shaSgHsotY&r^vsw zP*OT3&NK7tDrrgfoJF(a-+9hl?tiPGeY)wJXOqoZR<|Dy?+>xv$2m*zy)>V5Nt5o8 znf%rlDpbGt-O!Z1^;{|MsH{kGq5V^q-HTZExalzFK3yledS3~%@eR)%hbj$@u$kPR z$GNjY#Av>U*(C!nvGv?hOE-iqoFcTzUh?FjqIEYzE8AmSIBVXWP!&v_vzw8vOUd-0 z(wnuZt94Gb<*PpAXo%2Rw#xeT5l+XzsVm-b#EB*zFkAYi`W}ZxLC=fcwxr$;DTC6h zNpn;-9A;{;*Un;_73HKj?UUUid#1mvkM=uSlrK5P$#Q9_@7FzITu!ol^A7~fFcau~ zm3!*-d{F2+Tjv6|Fg`iKnozk-tA3oUS~^`W z%E_}WIFSGLO&i`Ifrd96$#(H`ZM>KZ-SxDXrClF9eZR}@Mv0r=c239G;Ly9WE>)~c zSfB3OIeqP()zg26UM;i=bdmJc5S_DbwXVV)mGu?!2SwGm7@U4jdE8NRS6L;%*cNeAXx|eckWqsx_77Xha z;prD)UbjQ>az;eMrtqhUn_9k|)OuF6J*0O=+UfZp;*|837;75a$8D+;OLhG|?U`Rr za{s=M!fV8KyX9mru5{D+Qm?%3Am4g_362*T`dju&G0xYYyz#u#o>wVc(*Hk9jWy?s zm}n%TG_ z+u-!x8Q-@4`d^Z`l~?!tTJ2<&ReJN5&ewbMM?; z>1+2i#T$+tnf2UVOitBf{SDW;WN$;w=E^I&>E+E=*|v$O1bsdm6dHAP&clwXy}R5p z?s~CkoT%BvEWy#3sBo+!Ce|RyF@u;>H56&}ZY7G4x zalj#T%>hG}TjIYL=xgbno37TBaB9Z4FW(k5yj)?nGsK;djiqn}r%qF2$)T0Au68QC zvFMVVl_Dyzae49V^#Z3>`8oN|Iy7;Y;zuK%k9BuzH+&CX`Ri(KVYTj*YYw~5m5a}J zYx=tIxb&Cf6^T4Elu{Zanhz-~nI65lFSho(EuZStgw&-WKUGbbKOFg)Klz-b+C7&W zf!d3{%=NN5V)#fqiT%}s(~}r&iZtJSJ1M*(NXu?<5SJ7KYo`M9vYbb5A)7<2S9&?T z;N)4P@+WE4Q>T;5t&*5*Wfb?XoV`weZAj%)pT~LqOyTc8JUz5&=eg#c7EIfE65Y3% ztysC(+hJbaU)$P+jI2v zKhBH~{j%wS$<*BnQQ>!l`D`Xgb}SK^yGeI>;o>7pB4b0NgDx>Yd@l53LVN3(CeKwL zdDg2wV6;1N#-LPNXVbgPAAhe3ZV3HiFVC~1ujR?1)P!$0_rzSRjQ?3Tck8h`;z!s& z-06=zRPv6wF=PGuV_R=~PSIO3^ZM2A(Kfqg{$5|v@@9wUo?6>dE$>Yo>k?+2G4T4g zQhMeNvt+eoY$9UN; zrQTiLJ3ol9x-~k?p2E08GqiNYie8V>k0yGNCtlq0*>Gcd=++dciPzs1?@UqH`=hbW zktal;O~z?SqRlt^wgvMAPyDfEQDl8@7pW@JV6;?kxfBy)^tOoJIXaa;-n!2Dwzp1b zgXoUfI~qrr;+A{qv^n`ICTtab$vCf-@q6AZgO!c9ZPx$TEbCVtw|rIA9M0wQ{X*L- zek!{MwZ`2QldB9`yeqVNrdEyYWcJeye$R{@p0O=hzUPte&*}_MFTqnQ&E!@et5un# zD||6QG#Yds4^{w`awdV{kfAM&4|K&rDOZ)^rP65up_dXvC)8PJk^wB1vto6mN zSKn@rZ{YS%)GL@KZhF6#(Qnb7Ec1Z*PI(I(Y$t^EyFN~_UJ)by>66Q>iYt~4I~OR# z3p>0I<%!62y7v3+jjQb|`Ru3ZG?o_IIaxjvoAyOrMVy4LUZiiXSpAEC>T=IlUk`szP?IxuWILF+ zjY*5q;NDxNOD<0$v+lQXRXj`c-pjV4t^Nzc!*!dE?Eg8_WMGrf#IwcFdo ztx6mx-6+|?d@SZl`jRk>-p^|mu4{JlXgvKR<$22@i}yhWT3)LRSw01Kepwe$(4S%9 zux>@#xm7Rh7p`2I!^)8JcemuS)$A|Cnl@GX&b_s1vEJqS*COfL+kH}%>Qjpi`j;dW zJ_xv{lIS*b!WG{2_gFm-KabL7OuWz>=^(YnWwGy?_Tvik`P?tW;O@n-|}au;X)27S3OvdMbfmaH4ojRQbwK6)*jJzmE6UeEX+c_Fv#)6F=`$xi2#V z%e9#suf7uc;QWGj_56?ppTGZ_(f3iv*1gI9>cz_AVVl&fZv4O4e<`}AdDn>qtqiTH zo*U<{kK{AIcICry!!CKPEA@}ut3E3Kuh?g|o-LkhLXFiyhg+h%PyL+7rJ$LR9ps z+^?MnO&S+{%{V*vO2n$`8+7%5e%bkXgZ-Lc_kLs~E#Npd>53np$$XzHlh>FzGfOT% zAh_{jO>mm?T&Deb3zpCNSbyh##x8{wbMD=a|9<_?orH4l;?#W#!fQ9Iyt-UK`^F*P z{aoAC{rsO^N@@Q7D@)SN#HPh2^sD*Bb+*%fCvH1*HoZpv^wGSlieJ~*-#NtZXT3+( zk2lf&%>LDPK0XbNUCZPmtF&*gby(y$n+ccxzX_{8G5~Q~mw_?yjx0 z+uCzy`Q;hsr{8zF5z2SMz420?v_?03p`XXkWjz}XdpZQnTKw50>zSaUtMH07@s-i; z2_;{9yri7##W}=v96p>(>7RYl&GJK<5*w2skMEt4gU48QeGx>O?7E8422u+c|SO?mICI;FEs zJm~@_PFl~eadud^us`F!@BYU}XQcS%hd@pOvGC zv+)tmS9>lk|0(@2fWxF}OYzC$zx>zE)8G7;U+deRlt)kE=0D%qapY0B#`M;vn}LrU zSGFxS>bg}Tc4nsdq*)>c5&{FYML%)y~lizn+K=2@c;W^mRtajIK4ua!+H7|3y4+?H; zF6G|4)5dm|A^Q0H#-p`g?QS25X}WcxW$~VQv**4#c13h=k$A?Hn^V8^MrUqlJ8{~} zO2ui#(^ZRAzU^gcv9@~V6I#h6vFM~(?|sFYv$GZzU$>ggc*;7jO1=0&?uMFoCI{*T zPkYTwSUqn=SJUaznE7n`Zi zjF~dMrCp)^O6iIfmoBzPhVELhZ^vBwxo!2Q`c_4|Pwh(zbDnr&Md@;(y`fA0u3dF% zTbIDAwxboo^OPIex0eN9nBRBHz$VLOZOy$i%NBi`7rMo*c8&6`fc#be%oZ%Wef*pH z_r{0~`!z~^t@A$Se7#!}E6>d(uXyLy^`mdHccpbNu`^Zp&CMHkX?fY_M&_?+_qb~k z85g?ia*1;b{`<^8s@ zuS!~bt@F(){hV~&x_8XGDzrT-M5NF;fA z40)E@T$TBwKXv%edaSxM&+7W#6Lp_u?z>KkSG{*%dykuHoNLMb2~pcW%s+U(Z0Wff zQrz3;>m0eaINCEobl%lTYbVB>71+?sTxw#P()gs?ck=6%D}80U->IHZF?Znj_<`k9 z(9|ERPiNl=pW?aK?_j2p@j*9{HK~gm>>rh`cwQ$Mvys6!;q7FZISk7R_O3t2ReIAp zvnB3{Lc9h~SGLxLFXq-BAtz4MOlJ{0cgW&s(?tcVCku{Emw)s7ZFER%l?MC5Y4aK7 zG8tl2(;vvED@8FMx2&j6P7Hdx?t#yCVdF;%KXSLt-Eh$O-3qJ92d_V`nEG(%17#i$ zjzyt6Mc;=_5ad*7x2Oo68geh7`uvp~alQq-t1XsKDpp&Wo|5zT@ahhJ=l3(%N-Fx8 zp3cs^t-~_S>GCx5=~s8uNPVi=v&{Bihue-hLVor%8**iOHM%Yfp3@DPHvJ(e1#Sd0Ef@CO^Jb$7l6o)t!p`b-pJT?c-h5zch$3 zdYRsZrdbKKQpa{&&EhG2|7vH{VavCtWkVS2dF9ijUrl~0Dd2KqYXJ5y)yi#IYkjjS6qvlC}w7OT$mHM~v9Ct(TDW{wDSIhp)m3CK2Xty$Jls&@dDF0)< zP??|FHC4XsZ|+>5d}DQ1SDy3V^6RDReoMhT^`Oh4GVW(txBlI<*LK#U(mPGuQPqpY zF1#=t|Ef-KQZ*|6cfnc70Ikz3^ej4#%p}s674^M~^J?+je5c_FWer2WW@+ z-PrKm>g{stvp=i01?irubxFN%G9_YaUP$y-+oo5`HodHuT5;o)SK_P-USF+O*DY!^ zo6gq5yYv+~K+GV7|eQ(0DSw;dP>%@2;`W@M*W~Q?K zosYq5p`xF!m&~4&Dw^Q_zEL8NL*zkA{*33Wyv2*#B4$YOr~Ik>$oS7J{Z8c7v!5cq z8kX=&&Mm(*&$MZIlegUAV*!1$*>-I5OxO6*qw|3Ck!)tx-Yv5>=p^Y}{GE}dZ*?

    *Ax5Oo(_}-|I)xcBg1Nj( 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 Q1_lNOPgg&ebxsLQ0De-OGXMYp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_mind_control.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_mind_control.png new file mode 100644 index 0000000000000000000000000000000000000000..fcfe155841865f01fb158cfd8ed0db6a334b7c54 GIT binary patch literal 8152 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 DtTu>; literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_mind_trick.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_mind_trick.png new file mode 100644 index 0000000000000000000000000000000000000000..99d59d3a77899385a40aa4441bdf9bb8263a90be GIT binary patch literal 9578 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 XJ)4{}k6JS@Ffe$!`njxgN@xNA?P=Ux literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_muffle.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_muffle.png new file mode 100644 index 0000000000000000000000000000000000000000..40ae2462ac7bcdb5330ad1ad8a1a36e56cc1be51 GIT binary patch literal 9869 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 IbxsLQ07w!fYXATM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_paralysis.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_paralysis.png new file mode 100644 index 0000000000000000000000000000000000000000..8225301ac8ee3d9bd34f761ca3ffe41a7510fc23 GIT binary patch literal 11924 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_sixth_sense.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_sixth_sense.png new file mode 100644 index 0000000000000000000000000000000000000000..c8bb581060a881d3acb26a2a4122fd5c16624a31 GIT binary patch literal 14563 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

    UqRi78+POO4Fq?e!(=eLqP}XoZaqH#73tw3= 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 CZxp!z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_slow_time.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_slow_time.png new file mode 100644 index 0000000000000000000000000000000000000000..a91a7fd57f9a53f88abc42cf6b930682b4c48e0a GIT binary patch literal 10784 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

    pX7hS$jBo>eU$&eoii% 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_static_aura.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_static_aura.png new file mode 100644 index 0000000000000000000000000000000000000000..8549cb1318096d95f806ec1b90a3e706c5199062 GIT binary patch literal 11658 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 LS3j3^P6^X_+~x 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 ZxV|i3^YR314+aJX22WQ%mvv4FO#p~#to;B0 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_ward.png b/src/main/resources/assets/ebwizardry/textures/gui/potion_icon_ward.png new file mode 100644 index 0000000000000000000000000000000000000000..ebcf28447fc648872502bc821381a63a860c1a2f GIT binary patch literal 8631 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%0DIeEoa6}C!X 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 WU`NIu@7oLv3=E#GelF{r5}E)6c_CB) literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_book_advanced.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_book_advanced.png index 47d76cf696d9fe779110bf0fb085caf2682459b8..72b51efd3f6c6b001ba0a9ca5af6aaed55721f59 100644 GIT binary patch delta 11181 zcmZ3Z`6G6Ma=qm0s*s41pu}>8f};Gi%$!t(lFEWqh1817GzNx>TW@DamOZhkYQ4Xa zOP}%c2AQ7c73^{Q_H(;ws4m^K>ejpC(>93&v2Y6fFJPaL`tARp?}q=6hHtz!dxqCp z-SpGpIU9eT)4ysL|My>s*}eJSPw%fUj=yg%zrQMudHutm3!YuCPni9^bX)yi`}yJ5 zEA4BgR=mB={`fWfU(*Te*K@|b->=T~Zsvh~Y-WE=13s*u`S|nqifO6EtDk-rdiMIq z=U;!?7G`Ds=~(z<&L-`N^Do{GDti3=Rj$sF+?P(yJ3rU^eEFOI+3rfQZyme1j{W9! z1_eJCww}v=wA`+8|Kqs#SDt&Fte<8+?at0`eXrx||6ZLs`}@-ULH|^je&b(xZ+%1k zxh*>xYvqOZrE1jg`S)X=_x^k4^Mk8Cf6II}$3E-L>EG4+n?Gt7KbyO+ILtQPe)Vg^ z%}@SBU8(N;Zr&%|b13B-puK8X){5m5 zlDssRPs++#`Fz6FM9b+qE^k$*L{UCbMP;wv`%}!}&XpI(!=khI z8fT_IId^j|b5*^3U5lW*ROOUFcj?+H^}QuGqL)b`3rw{$lVYK&b19aHgmba{iDxsUoUja`#nd(ZH4Vk z;YEy_KP8>nc|9ldc3F@;&ull%?)v^?ddk;jZ#V9FHfL$ozZ>bI>#En6Ffq=nn|VPj zd`9*8n44CabA-a)>xw2_u3<|2+u^dS*G>8MmB%0Ee)-|k>>pj$rLLb{);E!79fPTg zYJC9fgBiE?Ua4z)%Q$D=%*tfTomV1vicIy>+`Yyr_b6-LY>{(***gob6(-Nwc8X(i zJ$GJmucV)MgI%Wbt;5&nguSr-#wH(FDqIo2PxP7bldo@HxpB7Z6fS)1WB<)3{k)+= zWK)=B%N4!&@DG!@XD{BkVzaob_^op+r*q2F)ODi|*U5b~O?$ok_f3m01|9l^XHPWf z9Q5mOQ@9tJo7Qf@w)V!khE-lSLaK_}Z(O>0b6q{#L!a27`Kp}3Glfo?WN>q-zA@NQ zV!i5O)2_4GLDQF~{(Do}{`B#jYV-2RB6}8Z*|j|Rv1CkBP*!;V>OL91lOOn6a#*Gu z3OjTBRqouYUi$>OcMEowwprgk>g3t3&e+G|Bg+`=-?t&bY~xLq{yIh5)lC9c4EN;T z&MEwp#3Q9uKjD{3=>kpblS*yD>OUt)M;HqVvao;S<96Eqvzq0XaHBj^!?RUORm^|A z*sUA9DEo@Y*V%5NHzzRKN7$LVA3y)}mZoLovgNbCy>~6#GOdy)Nm<^zA!+99Q+MY{ zzKV;xX;XIIxqYGX^J#en&70PSgk-6od;Dfy&ABIcmpC5ZA$XGt;G~jEmW^CW zFKm~3iB4Yj=FUBj5c?lT8igOsW7eAfe#wCpu?sJa+H#c@C90$@%V*5eio5xodFr8t zZnyiqrF*lOq{NtACoElbR%_!rHOmLeSI(MjUT2XOGly-`VL{7M@9fL}o|ImGYsMLr z!5nIA5&XF$+v2*i?`!su_w|1g1rAtG{Ce~VE7zUUn~SVot}tORExW&|)x?i+|945{ z#m|JYnHT$J)~}iu!OtA9O_4_|RO6>yhmnqouI0gyBnPvw1?6YIg{7DXs`u3A9lh`* zcq7a9Ij0W?J=eLrs>)BMq*^3vUp4Q16LTN$d6uW5*WJBexBk6UP3VHH>!p^|tGyIk zRAc=j`u~jZr~6;Ub(Cn&Ur@7d!=22)6@5|~%*UEF_@A0-|KgMkn_#N@r^lH^;l9zn z!@+g_ir1f?(wNo8boj=cIokPr%q+t1^lhI-TDCH0TnRPs=h(wndc(5indQ74*K?)>k19F;HpIMf{qWqeOQHUqmHPRgl|Kz<8AYC-&&BZO2g4ly3g`Iq z)}LH;E2d@{6sTD;%zpjKb%~$B0?o*)72nu2r<}-tU{ud8{@F?Vm!g4*&lD!fa{)yq zCAA-PSr^E=It9J>;QP}zY7=Yb1HS7;Mw~{)N1J>WuszyvMe*xQp>s2oi)Xis>UPe# z`D>Cx{eo#T%{q!3qDw@U$|au2(KIlimSSxvQowTN}niK^MD#+TTRPe@u|waNFU@q<%q7sM7S zR(G^m`<3|5s9YXZGf^s~a*DyBljSC+huC@DnXl9c@!izl)V7Kx_1c^j_a}-=&00M( z%S9z!`K|ENIX{j+s^7i-&*kjx3l(xM3RxNN2sNlX(V(`e(cZ!C_wP*W`7^sor-lTNBVOGEB0{1Yz zSJOW0K8_SV_F|QV(QJ+*cj_vXe2sJN`}MLOjc-tnP*Zwx@%)7juB3qacME=WYK6TDIHsc1ul5*P>z^-=zVg-#4BrW%8D#J6)AD)`6}KCpAV`Z z_^fo*?N*WLBG%K2Cxlf5>KAbbd}*lXxppnUWdiTPlM9&2QuO{@XEVFl>|pKH7o%d5 zs=0$<$;IPmuI+oa&v^Fdc|UC5&YiNl!asYzPfhpt>t}AYR6R3$f0A`)dDX3(sg3kTDu^m)zDb78;cvxmp3ltI~G&Pwb4&a@kke!Otiw=4g6yU9f1 z{p>0qAu|?b=g=b4D;)2188Y%LSENi&5U{FfeBrh_WFqfXp~aK+LX#zQqn0c2Zj6ax zW4){5ZN|Qa>1)8HjEq^O5BfIf1jx&|`gmqMUXh(#KhIce1=|H#&x@-rpF43vFnVu6 zo_KT6B9X$KJ|5q>*QdVQlr75JwDH0F;1@;&YGKj`|(9ldm54-73JlC!MMEd;Z~=clErN16n?ai0@e_cSP$N-!k@W>w;Aq z_I)%}R9e34_m+saJxsq6*p6X@jXw8e!dLrCPnSpQt}n0`fHEeR_D*KP};kDs>O!arppTp@0~u^cyKoJzO5S@ zcRp-7DX@Ia8$Z!X$3?ehG`*-l@%B*SMfDQpTB%&~D+&4e=QQ1!R=Y%BT-vv~eag8B z-j)WYtdmz%d`S7yw6BGALHm|PlfN`8S{i3f3qp)7JzWedt|`{tFj=(1)7W>CvhU2|hbO%Ey|^89SvBd`*ZSY9 zE9(klrDLZoWOFrW%w-qul-AqwVaf^S(t?mb?z8zmEHiy_V`lc_PrKK)d1PI8e3Y{~ zS<>fW*9^%AJhg0RCyTtXs-15X_=)%9gqW8Zw{^?6L>@QuHp|lRd}&tq^VW}K@9z$$ zujD@awMY3M51)^`jOom&@3Jc<=07*}U}Fraw_q@k7hnu`^Huy2m$2%Y6dp3_Hy{~^T34OfWxn};c2_2hGyl^lUUv%5BZl;++$CURO=9U)C z|1wmv|9|@$?kS~xz4Q7(YyP^%nt+T&nJF=<2byjyP@cQZg`-hJ-QjSnS&zxGvV^pV zXOZRC7S{KMHa-sb2+?oUZd09~S ze`)`(BJux&*HQ)jd5wQfHWiBqty?)^ZA-dCa@^jCRFjF(x3pY25|%c4Eq{AhOt3f4 zVEr4zOt!aY`?or8w)k@S<&SJ3;Vtg_+m253U&Y@3#rm>DeMr^itrJ#?-)y>MknQWLMcH_qRmowBn z8V)fCFe%P2G4@Lf=bt`*(jnd*J5Bu8{%l=vk6F&yvF{0gK}(Pu$C~9wAI^XD=6>n_ z_2ykS-puV*Te|LTcl;#V`hbQ)KFb^}iH-&{oqxv*_-Zfa-IBUiS-D(T;-$ufPQJr; z1f3XuT1DJu;PUG53U%_25Wjimr-Rwd){i%0FTAyhxhR#zBDFv?)WM>^>h+4(eD9uz ze}37!@p{b5q@Nr35AVFq7bLJ`|JQ#ZwpSPQvaRoOzbK=SG;2}xoaJUq{EO=k+*~7j zWR>7@S>qhO+C0(U%fbw&KgwC7aVkNnebKiCTTJJcSU*;g(V6aNnyD@-*Sl}agNFWj zs#f_`FC%i|c@MBpPWi&=v?k+uWyWurrX`P8t`415^Ih+NZc4Xc>Ap%6s{{2ZPje4f z>#$4B5m1Y|kbQrh<-zvNL z(doYSOyfnznD#il^?Ecxi)DMjw);CSUfTI##sc;UM;{+y-=!Zc*;u8q&|bp8?N0s- zgKzIYK8m(Hls|vxFW0Nj9%h|+9Y5{1{3_m!-`o5@PygY0b^pQO75fj0@kn{SvUzJB zRc$`~XMM5szm+V<+sf~M&?wk*BSX)^ZB?HP^HBME9VBD{HbcuLIqrl_jHF?Yp$9Xm6TO4B628ed7F1ho6<=guk$`B zH4-VSqVMavv840xdM}>c!nftJ*sbhfm8b+S^KG8Sw@!t{^yP5!!l^5q;_q+o^{e}!@LiRvR?|ln5MWg=1RqxlHSW}qZW!i<+^-GSY^t@_he}kEMDK2r!-iGC&gly>7e?qs=q+JPoRWUDyS~)2_Qv7N z_5a^-%Dnh2@ZRur@ZI-^P8O#<-pm^HZN(IIPL?%|NB>NA|FfYZ)=k9pP)o{mQzyBr zQ}~~n%RT+RapgCCP5VvXe1FDX__6Bmtal=T)5_uxi%(P9+1R==dY{D=sdnQP{Ab+T zTcnm%m?rhRH_2MenzkbE)x8a66Th;YtUuJ_*&^_b?eT)zUr|*7izK(#9NxKT{lfW; zQ-zs%Q)NOd#o|<%(-r+K&R%UhETf zjPwyXd-waA2}v6iHrg}$k&+hO3`}0#>Oo4KtqLjTcmdfSFe#f@6o5cbget*5=F#f4!l=pt#`H zI$s}e9VdRBN6Tu>(Y*6h6@x@GP2WtY{eE8pH#-t4||ZKi*Xt}VkBYmUoHmL6EV zmc2#6k5hm8g^3w!D;I=u-OTh}fBJJ%OMqQr{B5Nx9LZ~U?bZ`G==~<|+~M#Wp8VH? zRn8rHUAUm^k9WWsd*f^R&y4OLd@Nj9yIk+j)^Al7=e3Pi9A!AL!9!r#rTT0RiCyw% zZ*SeLD1272Nw3s*jVCkYAMMf?!I$PFYm=^o1L#M*d8-mT7J%4WtUx|tCmYDy{bw% z^@*Y5*6MBRd#`0ZoaNEqxKrZE?WwE@%z;@_yPkU8aLm$qzF_92Z#PzQbliQtQQ4e< z&DN~GN#k&@6KjadruEkw|Gj?J956E>dukKw5rtQWoen5W?vmYg?V9H1_y6AHhsS*O zDB0+*#nUcj`9b`{`?8(<<}cIUw>V@E=-BpO zohHmMdoS-pzP&-Qn%cKaVzOsG14~XLpO61v@4z zWIlM~JlmUHyZ0U5vM&0BXzng>cG>Pn zw+`jIaThCcU({Y#xrQr`BW3ITTMv0mmQOD1?2tbmU(w!hs(zQyg847%#l=3q`Dwp; zXZFm(rEIU#llUhtF^dZOe@JY~0s z_D3@l_RILJThXDGv0!(2&lHJ-ZN^a-dQ96le~&!Z_A2An-19N#uEei9u%&aCt7%Lj zM}2|MOQ{oVe;wvB&oKUJvb?i)TWjc)hyXU@y!xQmdz*L5{o(Z~njq%AJ8whTx=l9^ zz1*|$ux7^o-0B=L$H4b5kMRb@pXc*r44hO|!f~=?&G(rst_tOoRxU}8-TuyS3U`sC zyk&C*Yp3+(m%l!44zOk8DY>rf$(gcf&%u2hA`RE-y%)O96Of&t_0Z2DKeSD9O~#RE zX6Ct*BqvXCSroA=xK_~IcH5`D=g$Q{`x?ve%u#UB=JLyrSyxRIj+62*S7haWoEm=K z{dlv|E@^&A151aey>cplR?j?r-Ru2q8LPflCCS6DrnMfwA-A|T=9lOBGYU%c%66Q0 zDpJZ^5H_<#rmX(jc}`9%uhk_jsYlqtEO*>)e3s2E#$)^BTFS5PGff7sjZ^kYMfQg? zeB8+`%5XmLgA()4Zm~uC{eL`f__lT9X9Jz1frZ%>Q@_QOEM;*~o5UJ@m`P*a?!|7d z+S~1q1b&{aT3jHf`#ZaI{vz#Wp4m5h#h=S0FF_C&*S9D=%{ZZ*R+nui@Yj?AR zF8dW&+Op&B?2OGy8yG`Fl5TnSe`WHSs3^8;UvA6(&)b3+p1s-`5O`EXe1W4p+k?t) zM;>a3GECK&^Gx?OOXRhbQq@=Y=BzmBnwvjm8?V*-cbR1wIh>omtPoTP(Wu>Esqk;o zHnCFX{71RMo{bwft`l}?<(8^{+ildA+1Q>ET(YZw{qucR8vT>3UdWVit=pFJMvIF_ ztiY7TB~au|L(ziJ>!B>ud!{(=I`zJs8 z|K+Pa^WXFZ`z;=1d_Vn1pF{9%tni2Dj~Eyj*pj^6T^Rl`{9t&St^M*H0|NtRLA^(0 zF#`j)FbFd;%$g&?z`(#>;_2(k{+N|Zh+k;Jt!<193=EPbt`Q~9`MJ5Nc_j?aMX8A; zsVNHOnI#zt?w-B@;f;La3=ASGJzX3_DsH{K>zxyQeeUs(_M%$bWF!OU?)u`qD4vPQ zN4ZjfS+C1!lR`2>bLm^h%^GYHJoS6l*j`v9ou78Mce~5eH^(&CICfiPNS z>eqVqyHp2e*lgav_g7^78PmwyM$FB>Udo7fD}}2+S~uAP5&-o3r*>9adgu`>egulP^+wKHIf&oRxKId)6utav2( z>g7WBs0(v@duJ&XJqqDZ;{YkT@#~}o@7&PBAN30>ZY}RP|7|py0n<8Jo{x>TngI>=sy2Afecv;=1XEwcwh3R4w|7WBwj&fO*CKlgQ zv_k%sdd}aJvpZ*I?hPu8&4@R9T{Zvu{hzw}XYL=Ye|5z4x|9{@);(nC5$y!{dKQFt=We z)$?5+EM?6|f5wcT5P zt)2OI_OvSg&HuLL2F{wZic`@zdy|=e-ADU>vGZ*Iy2POFf`{2F4E>FIFnQY1|QGacD;Ohrh+C1&H-%InqHb1ZZ{B!P7$0aKs z+`K)1@}G^4f`XNM^UEjy@{_u!{xCkd>YD$0{oCI^p8OanDERX3-qp|kIXAn<%y*yP zl)BFM#I=e0!e8$@DDmp$O230{+{vX67dN@zz4pfGMp@`yKw@zCGVoZ)Yaq{Xr#EKJb_7J1NefZnLjT8ujO8OXf~~A-;V7*0t9a z&gTa2j{EvBe0|{Uia&p5zN(JnSF&x{!*Y+!BzhL7jsI0?4Ugs3wq_Y0TXeTAaZ+9B ze`dq_vuU=A>n^e7p5BqA%KKNS{03`n&754BEqrO-#$~6s-(-7Y@~iOHvdL{t4uA3u z_Wp=_S!ADacTay+#(FD*diyD7a^12-o*e&}T~YkI-!GT>)2yPvoVmhIYmKZNi@ql8 z`+t`4WJcneG?6bw{V%6iyXc==>p8v3VS;VMSM~Gn-Ymai^+x!@w~hQ_c~|fJOL!P| zHuu?IzwOq#%w>CSo!j>I?zF^x?{oJx+~Qk!>oLn_$HVM%-~Qisf77n_2M_65)|>p; zyz77NJ)KvD+v>S@8(g{_^fzbQ&U0(!7kz2B6A}_U8K>d3%snN0%IA#=ZrfT{-DCOn z_>6hyPdA4Tb|136XHQIxk!NGRd$(xg4ozvLnL2k{RPHmRecUCw>EG_3#}sQGaVu{B zQ26Wa%fpKA>^Ni`)Q`Id?=RQ7w3XM1Uu?TUy`l5Tw62B(#V1#$nbkftjS9`#&&Vz7 zu=7vDoq6+kzpA{rlgk(Are9aTx#a)4C;aJG-UJ&cym)amv%2Z_ zmosKH&+Puxd$^sO$Mq%cHOueMyW_X?M)dQ|HFKMNe~Ri>S&blu(0TgCTuu)H{inQ~ z$ulw0PfTgVll;G7@|49qGRKES8BK^1sf=wQqP(&(LeS2h9^aqQhEzw^wghzDp(+p zwM6eW`?TqDpG0k#{12a5SbZURC&&B>rxlyBEk3YSZ@!kSL)Z_M)?hl^f97~h9*j(n;3EHi-mhHZ^yr<#96hZ$B z$}6V7yFc~t;r(YWG@aaS|Nq~#w;m^K{PabY70R4i;xEp+EyOYZi-paf(>-TBPTX-c zJjc@^;*hzggeR()%k9S!>y|seOg`E!{5$1eK`7V$T^dX6W7gga`*HQ?tJ-I|YwJDM zw(pzw?EKp!Z_KYAcU+#ZEm;51@}G(+##c(tJ2OMb=WlV>eeYnXFyN>$+O?KAs(qn`9i3I1TsSlwIj=a=F- zJH?t?`Yl1C4t~lqdkgNieOUX2&FuQ}tIMa><<`r)|M>CtfZLBPc^s8rvoAB9;E`Ic zR9?k1OMX?_iz6Q&J_udV;-B3fFlWs^*4eseL;O!>ea>9<|J}Amsh4~zSIY~7ttFN2 z9(uQCh2P1n>dds&3_;;;rPdOm_a$DN-DSFQcxP$L-Q+0Qo~&xF`4P(#7#?1ZQxy4f zW24Km1crx)89gQ&aENmA+bh-F(rI~S_eW!L0EZ}J?&LHM1s|<`x%J&0C%$}@E-I=q z`ImiIJ4Teb;hp+o`>D*oe`V!ySB3Jtwp}Rt_tc6xf`Tt{w3v^bpTE*F{pypxl^a=J0@oovHp$S5{Bk4u{A@Ab*uT;+`2 zlbN~w8O0_CbKA)rum2fe`Q-)o@!xLT$w50x{H|$>x;bR5*~xFeX!2Ta2@d~^4zsNW z|2rq2G;#Ctj1IGZ4Tgu^=L%kYwku&{Z-d0&1Ntqeo*MODR6F&w$oEG{>MoVv zulQ$Kvoh~-()fMWM)8W;!^wZs;y$(CpR~?rdP(Y|PCh1%7J)T~)$>>cI227(Yd91H zoHC+*xbQ7F^*ObQvn7DN-Tw*?hm6CV2|R@@0+)1OoN%8zp4t#cLlrYgvw5{GianF<&9aSouS! zA%j!Lhr+|5h7KHxS1+#%U|iDI#?GO5=(z8N#Sb@^Fkg~zni_j}(&?ue6IhPyYA?R- zH}U;^b$cczDM_a{hIg6jA6`D8DdE5&XjiJ#Q|H7wp;CkGcypt`t1}-i-v2Gr#puN0 zJG)G^N`p<{N^@)Ur-X-MidWJe3a9VyI`TnR;(2S^Wano4)naRYS!QwQ-km?)UUcUZ ze*xum|D#fNRq<)%-`wx99KQa+!=~dA&%%kDZ(m;`B~v&1*w+Pmb0>%VFsZL$IkHfK zBYKNxtHAVsh0AWKb$C$4R_CdnZY4TP<*F{(WC( z>2J@=)xYIV_nrUj6Z6N|83lWTCLUT^T)$9^=g3~gTbeBsYG$u^aPjw*v;~kfGxdeC z!a4R9gTr4{4zr(?y!fhC+C8nn#3rhUtF7c)rt^AUeili=qdS?UZ!NyRLx*1~=*X|@ zA2asXW#8DC;4nqeI(XBySNoSNzrrFgW75LRzlRn|c&wT5x9!`r^B%{ioL(KDv%k+@ zr@p~Lmc5DZKIhDDTeYqKN_Ns=D3^(#}bow8hv(Gnh z|81X}7k2Es^!w=B=nWRXwWcvV+Ome@vu1X&^(^D9pJo>w{W`Bdm+M&I$GHoukMphm z{b)wo%=u?J@}~$tZGN2af8mX|@D&WR_SH4>UX(rYtUlQPzk(5WEWgTUVY3(SIqXke ztpEOs`!lo4-}fQxiRFIVW;LCimgeH}?yo~-zx(YJ0wot39WG}n$#vT1;<8S}T-IMMWY(Nj^CmfKu3ux(Ho;OW$?IC= zV)?%t<8|ye+^W7-UsF6|`^(c07_MhLe0*hE+}{URmb3rnx7_#sw6=EN&4*7OK3f(u zS3q#$+BF>~Ks|^}YT;edMprIB-klV0R}~{}art`wiSX6&C#9?JC+rq@b?8w3>i}TK{-8-kgX|CK&<>~6% z+?@u1gwATv7+GRoF1`bOZI#T_*eBi*wU~pCTx0q+Y4wCnKOGhyuyRf0oM`TErh9Jv zShGwzHr}pE$KGng`cx^ijE%>>))dw?wN?5SvYpYM{6#>e{_#xzr$=U-=-l|&=t~rcZNFr2MQ4(mxU;s%{mEaKZ~F4H>Gj|4`v1G1^z(umx4~DpXRg?uc0D|1 zU({bOyB~kqi;~{#sQLL~V~x${l~35eU-dcuXN6?AX~UmC1^2)0@wLDHy5C=JecOaj z2jAOInE(Iv`PBTp{JTc=UlJo@tPNMC9^1HQ1M5T6J2_X*%?d2z*_wG+{k8x0_Pg`- zL)vfuVskHkoc!;`f{u=Kftxn@QDqgSuaaxk5C6RsO^{J=qPWIs!%t8`3fBchu{Px#eroj2-yVGXvKb);+|6oJ% z-QE+q@=NM->^@AY%KK}1_WSOR5ObT=`+q*%XKOlBuu}TM)%*YSKApPqW=hJN8xmo; zD@@y~c=N1dT{BlVrCPgYwr{B4{rI;1wLdBQ6yLK%%{%+pYjSW9*9E@9t;;WGuYG-A z{Iu6DHtE2}&vuC_t%<&{|76VU32T*W*N3?~cE7%Va_XXx{cYcOZPd)loUTVMpd*0-qLJIX<+ZS70GxUACeowfX-S%r?-Jxs# zr7TPGu6*zKmR$Wt;!>>5boD>-%ikYd^=fGvi_6~td&O7ktJNpj*<5PB_3oO+A~OxS zzmrccx!w?|?AO1zZbkikg|CwZ1$UY$MpqqN@o?hL&2}Y0`|r=WJ?}GrN%>`ET~JBz zc%!A?-<*FnB`d=7q;7Mqlz*k3@i#`pOHEs;Xrac;>`mL2s?VGm;^)7Bf4jbz`OB$d zMWu%-Bi>v)|Lg6liZ4$={r(xhR_ZPiS6AmgtmCmHTBz3dZ-Dg|Q-;Y(B1Mx8M7Sj` d%=;&QW5chn50rD;85kHCJYD@<);T3K0RZ_Jt^)u7 delta 4429 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 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_book_apprentice.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_book_apprentice.png index e1d14aaa6fc7b5eb3386cf3294cb3ee030d5ec77..7c1cab34985b412a5f59642aea22bd7aec0ed1a9 100644 GIT binary patch literal 11927 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 N#M9N!Wt~$(69A-1`MCf9 delta 5138 zcmbOpJ417VvH$~HlDE4H!#RdM46|AOFQ}b7TT-t65xba>p5(W@(E=o--Nlj5G&n(GMaQE~LNYP7WXJ8QiGO_%T;Dn; z=jk$E^T`|M-bzv{Yxe56xka&fqlMogp0tTfOE;W6x`{FQSz2QL_oV*~J7>(^dE>O> zjISHSPu4qd9!WCP$u((f<($hVb4KF2mTQ^p?wOaCsL4&5QK2`<-Lk5r&gS`?=P#cB zW?j0mPR8^6=c~_c&R_g_QJrt|=FRLvfg2;<2$%Gz{F?P^VcDT?rMGrosIk*mQd+%w z^`z5Jv;K!~@ASBP|JD7aL7r^CfAhbXb#Br3?eX^3^2$o=RrLu0_Ir~P>*Bbsua90i zf6L~IFRUxoUvZcGi`AN%^7NSR&JWk3zxc36?kwCa=H&Qy&A+vI^`RB)RWkzZulUdS zr76~3TU+&Ghv-D{P@8l%qc0xpyZ)#6`^E2$ik`glBiGazJ@utQD-~;2$iGte`Fmwq zLe<9=k5+|f?bG!5ShCKzo>_9||195U%Y#;4S^M&iQ|qsVb&Ia}-^!23`NVcX+VzRq zow9XLL7Kh(F8Nw1b@X}7q|1Dc`|uk{K}9eK`T%2Z_hjV;-Rx{{m(z1*ZhV4 z-q!mn_w=*-Sq|ImOTYfywM?(yvR^;g`0_k%{qwq2_nv>>v*4*~+Rcbf1Vw=;@tHh$3;!9 z{0k?36tt{MTJcRn`e5>J4-fn1G@u6^E zogAI=nWMCH+vY8|lGgB9{@d0p=c9}6wk1wS(-dx2 z`)GFCB1cwds@Pd~hd?*`yu)kCG&pYjZ?f#xpXya<7q-8@>cu*%3*lbB%#`a*xwszv zGTzhi-7jVG&zHN_KFSN$>snjxv?AC|-D92Hm-qYa6lR|Bzuwz4r`l(=?IP`|U01>) z6Tc;t?yIOzo09Z;qv?W|$*Z%U?z#;ozWlzMS02rF=Ev5#nYXKTo&VpPopZp>c*4Y~ z(&pL6Ij^}nys_gC){om`uxtIUuxa&gR<3OOKf5OK%447T+?x%Gwk`d&{oXUbxW59+ z?Y|@+zjQQdWB!Ky{~JDUJfL>jDKwtx`QtD8o&Q`Ne%Ntjc~73WbnVoGFCIE?GO*XT zK0p8a(wAx~KUptyUtc|8ZvE?cnM23pI4WEFZ{N?;X1`r4VAXIge%GCE)yo&{-R5Y~ zd{n#M=SzUmOeKXFj-6YVddC0g4HLZ_e?W=-!i9{mcXi(~mxw#Q&nxaQt}>jtPtYeV zS7`fOpWmO~rO)3b_x+`+=$D31cNRVObN%y+H9CI6hQy#)?bFS#^mtcQ2HfTS>b=m; zifh+h6Xt1N-TT}xxX){1Omx@JyDhwDS^Bbvo3{i^J6V57#Qt=4+h+H;t-Y1Acjfk6 ztJn0-vJP0oP_=LSK@ESX)~kTkJEr&hV}N-+&&MWeE;*OtWT8 zJYSdQ#Kz8^xnlwwJ9}z+x>5*-Y4E8pjkl#k>zdqOXil~(;op66#)pll!7xv4Cls`TAEL=&cDE;BKIr~d){@eOcw9JL&!I#bR#ZxMtq}Lv}_+!+`%{xdwP&!}K<6uQm9%iwd6LBN6G!WM=kdj$qZ zp_}|147aklj`?*kJW69!R$!QG&cwvP#KFMG!qCZn;pidJbL=b&&dqJTy>)YnNh-^i zn*8Q4b^&ef8BL5Y=4j3+UU5`|BjJm(Q0-+NkZxnJZinOEzwcI>%$@e>&gs{`eV#3^ zw^UYQh=0}7;l1=|RGEt$qwTHx(^t;SoO#B-*ou##@ybgJwa=H0OoeMwd6p$GM5&c9 z6sCqSSe2$;Il|1r5M{>1#E{KsVr^aRV9b!Q?dHv!%~Lu&9{wu5S@G-4_k%Gr1RMk= za|`F$)T*_#?@YBydbM}>mzO%o%n3YlGS^dAswwASTS3UXs^E#so2V+Lrk1I?W zrKM8^m@aJj5IA$Pkl@LuMO&p0J(?opkl*#|ZhUO))EK>Rd)Dlu(u@~w2URImK8!G6 zaP-kT`({qz(k}}GC+wbIEA{fpWrkhXj~)_Te7EFFkLSyiBCOLh*%F-2&$uDIkW+qv zx$EC|<~c24_2wabjj;&zd_s zG?xZ>&Y2lJyQ#93pW()W_5j_6rbFpQ_P(zf4W3Pvtm0Ve;v)9!dFq!Bic!1{kKFj> zC$;|kIh`>?N9=co5X0Fp9kJg||9Q@Ho@998i$}F3Y-_Ga3i__&PRnIE@`Bw_ zam(h-&dDX6bLY<8^}%!L{VD&>>|Q&!iLp*`%Drf{mR%|}m#R-svNcs*`DOMbul<>+ zJ6Qxc6eZgGb3ybLl^PBO0jK(m$R9`e7Cf(({vyP&P>yf@4oLy41`9>WoECvw(Kjac zTPa39VmwmkutCr%UcbJ`!F$W{_0#PwIjrA$eL1zld#P&`Ym30cFHU6N5zR4aZXVEpi zkIv7VHR)AUWZqx#>3=wrHyNaw*33Em>U@3Av3o3s&wuc+>Bwojkn-@U>B?j3b_)t? zS9m{H5w-J`XDrlUTO^hnq1ak!4v*M&$ki4K^X|Ckqzt{g=Px z_>|M@<9+J;{B;^EWZ4h#-RGS7j!WHKoI6}8mpzH4Wm(I_;?JC(l~Cer96+6yfxvhBif)ZvE~OaVQtd+pM^Yede04bF`KAUYOgsWPRe{ zf4wgj%RIkdSG#b%!(cP}8F~K;`8-10R-ECGVLW^8oLoo8nmapQR(+~p@aay{+bJ@q4!_mC zE^x`+)#qeY_Ls*sZ<^1p@A)?G>VBDDx#v;~8nX9%D9rZWUsv$@^23Rf*WLf!emi>I z&4+1^Um9!1?AKE&njj{4^7&^arK11Gd@YS9aQ;cSpI3WXz@l6%@AUWke_iicepBAY zy--o7X&dLx-Ug02PktR<68p72*Y2>gI;bY)z5loUcJx*sj-vl3=Ygt-Pe1oe@mhL4 zcteey{_^#)Q-Aw^s}bL@bKgrV7VEksjc>Dr?}mT*bzkjx>rdM@gRblU5^vR2JV`ms z_I!W!V_nO-q!XpWJ<(IE&v@?F_bGBx#r?#4?iXIG8+vX1xU_!jPf6>Y>nGRT51hY$=f23>?}E7(ugzU7 zzar#Xh}P5s`@^ey&u88G`u3Xnr^mwY%X|*E>4rtGPcP<`dTM)(80o`hTC|&-%a5clBPF zYr=E2drAGxqZc@jZvXvbV~BS4yzljYpRP(d?sszH_WSQ{Y^@J^zw+wWRB-%x?f<=Z z&fWsQeRqGkz5DyHSW;4cn6e!ez>TXE@^-S$X{29=>~AKmB)Eh<5hYhueyq7w`LM zXkF&za>TsDCvJOeSw-pV@<{)J`QKxgg7qtFP`CY%~^{yWM>Hl-~HePvZAGI@hNfrOEzVOLE zUoP9be&NNOC)c@dw`t|n|J$|wb=B_T*$#KE`z}gbv~A+`zS6>5c0T`StobnO({;+0Van6T|*t8?}*uLD3|7-QFedTS<%wvAcTb&zMeSfg^a_F3Gm&zG@7s)QN z`+o0x{*}MAVP(#`=bscl-RY`%dQqYEjV%A|-)~*mZ+v#;!L%zo{@o0*cCCE7q5k~K z*>mUGN=Qqu?rqYV+O@`_u8n`!h8ddAi2|7}@2e~a>2h3J_ z_3qI}Zk}}B7p9NCS-fih#Tjg0tE2=PojTVPcv$)G{c{T^|Jog*b@Ej2Y@@0l0=AbN z&F0w^+nODZTs!}3{qrJA&8c3z*-))VlQ!z>Dh26?{dReBU}j2H(9XRL#XI&I*!!<9 znQ-Xq>ve~d*4LHYTi4|ttpak%y7{}5g4ET!4=q)=cx=*(>{so#7OrQU%&1o@(eUnz Z`KC#3Zx7E%bq0;+dAj4nJa0`PlBg3pY5)2Fs>?NMQuI!K4#e@u%Vy1pIVqjp9%?ybsan8@p zP0cG|00HNs)Wnk16ovB4k_-iRPv3wPy;ODv2I23XE{-7;x8B~ppBP@T0vRa!+4e{P}TC@w~20n!n%r`J49T%QqF2-z$FjbgAh1-+$(bZ`q@9eyirG-xqE#x;$SoQ+|5g|5YpI z%{jq-bbi?%Th&N=&oBAguT)PtpMOj2>C&mo1TJk>%l-6d|BvhS6Cc0dH~G}Dwl_JU zQrrJ$e4F)=ea4Ja+wVM!3A^#M)zENiext|`?M)a%Y0eFFFWU~-HE5o7AR=d z%t?GKZkK3v?)ApJqmQpQ=AAaG+!Ox%m+1QIMa^;N-4?jzCT~yuRa^J;(uWOC($|^w zw#;cdq<${D{qGsiFWt9`eP5fN$)0^>U3@Le)$BWF`}S5W|2VgtZK83@pO$-UTcWhu z=PkFA*6>;W+tw`Sql@mgB~Gd<#bWVVQ$N+LsgwVDA-;6M`YB&>-LgbPj(kn8sQukP z`4-y~^QVh$ob%`Sdg=ws$*ax({$6KSDL&e|EO0_`|I1@?7q1FuuGw_x&B0eSAGv30 zcDdl^-g8~*47tt$X6>q5w**!-@R5Q=ey$zhFw4J{f^yVuC*&$y2UtR&mk9n z)ybMnhgv5@N6-4wdOsu7@Gq-Q5rePK)29cQ&v&U3oO3^yuh30j?Xr2($u+)@woT5g zxBKx$`1)hJy-S+p0^*`R-dWiZzdzwMw~(2S)@$ugJBnPIv*g12oc;!_=lF7_=!$TOK0;(-O%d>tN-Q_zUwZmH8g4bAz@vNx$3*S8wZ}-`l2V5{?tX=gq^vtsO zzEi)tY)+p!b-w;5e~Amn?%lhOE%upQXZTkCZ$OXBvIK`Yrdcy4p5J_CO;3OSUtv@XN7lPGlU&xg$Hhh?@-ZC#WO?m6y`1oBrf8P7O(9i!g z2ggDi+rM^SY6F+WwD_mHI~D%Y;XU#j*p6j4c zlVIAi#{VG0p>_eK28SOD);o1DFg|8F5-%OM{~!MYlkF$I-a79rZ@*6FIcGkVal80?6WLWq z=UrgfCCA9J;5T!};)jeZo;k`U3=YP$-|64ao};>0S9!tmFu!h?>Q`g?bLJ0DZnXspEaVd=S!9Z_25 zo0LCsy!h}XMC{$U(=mmOmkSvI( zSXSs9F=rC9#r#Ee-(N!-GV_{BAN4X=+z+Z!s(ct>0J7rjn>mF`zbp)#z&^iD=;f2k z48N|wJ!>InXlCaHF}Cu-$>5B42mk-y|4ySHP@=L%u7LE#8@xf|b_0iE!w18q>AfG%e_(iE*w!iHqod1w7RalhDUJX%r`UMS zXdE81;46c~=TkhkEkR03{BpJ0HyypRWKdM&JP zd)|`5P_j&2(frdWC22iAPC@?617;YBkCJb&448M#Uu1E@6N{BZ2$@WN!%`;+hs$Q$N{sPDI1^w!ur>7W& zzj!0kbJ*a*rf<=6ruS|=pV?uzb>p|4XLQeb=lzP+o@}A~YFEM>K|#k);m=d^3g@-G zcr4l@XZNb7L+v{2W;3RwFU<=CZr#1R)bQ7lckl9oe=NC_f2#G&?YVQC80!?L*u^Qg z{8Fj8bUb^~ek=WzUuIA8+Mk)alSP0-QKG#+7etq+)Nm*WIK7DYafA<)X}$ zD>POpVJLJmy1}7XvVDWHe5uo>Bg`Ft8xoXT_C@`E(KGFZU;NtI60x#dQ(sIC4EIj0 zVr>z4n0&^>_yz~B6GzzL>VdbrM61z{AI_tCJc8oWlKgE3r~HhG%=_Y)K-ILFQ$Kzzlu}_V`(EJJdH>|gnN17TojYuoRV&uqvS4NA zP&~B!>gR~_eYF~F$D11ktmZ#_{O4V<1{;TBNzSdQFBVETL`?lEx^m6!omOm$S8N|9 zZ;p4>`NMUra^XW!sZ|NNBK7}X?FqRS{$&5ZUhjV`hTARjO>5?y-Zf!n*Iv%H`41;n z2;AgZxbvv^^(9(o_BlWP6)^prr&i4^JElhgJTAJomN<2I|KAauJK5z2%h%)^&W1J2 z85sour@Zys_QbJIx3#^OB*k`qk#Ex3l};}TpL*1N+UzQI`=S5;y*Z{ee|}xb|Ftzr z%eykuwT+FvcDm%NfF6UBY|G+2d2e6+r2ct&M#kBce?g0K<*qCj4z8>gSF^FPo!Ywl z^F%S88}|g>Zmm(dt)^AsGwr?13Y|N1ryst2`G>N?IrbKf!(UYnv(J^hX!ZM=TUvpM zO;r(B+q*ZHx5Y`zaTqIY+Q}^aYw`UZI{deSj+~qS_+tIvYul0!Hdr{9Elb&ZwcgWz zC8vUcs`K$*t)=tt_3T@A*RR_tr`o=Kow_-GPaW&#o8e(h9hWyL zor=2lq^u+@OVs4)rmu6io3TD#@#FKuLl3guzTcdY_A)!|hV;`Tk%d0bmaW~p-h;8E z{->PuqVtNAx6UheT_V2Ac)}OcoE!TEYo|Q^b9=r17txMi`=e!D?pof=;Mx|Y)!lKT z+?`$NQ&zWm!mewjdHw}r`+l8&&Aq5yY*BlEcy!g*)|cPppEtOqww&rYAQwi~&y7oficIyQpF~{32cibFU{EGf2URw9dZ2rkRTWr?ZW&M12y=u1Y| zKl?6mNF(ldd*<(xcS=sPJ-@Ec=lSha%WE}>?KvN~<{uOBaappjUPpPcPdDd3{k2v)==Qx#9R=$`R~MIi|7J_>{BzCYO=8XZo*BPhZgyA^efa#R zYcFQ-ED7r630OS;*0;Wx{iV(zy{=ELa-O_m;=@1x*T0Xe8Kfl7nmC>4FW&8+TkT#~ z@HBVj+Z^xG#ai{hzkk~%Us9~@{!_Zw^(Usdj$|B&@~^Q^Mk&40K4d2s5s?d1)L-B+)@z8TZ(R_SlX ztTxrlb(j9j@1kZ5lWv(j*mlQn|8kX=x0~;px&6+Z)iiV8j9F#1AKTAA`K3GY_4d3I zpZ5P>F7p4U{A@F)@0Sch^e2^xJL`+wzj&}Q#O%85`~R;_|DXKlOz2J%n>(Ac|1Y^0 zy!`d)Y5U*3_k6j1|74H>=C|Wdi`W0~DQb#8a?jz_C;7Q|G=uiC z*B)QJ^O4i-d)JSI*nP@w&2<(v^Y81A$uG|n?)bgS^NPiOMnehC-t`@r;-|Rb6uv+>;e%;sCH{_3HFJEG@YoWu{>J2}CUfJ|T)?so+`-<~_ zcYOK1Y`?w6Ka(q;eB{F8q6+T{n!Ws1QoTOz@9YxZZHte6J-_Uh=Be!V+H(#cZ~eG= z;^=kh#S4B-7QT7kD(?@Ed`Y5V@Hy`-x1!R_FX}r=KQ~^LTAFNaD_`|3Nv{55=}LRc z%%A12408ASKHk>c`}D?}`*rJL*Qc(Y|M2UY%$ZGBSF7*K*X!iJ)1OmwEH6v_d7Vtv z+Mb>?mv8ZZ>K8}lM>UoP@4b<8zHZ$^75mxqOnc)GiabBp;g};PX(g@a_{BD2uBr3i z0Qn=dQ3$i2$r z?Sl(nZ^&$~yY_$Wwy!U;Ef8ZwnSv899lqPR=)_FplV6q;RWm*>_}$dh&s~;8W^@B!ruJ{)V?zORu6sdAtv|IJ!^(*{ao#UB7BXR?W|Gxas*z`Hp UtA#K@3Na8etqY> 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 F2>?Fra&G_t delta 5335 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json index 37fd0f8c..a97d369c 100644 --- a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/_index.json @@ -62,5 +62,17 @@ "compass": { "texture": "ebwizardry:gui/spell_hud/compass", "metadata": "ebwizardry:gui/spell_hud/compass" + }, + "mahogany": { + "texture": "ebwizardry:gui/spell_hud/mahogany", + "metadata": "ebwizardry:gui/spell_hud/mahogany" + }, + "oceanic": { + "texture": "ebwizardry:gui/spell_hud/oceanic", + "metadata": "ebwizardry:gui/spell_hud/oceanic" + }, + "planks": { + "texture": "ebwizardry:gui/spell_hud/planks", + "metadata": "ebwizardry:gui/spell_hud/planks" } } \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/mahogany.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/mahogany.json new file mode 100644 index 00000000..c01b3f91 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/mahogany.json @@ -0,0 +1,33 @@ +{ + "name": "Mahogany", + "description": "A touch of sophistication.", + "width": 126, + "height": 39, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 43, + "y": 20 + }, + "spell_cascade_offset": { + "x": 1, + "y": 8 + }, + "cooldown_bar": { + "x": 43, + "y": 2, + "length": 79, + "height": 3, + "mirror": { + "x": false, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/mahogany.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/mahogany.png new file mode 100644 index 0000000000000000000000000000000000000000..fd68c7d3078f47e99faa65b8601e5b794e20b3a1 GIT binary patch literal 20766 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/planks.json b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/planks.json new file mode 100644 index 00000000..f5bf90f0 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/planks.json @@ -0,0 +1,33 @@ +{ + "name": "Planks", + "description": "'Look, it doesn't have to look pretty, it just has to work, okay?'", + "width": 128, + "height": 43, + "mirror": { + "x": true, + "y": true + }, + "spell_icon_inset": { + "x": 2, + "y": 2 + }, + "text_inset": { + "x": 42, + "y": 20 + }, + "spell_cascade_offset": { + "x": 0, + "y": 8 + }, + "cooldown_bar": { + "x": 43, + "y": 2, + "length": 75, + "height": 4, + "mirror": { + "x": true, + "y": true + }, + "show_when_full": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/planks.png b/src/main/resources/assets/ebwizardry/textures/gui/spell_hud/planks.png new file mode 100644 index 0000000000000000000000000000000000000000..f29e78a0011bcfc605612a443239218546f1b3d8 GIT binary patch literal 22007 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/spellbook.png b/src/main/resources/assets/ebwizardry/textures/gui/spellbook.png deleted file mode 100644 index ccb7aef4cde39ce0dd3f7170661dcabd130afbc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20096 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⪌jI+57wUSGVBHAue0y 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

    J3P3$A`Rq2*B0qN=Uh{Jp;|nbSSa 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/gui/transportation_marker.png b/src/main/resources/assets/ebwizardry/textures/gui/transportation_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..9ffa80c5ea537e92379cc9275e19c42f15b57233 GIT binary patch literal 5708 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/integration/antiqueatlas/shrine.png b/src/main/resources/assets/ebwizardry/textures/integration/antiqueatlas/shrine.png new file mode 100644 index 0000000000000000000000000000000000000000..951b274105dfda2c1c0d3052de1a21b9935c4904 GIT binary patch literal 3333 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_arcane_defence.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_arcane_defence.png new file mode 100644 index 0000000000000000000000000000000000000000..d1aa14b4015262d036c004484bb7441a827bb566 GIT binary patch literal 2150 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s--&Tc0lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{9y#sl3cf$-qI+3X3_G40%)4w|ar%A2hW8U9w{MF3Ub^gH zgh!*3(2Xzu|Jt63|FO{}drrSp5Qmuk^q5CIeYgIee(iT{?eEGB;m=d=+|ieCZVLOh zxXt*U;kgOVjpO>~^%VYJqVe_fqCNXgxC_2EEQqveYuUzFEi$`Cgj4=>p8fQ_I?|Jl zJy*S=Y=7?eQ?@^|D~p9Je>hxx`0mCr387!7uDSkL>$_la(X7ukmRHes`>}=7C zuTJ+QxXOROwfK2_N9D4TkKa-(TW)_kZ81$C{#wmOv;W64tlaLeKCPE<@}bVFs8g>T z*ZJhHjbsczvVXhPT-)_6-V=pH3$F;Iu!b*n;gMpu%$kxJ5TCo0tE11l**$HYP6#iX zXo||Z?mTmSDH&By=BqlQ4;3VyN^|RO&YZb=iNPHY-bL*Ta*mzazw3;D%dr`pt|?!? zi57f3W3phz89_;J0cK^BzTm$_A4>QBS6k1-_P1zrQsd2OD;d9t`}aSXWv|$n z+`DQIJPPt=Cwc6;p}dte1DB>)c%!Gp2v^;3S)()|J={cEP2O%ruOMu>uXVQ(sOm%(xm*BM>&4$HQAMR&8Ga+ zUB3D0?cV%(7UnnBy9ZZYQaqLaDE#*6Ko<3B>a1U5FT_aQ7vU?vz4q`;#qA=$zDjR? z7QJKUwi730Tk}nd=EbbNrMdp&J&C-RzY{mS_B)e);Qd?af9iLhr61TnEr-8NC1?YW z<>pzZlP)=45qN%g`_4AWlCBSP?%q)5b6TCP%am4jqP%A5U%wcH8!-G395|+Me7MWhX6m&dEIYl|%5eVEyCMWfR*TUzj(W<4k`3u@))k zQ0bXZt(VHJm?o;fFTiiF{CdsbOR6UwU-G1H`|N$H%v{mm|2PESH(EG9#`(g5(Da=f zG*<3AHs#{_i$yyt*R``+A6a%_>#B!~*s2~~jOu*tuufKbZoT9=`GC7h+Sfm{S1nm# zwz{9|N!`R#@>z$Y*YVbi1<9`XDY9JM&*+mPZ^zkuL79`WtG<0$xbj;?2#Xu*^Nqhv zpIC!(~qRYa~%3rc85*wKl;P+ z`PkF#dNp$rXWy8(SEsH2g!zZ|N%{}YtQM|(?vS%-QrdKR^Y!-+f|PQ7Hs7jS`q_7l z&C!lH4oQy7>MhUuZGJiYYT`+6SgY}EO5mo~j<+`LU#RdPaEsvP^eC^bY<7VU3o1?& z9-lt*_;ubJ|1!NTB;PDmI_7g{TDI?ow%S(>ML%p-KD9|uKbW~(*5`>F!)co}C)`?i z*|+|?7d7{a+RGnvzm{7+yE|+3oT)`!VYArRZ^(8ycrN^}=JQt{m&NXGj_^p@ZTao! zgFjckUVC`XjXy8zip*QiqITzp&jSqXJyu;iH*Mj;|Cb7X#9Y@tzO(K4n+m4TOCNP2 zR&9E2D*YvJR?+R$6j$f}ndj(3Kf@{C8+8tF<&;A zs%4aw%^Z09wUV*(q_htQn!i7oSA1{h``8Z?P9J&UqBK=ydME2?_polZ-yYhD|Mz+y z7Cf`ZS7~ZW+7%{&`cmVUAI+T~Gyk#6`H=Wnef_-YOrP!~&ANO3KBLCEs7a@fgiJ2H zAW~8B-6;9Fa>$+Jf8Xvt;^F?Y(?Fl0xI6Qm{$B1oTUI)jELLma$_p@CeIvbk=H8hJ zf1k>I`__Bls-!$fD_U|m^yj$*#(={9+f@RLJN707 z{3wx9IPrS&UHQ`gI?j)oZ`|fvD;TnR*7el?vvS_~X*8Vt5hndJ?%{&p#%9HfN*1@7 znVv|g@wPe{clKoZn}$ohQ5ViUTE)5`>QT$#-?f{_#+UVpuLVOy@CRNscgHy`>~w_lVU awwGOX&hE*AgDeaT3=E#GelF{r5}E)2^%s5s literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_auto_shield.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_auto_shield.png new file mode 100644 index 0000000000000000000000000000000000000000..960407ee5e0d58810468525ca05c08a3c685c142 GIT binary patch literal 422 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 HoD!MMDC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_channeling.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_channeling.png new file mode 100644 index 0000000000000000000000000000000000000000..1c4c1e077de48b73a141445f3aa64ba91e4fe3b4 GIT binary patch literal 500 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^K?cbQy$B&55^X zU|`@Z@Q5sCV9-+rVaAH3_GJtV4D2PIzOL+#S!4uw#2dJuTwq{ekSuYHC~?lu%}vcK zVQ?-=O)N=GQ7F$W$xv|j^bH7a`+@@52EC$M#>D;JE5&M~H}X zm+YAdniE`?cQhw+{pIcoc%@TPG^J^C#ES-;S zJ+1?rk1pNA#!yjJDZ6ji6XysE?q@e2CGE6x(w~vZpvUN-xt_IYzvz$oi#Nq;&B*jP zd4%H*d$ix|$A^DOA7JCU5f&9!Z)CZ;E97jZiQS16GIcoyQ!WNGI2`5`+^l=*h31_5 zriZpq4t1@vxux`f&%Ns>C$O%1W@40*=oG7SLi%WtEUR&E`D2Onxw&t0R;`G!6yC?l z65%J!@L^*i$Lnu$^Sk<*-&rv%xc266&XSKawtX)s+T5~Jlr!x+Q`r>Z=4<6yOuFwS zMRzwwZ5FrK5ix^5Do&n1U-pkBPb9~jKl_h~AKgAJOtK=bnSp_U!PC{xWt~$(695t~ B#%TZm literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_fire_cloaking.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_fire_cloaking.png new file mode 100644 index 0000000000000000000000000000000000000000..080f16ac89075a1248d145ea4b1c0e9a18d66cea GIT binary patch literal 1803 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-MXN$0N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kDl~IgXhn4k!ltdfu_d^a)Q;(w*S;5cE_H7_exSYb%TIL zAeZCJZ}<1#{nOkY+5B;l;SvEIx%oAZdfc}Bp8S0Fn)&a)CiWley)#FaXQK1lZ|5bZ z?QuMJ;kl}Q_B@`QF=}49r8(PWD}9d?N?PdXIro(@m-*&=nswsirZ?Z;=f+Rt)qGXT znfmhkRr|XQ^Ck7)PibZe>ffHeT1x2F#I@l+*77abTOjo~C0h7y?QG|%jh(ZV(?9Yt zFJ!Kn9^>}*W7-#f&c$yPrQdH+W{u8SvuG~g{(bfL6wTScxc=l_n%*6ELf>ch%L|JS z-!&9D_iN>xC*FDMruf~{o91kxd;dgeyR+W;gSUQsjZ1!?8z1|P(VH(j@OV%fch&6= z*JMNkMC>;fT2xPI5!$HA^=O6C39~6qof0NxpF%W)mz%wIVimA854&=vRaTTakwvoe z^pe~CPIE<%go`_tIa*kF{5;}xIcL^0E?0?lBD{;54Q_Vy+iN{j_uAXf>zeZTrS^kI z8!tB`8MvqDIP&%c#QRNs`C#!K`{ri-^W=MOa@O5H1IxYVTw#O^I~y#6PUs{ckXlEEfYAx8&clKFj(GT-Oy|36+E@I+)zld zLqNPIxS)A0=cYa4NBVztNSu0fq}xMas)lD#LE@VY0wz5@v#zcTzqnvk;N&#n*e`)e z9a70YhU$KNlHo$%lDjmQ&Pg;$e%5nQlFKrG&(5>?n_7Lh?^voUZgx~Oeo4zB)oCF` zPhV+$E94E$UbFI<8}Gs^HIv0=ZMzY4T6W>J*zd7bFK#9KFMB?DtLtm$pADu_Yd)rA zX}mfqwPe+C5tB=uJm(HbR5Lxal2AyW!Jck5>ATGg={Yx#+z>s)pxHdftJ%=th4jV} ztDV1-{Cc?S+s&Dke&idZvz6K>yqmZ^ea%%Hek*fHsoMn>SFPUcJEvHDX3x}TT7~PM zwAS2-iTfnt%n%*Nz_{GNd+r8Gl%IM*qnr7c>5!F0NPl~+Sqne=YGug*Y}WF z=@oCD-`nQq*ZwPH+8n>E_^VQ{_*8m(b}pZ&c&)X6#kAn->z1~J{HW$tE?c&1%9IHxAXq&y_{O;(F$6re9SbO4353_&ePTABA-yGZ2=M+~rYC-npwpX7^*G{$x9!*nVBb--Rky+drg# z?0E8D>aF#L(yyT`9C>1e#{#$SOBL^5_r$BfaD7L|(ml`qe0%f%%ar{`8eUX}8-9p- zD%#TW`M}3_hq9#Wn@-<|zh@`sck8*sYU?uD^{<1vSF%>k{dJ~%=ZEEA@6Y$Jem9A; z=|AHQPRUoXYc}m;U|?WN@^*J&kYvzgh|~Y$4=O)73p^r=85s1GL71^(seKs(0|R@B zr>`sfV-_)P4Z}MMI&};T43Z_T5hc#~xw)x%B@E6*sfi`2DGKG8B^e6tp1uL$jeOz^ z42(gZE{-7lw@={sy<-fFyCS6?rwoE+&=_2?G$w{ z6b&jUEI2zwL3hiHr2-lvSqHmJEh5jU{#Uk~?6dEs)4kt!PurKjsmPXmt?ioem21mY zrBz#*uADV}6Jxu0>2$}c7w0Faweh$n>Q$!-cymtNkt)T|aPhYKt+@+N98uKCc0X-W zQ2Se{XS(`s1_uSkz()^%^aajfJn-_O*{!*X>H%BQm>eGd=wpaTX?x4I=xE9wkNJ+? z`o$~N_CCMT7;f_lz5c#_g0DAkfW<$~rZsW^7hZDn%Y5o5oeak~$5y1D<2{CS7xw@0#@ zSu#i7@Bco7wY+lLm)#r6D;j$H!|N_yd3fI0BCa8G<-sSvc24h9U@$uTe^LCm^Amr) UTeWf`0|Nttr>mdKI;Vst0G75%vj6}9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_fire_protection.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_fire_protection.png new file mode 100644 index 0000000000000000000000000000000000000000..daecc00828e0ffdeebd09fc4c1b6068b88455ef6 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^J-8G#TRb|M-KX zISV`@iy0X7ltGxWVyS%@0|NtliKnkC`(qXfQ5L2(%kK9xFfd4#xJHyX=jZ08=9Mrw z7o{eaq^2m8XO?6rxO@5rgg5euGcYjx^>lFzu{gaoNHOn-fxw)}HA_wyeBxJPmC>=; ze}MmkXPs-@Lw^&6H9=FF6&oAXLm#HDc6JS2={@Vj^EHc=V|Q3vTU*a+He?I(nv&YN zNMpg2rXa4+(1$av3Vff(cvSmd-Vkw6_j)NWgTkT;5euP%y4CN^r?1(nbJDHxyWF*? zExEH#@yT?0tQQvCz9;_NPJ{Es1?O1L9gr~RIn10EIzi&twfUkT-JkwyRz1(NX z8-@)r9gTvP#|mR?PqAehmQ=2PZRMe9zEEgqeJ98B>%#l;-|u*&I{R2`)BM-$`|R!) z*vD-;)@8eWq3OHh+{-eZ?tef3Ta(zj9kww4Gi!?*%9T89ZJ6T-G@yGywpT CW180h literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_glide.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_glide.png new file mode 100644 index 0000000000000000000000000000000000000000..7ca29d2db5a94b6611b11b54998a5c8d637c07e0 GIT binary patch literal 440 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Qm)@V?2hUIqpR z&H|6fVg?31We{epSZZI!z`(#>;_2(k{+LBVR9w*W`~AZV3=EPbt`Q~9`MJ5Nc_j?a zMX8A;sVNHOnI#zt?w-B@;f;La3=E74o-U3d7N^%v-rL)1AkcE$U&Nu~#Q`DT9ZXy| z4utM#5f_~N_<-ReCMP4MEQgkN3Hph;_AK9(@4B71m!Ecn_3Ad=Q=3|@Nri?kT$g>N zw0BwNhuJ~bnX}j0e2QKF{a@sPsM!k7Wf&6fmoqqUJPdPrx}o?T*Ak^ge|$PUCLWHx zu6m$)ez$VV0T-1=I?q~7I*a+zk|s@4GPys z!%Xgb)v0S!m7IDep5D}A$oAPred8k`)1x-6Gdd^TnbspZ!mj*M|4j*GgSOLtp%syKHjzSe=MKg^c^2`}tp|*Eepx7BP*L oL2j;mxmdKI;Vst0J8qGUH||9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_ice_immunity.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_ice_immunity.png new file mode 100644 index 0000000000000000000000000000000000000000..5fb31676208d8663675f2846cfbf8ea96dffac9b GIT binary patch literal 6552 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_ice_protection.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_ice_protection.png new file mode 100644 index 0000000000000000000000000000000000000000..dc49826a4bc82b71154ffa6a6c22609680eb4203 GIT binary patch literal 1873 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 L^>bP0l+XkKYUk>^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_potential.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_potential.png new file mode 100644 index 0000000000000000000000000000000000000000..6dfd63d60fe2e776a2000f929c377a45b926d53a GIT binary patch literal 478 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Qm)@V?2hUIqpR z&H|6fVg?31We{epSZZI!z`(#>;_2(k{+LBdh(TSaL*Nht1A}CVYeb22er|4RUI~M9 zQEFmIYKlU6W=V#EyQgnJcq5-U0|TR*r;B5V#p&M38?%@k1={vc6?RmLIA!PX;Kbe| zVk`NT6jit_SBE%m*zlQm-PTQ;BcwNaWflrJY0XzsOyW_QaAV0Wk&k_!zwDWvRX+3Q z|N4J3MfbhGoMToPJ3VZ5>l7hP)p^eY)m(lFu`o8ARqH*TJdyoDO84)-b_}PV8qJ;F zptaOx`Q@9T6ZH5F7xcSk&z;k2Xsxi3Y4uh$p2Idf&3My#HX2r{zPl*Vd~KEj$D}9U z?(RKXwIOuE6HCd(Yl65A1Nz5ARrkG`CF{O8l&vv-@f6dL}1oyB|L z_OIrnmz6igiMBFqz8FwbU#sTx&(->_+|sBS{_06~b32s21$6Pwy2|2MoYuDg dD(3$fl=5351tM4NW?*1o@O1TaS?83{1OSX0!d?IX literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_recovery.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_recovery.png new file mode 100644 index 0000000000000000000000000000000000000000..41312cef26573dacf4ef6a324bf18f47dc28bf87 GIT binary patch literal 6026 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_warding.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_warding.png new file mode 100644 index 0000000000000000000000000000000000000000..1c7a6381cfe1798e5f593fb030cf78b03d9a40e7 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^J-8G#TRb|M-KX zISV`@iy0X7ltGxWVyS%@0|NtliKnkC`(qX{ZVm}VuWcD7T$9SZ&BX9(SD(v~8CT_&Y;}vAmgwxonVl;T zX|q8pY~J&EI)75HMR{mC>l{28mCYb=<7-}((weOX$2b@w`Xb+|>+P}FEO&z8o#3Cf zIhUI3qpz3pv+qyox}zi-S)Bi;tsu|ebJ77z_n0T|wI|Hqa(nF}i`Qpa&+R<%Porzi z!q*?gt|eA0O$|Hp-$Nvk=XwA6`+uJ6GaNX5`|^VHkMfmfAyF3-s~25=ULKU`y4f{t d^72RQ+hr$D|8U^?X$A%c22WQ%mvv4FO#t0~sU-ja literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_wisdom.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_wisdom.png new file mode 100644 index 0000000000000000000000000000000000000000..9ad1d0c0054b3e23c7300e0997146c9396092c83 GIT binary patch literal 1793 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-*{VV!N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHWf$ei?5jpxsK%_0_+jdJZFVq-8p`qi3_HFmAW&{ z{DkDMJx^0_drr75?Y!|V|IdHUx7sXn*xQf4^~kWiaC?K-?Fk>g<%~Bo65P_Sie3YZNr=WKGwy4gPC06YUT`mnd26-w=ZljFI{0|P$(?ayIh)s z^@FOHQ}&0H!avFzE4p%)By>;x_Tsqmy7}wUl#?h* z{~hG_&3#>-=G;AZE6Uz|sZn>I@aOIv{%gnL-Ih#-0waXN1t?3d8&M7=PJs`<* z>gtdyg{4=o2PFIUN(HT)nKnCnU#nR3E03*ucS~-^ez*OyqRJ}r_7=Ol@f+M`o6hs$ zb*TY}fZSS@f&sf)3 zx;)=HttrYdJ5D!f^FwcwcHz?ZPq$vIcDb@j{!!tEPbYmuyWgHTDK$%D9`o#8Z_|F> zXF^F!*H`Q<6nj7C&yKKi<{FRNQrGytpR?Rr!jp9`|Hmt#fBgm1%fG((cW>@K8Pl)P z*Y?ag&fWaV_T+V*2Zv>r%YFVDRb}^lSJb0zM~)t-T$s9YS-wTUeV<3yU;USuyCaL? z^;`EfuV(N1FT(V-HY0v^@c#BMx11K$wf~iS{+6S3?wj*(TZJmOFPI}5_-I~K?u|X( zH&1M6Z{P84R+n+^waxvLe>@M%JbC<@Y1z^4!}FrQDm>ub@xVgBOi$>~t?J|lEeqB7 z4lc84FOA*Bd31fhg#%Zg)aL%Z(^TJCsu!>Md24yZcRi(zV(DQu+I7crdV_=CC+v>6 zp{HV)rN6sG=yyce+Pghfn;yLi>VGU!6Y zT^sWH#8)0G;aqM1Z+pRIt&%8TZ{Gr@%Xgp7U7+Ogb_M^h!lTN%P8sLUIyx-B?)bX< z>!V=b)&DCrs*F~BTM&CihT|;+&tGo0?a`;9QiNSdyBeP@Y+mq2TW68xY>eC(gjY81Cuf7-Dg{chbhJLjfXf z`!94)UOPcajBC*q$9A7an}+-a6VzWQePcB${lCgD>W+IH7`$pMVQweTbs}G&s(v7kd02e z|2TC`VGHLPhkePX9nZ5q_?ta_kQbdq zd@_$=@=uLPYfJZ5_5FD+`$D=ga))wEuEEZr-)1kLY`XD||Jv!>+rRn$=<9v8%!+Z- z{mhI^|7Y2cmv((LYAg94yWZ~vTSL}Tm#vf5lw0)Pc*lRNu=V|o$}m0M zqP@h^WkufS>lUne3~Lg$oJcLO+HZK|qY>MJSnWBg%zv2vXzVsRKb1F!fq{X+)78&q Iol`;+0REv+J^%m! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/amulet_wither_immunity.png b/src/main/resources/assets/ebwizardry/textures/items/amulet_wither_immunity.png new file mode 100644 index 0000000000000000000000000000000000000000..289a6b97b6e07129b7ef9410c12e86f15ebd4274 GIT binary patch literal 1831 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-8LC1eN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}51*u?$@AyANHt3f!@fcQp#WvR;wL_G8KU^ADyTTrfM4ufX7?jY-45H!sX~RtTMa@nXVyR-d5lOf4K7 zG6w{j8Q*rwR$glA_3aQi!O$eMKzf^6vslr&kOq@!H=AYFFx@yNvGC?qi_J%Fa5%Ok zua7vuJ5BAxrfZ4+I(TO|pWL|loaOr?tm3hs-W=!p9QWr&;N%Svg^yfSJfsIyon|>}L8&#p83j0$aOv*ZojZoe~jb zI#v5x;n&ct6&shi@dmHF`D|AHC8uuPQlG8o?v`Dzoi0}uVjH_AH%k5zf5hUmvu67A z_7!bpTX`bTG1{pG*7 ztGYoz-emUW75hpSc>NYimouzNe4Y8;{J@p(jU|@*jDE8Fp0a!TAUI>^uk0ep-&eL( zt$H+bRd>(2%fg|rSZC!g++FeXQfQUui^&ChJ9ktqe>79;a}%FwwC-JlW%FO;R=KWI zpIY$pz~7>hlSgV^ubF;K&ba-#!#kPWxS2~AyWaiva*yOWx%P~_-OZcl-ains{cqQ| z4v}5Dx_M{(%-_7|{t#nyyeLUZ%qVBw)2FZQ_aw~T>oVU&esxoG>q=c$+5fE1P9Ocv z_EBO@U))*4HHIzo*G1+$7JtyfdwfOdlT#L_W410plG`|JkGI z>?&vM=eTdb`|5zm-B)i#ehMq_r|HL=_D{sVRUvK!S48NO86ZqgBU5Y1NzclQ;`TEmSl)n%{j)+^v4!#R+c}vQLz)u>Y<8 zZr?8jxqW^9KTXfxxDl0Z*vAmIEIjXlw9TI4?-Tbwe(kj*D52-!-|N1nfA^*&XU~;4 zZ_n8j%^A-1?6c+Kiyfa+SBX7-;rYY$ll=9&+i&TgGW*QHz`)??>gTe~DWM4fK8alg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/astral_diamond.png b/src/main/resources/assets/ebwizardry/textures/items/astral_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..679f6954e2a97bc0401abb6985f228959383eacb GIT binary patch literal 2141 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s--&ci1lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{o;&T12G5`Kn%_7S7=?}>tl2YN`pw7f2Ag&-zid1+<#JuJ z!7-+5~K^VhjJ#`-MU`Q**VZdI{WFIL>&f0s@E{BGMHt3M~+xvS6N+%xTa zvYgreBpX}12^o)%A1_ot`(}mYE}hwqaoWOGX8vadF3a(Md(%}L{`hj)oBpRJh5mK5 zeM|;bhZH6+KG{Ey?eK>q5ON?hR;`z{Ztk? zmp*$!yuqfA6YeFKD}6b1YwM?W@z%XRp5GTPD=wQ`{O0b}8I2)j+g4_4r}GQ*JDhx; zE;;>y{zCodp#_@TZZK4_&t_lu%!!j_OM1t`cBwRp^xIC&-4oe3qZYZ<^l5U7W~ply z#wJc`nD_1gM4-_eo0)O-tEl0@6Wn2fd!Qda9&W zt-kWt?e)DqGlaI^Jag;Vjl*~Or!0Q!%^4Z>XvZEAzQqU1x6k`?@5o}_OH0`3T}t5$S%+M>Go%Z9rh9jhaFzg|mw@!R-A|C$|f7OaA~KQ>+!P~<%_^JUAe za!~_*^W#_b?{*y1y8ZlBH4E2ao2k|6Yi}Onm~qT>j@2Tmg?A=jzoGTS@{CNuy$1O! zYB%FVCadRum2Y@ZcDDA_>+|d6Rya8KpT21pskcOphj(+A&SU-KMRL&stb*zscY+TK za%D^pDq+3+^r^-hw|f`DzAnz0Ecm=dFvWYe%KlgX*8aQ8$FSr%*Se>VcA0R0-?!=8 zQkQepyAMd+JaeQYA^N~B_DxqOTuuBOUKBce-#KM}Ir}-gY|8Uv_Q(3U%1`W?ynRaY z_v$H4C3_ERPU9=MTNix5=T-TG0z+T9I+Z0Uw_O~L-H?BL;~HmXO?_`*k<+yBQw~n= zGmTp&zsR0farxfGzW)w)tXg9tq82dl{%lyia`pCS_qDfw-*a%@8t=Dt+Lg<0JnH#* z>WrZK;lF7rPD%HQGL=7Q9G|-AuEVi^HtAo~1Fv&yg=|aQRlnkf2;=Iy|{mSaXyUnhwO1*UPBHNt!nYHSNi~`Hbv)m+JtT*oXV8&v@$PxYH z=fjp%2yyDgQn<%hzOP|F@~G z-__F>uIH)UcsT#f8=i^#ADu7f^_6jAoco)f#YcBd)zU<51_lPUByV>YhJJ=PhNJE` zSMFqBVBjq9h%9Dc;1&j9Muu5)Bp4VN*h@TpUD+SA2?$!S{`7g!z`(%x-qXb~#NzbS z$@Uq-filPK^(}c*1b7zZ7Vl&(JUPK9PqO4?fY(BWD`yY-bXkZ@Y+~d+5&3jQhSx1e zSu3u_3ld*MTshjC=ZaX)G1+>NM>WssU&VRFXGPOpR_uSd_kQ*L_us$&-uwRXA@138 zHoN~!pY0Z|wDd{pUv_q0*Ohx8by#?tNU7D8SQS)!Jf_PacYj}}K$6nIBX1ZaUT#wr zDq!T4&MrUpPP@5vicmw2p8u0_`G`H)8~(3u-WlpR`_j%U&UrRGlQ`@h&8DkA+Ln6J zfI(y5O~t7J3)!zeH@j6RyE-Ic_nxN@o$9tR?#Or_@cWj^($y-9D zLgB=-PjN;|S1Bl3iXQ%XZBf?E3(Uo9nu(jC5kh96dOMMvR%(~)PF&y)z$50w|egB|Mrt28NdDG`S z>4#1g3(B(GJT&)e9a$l4+umDIUs%~1x8B)8WMR#H33UsPAFltt?)+!{kAb`U@ZFEM Tcf~OGO<7WUG%Ee+vm(c}LIO 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/charm_auto_smelt.png b/src/main/resources/assets/ebwizardry/textures/items/charm_auto_smelt.png new file mode 100644 index 0000000000000000000000000000000000000000..3acec715ad348969af050d093c7d8eec50f8c9b6 GIT binary patch literal 419 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/charm_flight.png b/src/main/resources/assets/ebwizardry/textures/items/charm_flight.png new file mode 100644 index 0000000000000000000000000000000000000000..7332c485fa43669bd00342902076a260388c500f GIT binary patch literal 5949 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/charm_growth.png b/src/main/resources/assets/ebwizardry/textures/items/charm_growth.png new file mode 100644 index 0000000000000000000000000000000000000000..408867e53bf12c0bf61e7350bd4ceafc794c9879 GIT binary patch literal 5722 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 Rmt~-#4o_D&P^Z4DT~__Br&akU!?Ifq z0!|^G4nDu1zt8)3=jQ^6@;64BvvB!)m$ChpN+d->TGo{UPvh zEobWM?|1DJ51jAmpL*b4C6`$IX?G60MeAyAFx+`nutmHtdCuwE7uvU3hDzEM3QuB= zx3>}5p&uyZ)ve$CTru#BM$ zt@RUT=YLxBPo3O*^6cD8CvWGbyER!Gat`cHzDbfSC)V+OLB|i|CgrgHNM&jb-lR2 zt^MPu^5q9d6Z%fbu$US+)i%FUJMjGXN69^05+%ZEN0}~9Y-hbNUv@9+be~16U3^cy z61YmG8C*UbI4CJ(P*5S{KCkaU4wGO*h`^KwR^3l|qE1+@E10xa;V6?bw}JUFmRYOb zRCI0>Y~oPA=fPm^;X5I9t@9t2)g23;9Ep5Br~Kf`ZoSHn%7^#x*S%Sx>9OG;tGv?% z0cRtvtg9=pFIW{A{6ynMVXTXtTd(1=7EfUv^&YNzcJSqHY8nSldGB@6ZS8|HaZojbQ=rk**wcgwBmfm;1F6Zkno;~|o`*-#= z7t?yxgPjdy);LNX%4|AT_J}P#p+~pzgMoyC;hE;m&L^Yf&hVb=J8^>Rc)=y!A}!uy z2NvWWS$Fy9UFqU;9sgzT@pL@6pKy-nRb0ZmiQCiHTs7ghn#t2^BC|lQ=}or9RpIPc zhTcar4{a9J413K{&-X9r)r#KD^H-|Hhq)i*eC<8AR3&uzmRGihrU|A}4?b-)nP2*6 z%b)$yi>BRmF`ObayN-?1boTTp(X7O-v-&@bmz(#04$j{4EO=jqQf$la6N-7SqC;ap zHatGJLE7}3Zq{_~f0s8|Pu?b*zk92#%<9Mv?~j}3dBr%n&e>+UL6vj)8=c-4a?yp7 zT1(d-%yPDIzNn=7J?VJsyUCZ{czKlS?%{4fa^i6B;YR88YpmWeM=slURB#jfyt!<9 zZ;5Z~+weDUj-^&mlKH0N|F(opebK93e~e+1x)rhDY3#yOR)#Y^P{A=HFIPYG;_4f(;QvGyJ?>anfhnef< za@U;6-rB0?!+Y+``D=Y zUu5nu|MAWk)Bb&N@0QA{J+7-P-?~*clJWV+n~84cv(L@nH~-PK@`5fi(Z}0M)sJt! z`{?hpf}0VuIG?}T**bIa+`}PnQdeE6HF)F}@ay>A=gFE^A0OMs7Zh{;W%OU^4F1|@ z(IW8-g;Sora<g!$&#&98*7XVgm-){frl{9ixw3pA0|NtFlDE4H!vTib4BEbH{(fa(VBjq9 zh%9Dc&{GCs#)_r(Wef}q>?NMQuI!Ilqy)L-|0w_KXJBBEEOCt}an8@pP0cG|a4t$s zEJ;mKD9U2QS zVhZ2BhW-l|-6!bnbDHm1p!tJoX0*(bU^7P+MUh7jCWtV#3Yo<2nV#*l#Q9~U-uF4b z|31H0eC{gSU$$#sMg5ldroWW%6W*O#^m^|n{bh5x?QEr5ch%RO+!D{pQDE_kNgzLH z+2qot9bv5e?y--2xg5lv8j0-e=n2@vUN7-4~IodZ+qyPIY>wh8ap2Q?!F+O;G8U9?{w>y(#5bXA{<<) zBDQN3xV`3=Di&Dz+J0Jn=hs15z2}eT75`-XZ@Vt7L12>o`=^`kPPl!|W5+x%K?bH> zFJ%-}vVC6*aVSb&@Qr!GH*uTy2XEea>loR?y%ruy3Z1oWzm?X~1yc^)K5na}qcrD6 z{=Lewn$~^$0>634w@!F-&*y{nF4s#+kp1XD-WhiiJdjwaW}91 z^1t8-d+nTCT^SgXt2^fGUr=zF@p_mD)X4x=ydyje~^$V z$$0n39UqRlx74fHZ6qWm%RXG5Y+SMT-YWOi{|;>P_E4M5!PYEs<@d)QA39F2miZIp zY_YNbB>&Z0b(2%<=BKMoR`fjfxNy=F^J|kFb$6;J8ZW;8jN9qnz8RJOHPsmy7#KWV L{an^LB{Ts5Vw}%C literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/charm_light.png b/src/main/resources/assets/ebwizardry/textures/items/charm_light.png new file mode 100644 index 0000000000000000000000000000000000000000..e7aa5ae68de6a2d12728e8aba88ca622c1e1d62f GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^IrxLK$YtPnor! zfq{Xuz$3Dlfk96hgc&QA+LtjfFtC?+`ns||;$au!*A)G3ro+I%AX(xXQR1ARo12dAWn(yol^-_-4#DyysI;9dmzy$=Tn9Iv04BikY-6EbJl z5eK#9UI!h2F`jwxM*V|v$0EIRO|z5tIb3TFMP&f@`Zo|DWI+ey#1?%=pr z#9qGt|J}XSAJ*quNL)R9aK*i_qGnA&rdQ^)-5z-^#B{|DN42c`mdKI;Vst00gV6hyVZp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/charm_minion_variants.png b/src/main/resources/assets/ebwizardry/textures/items/charm_minion_variants.png new file mode 100644 index 0000000000000000000000000000000000000000..23085a5d795062eda0816ee018f85479c81c87b3 GIT binary patch literal 2098 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-Csc(*lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{7P;w(2G5`8BE>8!W`#1>I(8nEsh@Oq-Ky(fr@h;@m`BxM ziIJ-0)qlUYudXjJ)Ju&Okl%ZKN6was!d8o}PklCd%iQyS-RGa192?8bGubiwTKvb` z_Y%_2JkQmyp3AbkIznTc?S%R4m*P57^9#!ENJ~aZzu3FMt6K4Jb^7jq&!0~F7IXnU-!msM%?jhnx-pR51=@ap9A#kYQZja&MC+aB+0hg0{@wOV&Z?%C6W z*J@5b=KEo(+x(``{Z7*qjgG}#3a58)yC$8uaWZJB%iLQz+@cO!?pQ2H)yr9-A;FsD zq8FTJo%c#cp{Dgs4%eZB2TqBL&ANSTXRPAEV^duet2nwZ_DrzfakX6StDR7n$LXV@ z1s_kCERZ-QsOdX{&2>e7&|Q@uch+COaMi)lJX6eKMv0uZ!@oB#`1Fih&1Sr~u#RO} zz;~tv92_zSCNwhLnq2tAlU-z+1B((Xld3~{vZb?FQJ=QMCevfiGAWGTj#)Q83n|-k zMx#aGkmP!w1~U)ej?}fze^|6T7C!0Oe9rQHldyQ~r(^v*pY47G1_m1(WD~F9aCGAF z>=e}Y+ruK*IZ4UAx$CvkCqu6uL)DyF8;TCy<`fP(HOF_`&D8nM(`1UZ)^urZ+wsU- zBPhvp>gtsz9>2<75tQuPE9JEE=CfJ(3q8AaOIxDM@0MM!<&Uijv5j4o8)<*XKA?A7 zmd#Wt;loR%)+o+V&6px=Zql5T!`alnkU{dOjmc%FYo7x0GL|VTYs)Y%k$w~+)#d1T zyCZhF_wH!Rpho;u5Y`ayT0|^Ti$&ko2Tn396$Jj zf%D6ohnYdkjh~7CjJ45S{oNuiI%J0B;)SPfrz)SkHnH@;nolxMbe2wW6My>bZqfUw z($%|S({8_Vo5RzT#aq1o#!P`IsgKXo?3n`RbnLNMs$Zb0^L)b8*I#AU&IsCfd~($# z?ftxyU5fV`T(WI%G`8GTdGuV-uM%hH|O=d=qb1M z3Y_yOmCRjJBvzjGbH^+<)`ZLb48ex#mp4}9?d$sYgTNryjea{e*zGXAFD`4A zX8(l$rGUEbmj0>FSIfLi&fogjSKT~(Ta*6n#_5k2o3CAO-?`%F+%Tm+lPw*8IuyL;BvU z{9Oumv#PK6G?&EPIdVer+0-r0f$`;AGvw-GEaMNHt=WE0{aGff*hmVSXJ&2QW+vS}^=PoBMUhS6x4_7}JRN6n1LI?9{rm z`&7mDS5r>?Opf}d>L+T z9)3c`Wu+v~{x|K)hi2x8bAB>t_AI&O`RUSu`h$G`c#jrT^aijuH_9F2+Vj+-|80QT z-Sa`wDTXyRJ!`Mdxw!E8m!BVO-hcny`226!!32TsqfLh&9!T4qxc&CV+izd&>U&qn zykYm;MWHLhc<(-b)^(G~;p2-5ci)OUEZA``J}xfL_X5Ydsasz!(+J$cxcDFA)~#Dz zZRD2!wQ0KhR%F-lvu^|SUzSJ}f8Ss;uim9>eG6lUuItjnQKI?w{&!!OFb1p)G5B_8 zf=5bUt9thq&O5XBoX%i-hiN6@L_ z`ZBAON!3Z`SI@)KvRdVfI`i+GcPkQ|yz;x#@hhB@&d*=9(C)3c#l}+!_0ydg1gALs zdfcuSE+u9EvuOE`V}Ei~!X(~Y5Bd0G5)V($hRIdTtCr~9Nyw@SJ60>4qY{?!J90(S z`u+`*tIj@iZvT}nwybG$klnvS&rXYbec!RO?CZ2C{q~DjXkGvG!9VfW<$M2^o?|!~ XaJY4@;N!at3=9mOu6{1-oD!MFdh=m_`dWM_Zgto88tq{s7n^zUr1E!5^q-QL0wxZ%lP?~lK}rKIlr oxb3Ys4~GErUXdRYV*fE*mk7ThHv8=<1_lNOPgg&ebxsLQ0CrEE-T(jq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/charm_stop_time.png b/src/main/resources/assets/ebwizardry/textures/items/charm_stop_time.png new file mode 100644 index 0000000000000000000000000000000000000000..f1a166fd8098090746f21a3b5cd915520e4dcd47 GIT binary patch literal 569 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^JY`{xc*!N$-Eg zz`(#+;1OBOz@VoL!i*J5?aLS#7}!fZeO=ifvqUX-YC&4OzPD9i#5I9kNT-RX05D zP+lA@>(Hk*A&Gqr%Pj^AZeOLXJed=6rd@1Y{nPWgeIEP7ty6sC;WGe==j{!Ih?A&ZimX$hU2b)NOhwara!(S^Klx1^c&qxZdm)v$p4X zz3fBr#4V~Hw}oH&VAQo#XQ?Pt=GP@3b${3@F?@U;eph!zZoj_D{~Dh^7Ha>F+A+>J XFjeSlnR_<_0|SGntDnm{r-UW|Bu4Sa literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/charm_storm.png b/src/main/resources/assets/ebwizardry/textures/items/charm_storm.png new file mode 100644 index 0000000000000000000000000000000000000000..32bb5b8c51c52fce3a7f531023e0386252c9e6b5 GIT binary patch literal 1945 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-tE)mHN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kDl~Ki|8)X#Vrjg%=*=TZkBaS=E6rbiIsGov@_Bp-Z=v-5 zeb%fJXBP+FC=eIwPM@)v!)AhtP6|C~8}eSm~? zpJT z(Jv;ku$vsCtD73*#6sbw!C-#o$n6GJ}-rCRwT3Tuiz5M z^Lh46I834C*ug9MHP>_Jl_bya5H)xqenyb{%(gd*UCZ0IrF_)c@cEkL?x%jY&M`D_ z6jxg~GqL3;d=xpMwONSqI7gk4O?qL>0fx%+y=NHAn>+&gY@WNxFHJo?uiQ9@yW@k9 ziz6=+M~db1h4Q6>Qm5kf7~lK-;Hvxl8a|T>>T7uHnqIvUUYaZ*wu**zgfoms%d|6GpB^9mz#%gvpFBJ&PP{q*!(d{RQ9WbO_A zT|27{zANV++a3S$*!vmAlXv}RFHQ?8pYeP0_WX$K%C{PuIA#S}7;ZJ1a3kSD^0OJw z=Y1*6th<^xW!v+dZL4p@x-XMGa%}SFC&H%Y+UL&4zMg!k=GMpNMw92;?yL)FjMZ-F z@b@&-HST}wksDe1HRSQ}yqV>BTkOI_PffnEF?G$(8Bx56)-M#!v{$G7ydJ%4ZqnMk z{fZ2KUI*Qq_UtVCtJ3Nvy}2^4)Go#>I3f}qtKT`V(`>a+M&)ZQqhptP_IkanIhHVU z;x}){eZq0-ck`z8Ee?FoF7W1Q(uz0cX)Kd(D=Tv3ey_Z0?6_JwRz*&wC3Di^%gfk3 z*`{5cx&QdoDm$x%S62PHZ0sMlH0PJ8wSjfbea7ZBpWbBnq|e>z@p!}a&ZUZ(I-eWn zI4#qyW^WDKzr4?uBmQSX%B`z?G1fcYtuwn4{%~eKb7R;2x^kJML*E!rdSp$tFzbv> z)<0xE;n|woN3A{`lw#v`5463c8Dw~5;X3n!oU3IOmxjC*^D~KXUtRzFZ~wX3PyZI= z9llc#;1T=Xe0~+%x~iwI5k=GilS`X{*$(Z4rOS z{pQn-7p^JOL@(Uv`>^`a+@h%4vRQ38w;}`lCT7`cuLyQs`ZnV5wuGbdRmi5a8r547{OIFBjcZ45B^^j z|5`monXmHAG0#1DHkq^4Y_F_9wh2cdD5y;eenB}gU!qTUVZ*;dg}Srj~%aN z%)Y(ya`~${@5|5q{A$fpzhybY!>~IK?;lfAJr9)=#AVeie!1N^`BSm@M$yfU^|A~G7i=2V+|rpg zXNrK_fogqbhN{`QC8EE5wm<4CIaahrNB-iw*7lXF8?JrhvpKczgi4X;gv(FW_PuSq zzL{5#(`ZV>igQUzuWv4Qa{kV*t)j=7<9lZD_ALwy1#>5Ud3iXXT>W=gXN=H|*Yd0k zKZJunHdS2tBC>eH8m46>ch4_*Q?m2p($DYtmnNR=IoA7Yg=trY=h`67P=%_==9Y3> WTEhZ7x)~T47(8A5T-G@yGywqMAhgQ> literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/charm_transportation.png b/src/main/resources/assets/ebwizardry/textures/items/charm_transportation.png new file mode 100644 index 0000000000000000000000000000000000000000..75f8e7ef24afd4c8d31d82555c7ba56aae1b53c1 GIT binary patch literal 556 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^NEGf*72wYtJe$ zFfecyctjR6Fz6|RFk{71`!WUw2KEw9Usv|WEHZq0tcP~Q9%5i%kSuYHC~?lu%}vcK zVQ?-=O)N=GQ7F$W$xv|j^bH7a*+;-(mLaXM@ zoX5Js)=!sykXzET{iesKQ?4`Z6Jlbf{7>+|E^!<)D7O1RJrj}Li0ZFbTB zRqbX5uiZXtisi)m_3tiN?F*XnBz^MMt+^l5nooBti8dQ9a?qQudvV(2iLbZr&^Q^w zbL@o7OC8;{8#Zn{>ie#%vC-~$T@I&-ZjS5XV0RQq{u)yS_@hgtT_7 zIuQJ3l11$g_W9S9c{V@TbLjg?O~wr~Jtplvr@WnQVs!KQqzau+syVa2t(^N~j~oNf z<^;x&__PjQb7Oh?Wf~_B8F1&Q)>%ngNKXA#=((vv^N&RZ!={>|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+RU+lHGp#9X|#JCRtAx#}JFtTPN-J z7fzHoZeM==-o$Oo7aS2PDNwLdGLm5b%PiBgdYKTT=wk(D9XH=#VGoI{4j#T!D>|8* z4QFTtUU{K5sfqWA0*k?xE|Y`X;?{qEUAkx?qxfR~Pb&HMp8u_Dd;a&p|26XtK7O?R z@b$J^t?zTYRx_^+^@v}Td)zv6`@*H!NlVO+PMP^^hR$W-_e&hFFMWG3rACUO^7SH_ zz}BVNizFN@SSM>5pZ#-(IjvWu^PY;|Md8xQsRgc!HTGz&;QA0ded0Zl@I0Qy(`q#Q zABCCdTwgjR{@6ENhK*|(IdWw0G=U7idq~zqljFd}U26ND8U5IA!qla3t+4ULzr#E> zJH2@qtlsZxQki&+J^#_%4HI=GQ_m)9PCpo_ol6ff+In5dJ$6Fx(e$}d4hjAp=cT{TGz}^#El>EV*FUfC zV(nkK{CVjcdPJ9a2`KMAajV_;m3hdnU(qh20^4FTOTI|H@8&+U#;@RIO^@47x%7Xm z46ABbtn)Yj+vt(3>Gb?*w?@^DZ{ml{E=`{`rL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/crystal_fire.png b/src/main/resources/assets/ebwizardry/textures/items/crystal_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..a044d55235cdde80cb7c9c812b16fee0322356c3 GIT binary patch literal 623 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+SMvjESjxg&G3`;~!5K#}JFtTPHhu zOiq+IUZ3x}ku(0RXy2KW)fSR^FVJ@>o58x@M?)SkePyrZ(CyZF)A}^`jrr|ByE@l* zx1B?RfBwv5T7LP&=lAZ{G)~k%JM~A=u+Fk!;acgy6AIn8HGMR;eBl$=FTN;G`^}au zNhPHh-t(MZ70L4_3eJT@hqZ@n@>Z zu00wr(|`Qt|7;+_xOQU6BimN?WEE4$C-1Mma e^I`j=`YRt_U|GJVe+>fz1B0ilpUXO@geCy+ffI88 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/crystal_grand.png b/src/main/resources/assets/ebwizardry/textures/items/crystal_grand.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb7a620cd182db086c3a632a3895c6a0f1bcf52 GIT binary patch literal 667 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+RThUTnIx=z0bQCJj#)#}JFtXD9i3 zOlFigUSEB`+|2u|Lg^AQDL2-uOPym=*fllQE)5V04Dnc+TIV(+LQaLLcZJ5w$6`_v zF0!vwV!Iscj^4SFnQ?aF62&(&_ufBHlVel$jO)?9o=dN*^gcL+<^tWWJ==)rWr0;@Y)aj^To_!SQ>{?kiWX zciH#;8pAVX!#TVEbtEik-nA%=X(5Z#tgdxGCBE$VIJ@LZ!=Z)EtrqSIYor53|32qT zj7>iFHsz41>&KHaRlDXnsW^Ew@3>KMrNb%F)3PtIccGp6ds}Dj`UM7`Kbq=oZ$9}% z#4P&r&xE)(NAb3|#vUHY83{d!@1r-FElH}r*mhEZjX`w5-o^XvZ1qY`PMUn!_;_*H z`txcp%#H0VPOQ Y?!GNiynZZ-fq{X+)78&qol`;+00$r`+yDRo literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/crystal_healing.png b/src/main/resources/assets/ebwizardry/textures/items/crystal_healing.png new file mode 100644 index 0000000000000000000000000000000000000000..9caa21f164d2a23c0b7a4f57a24c6cde49fc24d2 GIT binary patch literal 618 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+RUMTai&C{VM|l<9AON#}JFtTPN?$ z4i1z!R}+}yq8#iQd_><_peS$V^C;bf7E2OVFi z3AzLv@swd|QpkOJ?VyvvwP`Bm_su`vn^WEI?2*ySD)`H%o%wwK^F8OQ6ZF4+`6iGr z#=q*nS$%}fny9mTylf@zi7Ndw;XT5^(=r%~qMlx6d{xUU?e5dX8NGs*B$JD|PG-#Tpm>UGL+2o_WRR>+=O)U*FxitKmn2 zL+swqt-HR?$#PbD%M*81$)rdq`>W`tAIvrxH(&n=lCy0{bAC9*?(w>r5nIDP_6B9uFPR)#dE(@Bjd=C_4U=U*xc)nAbF z(_&_-OcTS7ODww^mq#m@7q&PaxlquuadGQAVWmXg@L4Wj44D`Yzopr0C}4YtpET3 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/crystal_ice.png b/src/main/resources/assets/ebwizardry/textures/items/crystal_ice.png new file mode 100644 index 0000000000000000000000000000000000000000..aee7e55a3cdd69ae29c2da36ef549a3125befc4d GIT binary patch literal 562 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+RTdUj9|q#hnZcjQc%Z978Nl@11O$ z5gaITy#BkYul36*w^j&DeDp*iPp?csgk|Hbpxsl1j$cvqs_B^Ir?f<2{WaGmDJz=0 za#wn^gmKqxY4mfnl5BSAxM(Kd>X-THlV7{p!Y8Un%RcZ=KW+QH{@?eSJIw!?l`ehq z`z`)__TuDC(>>-!MDNc1*P*DSWc~Xd)2|~-UI+Wf;Q@m$Pa z2i4^hJB}CRgst3Wy@2a|kB2SO)iaeT&$x5*x=U(W|GbKCV|Ly%Z(g$U?qgSeIA7h; zu~qK;@=1UGee5l%Y5khSINdq;w=rccYg6QOVP?~A40TISUukKS%R z&UHX*`jSh|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+RTdQGWIMQ%4vWm~1^=978NlZ=D?L zF*#A>c>VjRbC=Yr9=eNhPP(_GRzg(h)^wpM9v(@Of>Nc*87x|triv@C^w8I8b+cEDixBj@~qtwA?Q*iFErTsa}Km334ch~K9 z{!{wt;obDF>#!#_MDg}`_dvs+WwGZS>{C9*9@9l`Wi}m-UwekB$JwQ@9Cn1bgQ#- z*WcKu+WA#Y`PH1}wW-HTJXjud=P2L5q#IX$UrF1xbJi!DsA{&0CXP-?GMXnpa+ESQ z^e!PYVD;iy6;_N4vS?k}cdz4Tne|~hf*&p037N+F>;k;kc zN(-m!hj-U(IGQ-riBRvuW2fy`ZFNMjzA?I#3(G(ctLvz)ABD zZt*|7(!(NU_P#BGH&1?Sp^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/crystal_magic.png b/src/main/resources/assets/ebwizardry/textures/items/crystal_magic.png new file mode 100644 index 0000000000000000000000000000000000000000..e74c1d92416eb837101d4c621d21ed7fe805f8e8 GIT binary patch literal 519 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+RTh-oVvtLJ$K3;}lO9#}JFtcPAQp z%nlT3-T(d9aubcO>k}?;O;zGZ`3ha;3l6et$`dN6*T&H4o?v1ANcHMT>$hj|I@M;y8qu$2D zdAmHiGY%-~uc&<*wPu}ztA)nr1}0yXPwFzK-J%*|maRE$dOh5B#$28(=XY6}lW$E( zU2^k)=i=_aPXv#qS%gf#CBLomVddHP_BUs%O}k?G@1bE0v;IV{hXoGN+fTagK9D-A zrAFDMdG(S@FZa(`|Lx`_$@Z20D%;FH@a}u$taEJU#Uqtz{THfdf4C!4yVq8w?nvZM z3&mH`7!mg_Oi|0PkxDMuMRBC?qSGhZ!5h&+s};O zFHpk9X77=!w@#fue_QAL`Ht%3n5a2o3E59WG*~xjXx5#+{I)JmRsa0E$Ffz&>Vv|Y Y>ZTTNDqGIUz`(%Z>FVdQ&MBb@0GZL>!~g&Q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/crystal_necromancy.png b/src/main/resources/assets/ebwizardry/textures/items/crystal_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..b7a1a759661abfde6ab687f3b99f8be91c681e0a GIT binary patch literal 588 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+RTdj+1?9=t>3##+#lljv*GOw@&u; zxLhc4-2Q){?|-YaTiwp(I$ABhapvZNT`tv*hpLx9m@mwJvhUK;MnT8xe6m%OPpm6l zd3cise`3M~s}!*nPork5e0gMVp6&d-9a8XUs)143eW%R2eKGKREBXa%0X|0dl)#<7d- z%t$y&Nk&4I(qN=?>}}ZR!=|IYPm<><<)C#CoG|pQZ(ElHr|L52Gmi=;vBM(~hxc~cX z)bY3W=mCu%GcCjo3=9lRuIr_|c~gDnLwE2L$2RvF4-bEj=6NH(ql24SB4SGdlQOgO z#sBql{!9G(o1BpFC`suaD~IzhiK&${Btw7Bkeqr{Lb5$mh@D~97}C7#J8l MUHx3vIVCg!0DvEt9RL6T literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/crystal_sorcery.png b/src/main/resources/assets/ebwizardry/textures/items/crystal_sorcery.png new file mode 100644 index 0000000000000000000000000000000000000000..9b76a9778d4a2475e376befae7ce6b72844d5741 GIT binary patch literal 620 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^P|vPA@_#`s z0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+RTdL3-;=`#B5@j6XeH978Nl@15-L zaXC@unEn30nrAGR8nT&9lok5&Nb~aKD+hTK+xc4U`%h=F%w8P9`7l*3=?35G(`I|# zJTPNB#nCCmrIIA%d~>1bMi-N#n%OxUcg@Ie-#A~|wb7A(&++GnKi5{o{g4-OnsZ0z z_nJd>kH6hlbmDk2!8@iZq?)1Vgz7e}>P7jVW^K4z@=r|3lz-e|PTQ z@t3j>GxwcoxaOlJx$yo1Mulh_74aHP#uc*)e#?7?PCGHBjI-izOWJh9u+Sxw1fOuq z*ZEITJbqQJn`y$5s2N2o#s6++YW$dHYHZ&wQmg|C;@UWtTmz*I(}!KA|}ML-nF1THYmb zl25O8vz$+tdmJ%aJ@{7Y(jBK7uJJg`_EVpGH%z;A6~m)*>XUMB`R=@Oy8n#Y_hauK zM9faVVX$IG^p`ZQ+pM?Buh?|EO_@BEujt^CDbs1r;MT{^>8O84VVg-=IR z=HE7VxqF9Yh5M=8y+-4)MoM}1_lNOPgg&ebxsLQ0B=(fxc~qF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_0.png b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_0.png new file mode 100644 index 0000000000000000000000000000000000000000..401c1591d338c5191d10af8b21f785b0eea165b1 GIT binary patch literal 1979 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 N44$rjF6*2UngCM%i~9fo literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_1.png.mcmeta b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_1.png.mcmeta new file mode 100644 index 00000000..eb5c833c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_1.png.mcmeta @@ -0,0 +1,12 @@ +{ + "animation": { + + "frametime": 2, + + "frames": [ +0, + 1, 2, 3, 4, 5, 6, 7] + + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_2.png b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_2.png new file mode 100644 index 0000000000000000000000000000000000000000..4317eeb8939a9ddbf6dea487186ddb9a729c049b GIT binary patch literal 5994 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 Wz-(>t7kT~p?_cjf6(28u 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 TcI;^e1_lOCS3j3^P6(%dC? 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_5.png.mcmeta b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_5.png.mcmeta new file mode 100644 index 00000000..eb5c833c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_5.png.mcmeta @@ -0,0 +1,12 @@ +{ + "animation": { + + "frametime": 2, + + "frames": [ +0, + 1, 2, 3, 4, 5, 6, 7] + + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_6.png b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_6.png new file mode 100644 index 0000000000000000000000000000000000000000..56bf06f4d706775eac859244abe75869f4d465ff GIT binary patch literal 5743 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 bXLxJ1=a&D{rO>g~>JbqPh!O0$;^ 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_7.png.mcmeta b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_7.png.mcmeta new file mode 100644 index 00000000..eb5c833c --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/items/flaming_axe_conjuring_7.png.mcmeta @@ -0,0 +1,12 @@ +{ + "animation": { + + "frametime": 2, + + "frames": [ +0, + 1, 2, 3, 4, 5, 6, 7] + + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_0.png b/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_0.png new file mode 100644 index 0000000000000000000000000000000000000000..401c1591d338c5191d10af8b21f785b0eea165b1 GIT binary patch literal 1979 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_3.png b/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_3.png new file mode 100644 index 0000000000000000000000000000000000000000..754012d9f38f9f57426fee46914a8ac85b4346e7 GIT binary patch literal 2012 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-H&=y3lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNUGd?m0Xvxd}|D>MD*UVAQcX9r5vbwup#Zzyw@Y{cHrmb0Xzc_jQxyw6t+7?J8ZP}Aw zYyVC1aaFzI2}%9)kJYX`R+n?1{`~QT=V$olCX4qgmsQU>x7YLeULF3^mhpV2kDmSU zHIC^(MwesRu~M~dKfV@=xv|W#Sls(sTsS%9o2+r2=sCM1=kDy%e{i=-|HjRlV?QOi zlK&ch(3hB7c&UG5G{@czWoQ3<#qY1CesnlBd-IBH&DHFOnKUZ* zJ}YFc5&gSiU5j>7r|1In4Uq+*&YdzBOyie!%#=QONpOzfy^7su+?(xp=Jg$$aY=R4$2QSN zMZpam$wub&iL6c;GCrjbck6v#ApP4xr`a*qz+K1S_NG{orMtIPd_1!uSo>Js&ftvW zj0%VDbR~2gZ1{S_YhF%)o&e)eMMMx6r+8y|YZJzdgEIE&pdtpk={?1qa&&k~|dM`-Dt? zNhI}XK6@gxxFz$G<_wWwFU#ahJl7@j(<7e5#5`1T?bcs-WRlmq3I0=8UA-QV>}zU% zeTU-T+4%>z+z2{7*J{a?rP<$YzuX8u&m1Lflk(z&a*xHO6Xw_WR-a#Uk-Ip4vs?St zlQVR77o_tZR*cchm?k`TPNShZ%dx{L3{7Q|jio)0_&!rhKar=>YPG@5>SU&gBy;nn zlP?!YmzO`=_vGw~nr`#&lErC3-_2(jPu_L-j&;8LhHIa01y%@}Y%WO3s$8();DY0C zlIB%k>W|)RrTqDuDZ}jt&kpT5xGeg0s&&w}+bX6lFL(N@83a{rT3i;)KCMoNOXtYC z<15bG&pvyb`H0!Nl_?R9lJ zpH~%iE^XVpA*A|A)U+a=X|W7Rz0zUUF+S4#Q{q}`zf4t_qqtx6iS&-6dF(S+yySD4 za7uky(-ofTZBnz(3LDH(Oz*qREVtoY-G0rhO8d9HX7LFW{q|}po66#2-hVs}-PyQB zw4!y{*K(=0kgq2+jtkDb_%3?w;VFkK^Pg|LcIvm_uZE;C4bHY zI~!WtZhX-q`|d`)nGY+szCzvup|Q^5+~9D-kUte9aUFXbT1F7)j7(Knt-OJ|-fS$j8^+wtoA*%|%H zNBTs6`&|q6xuf%DPqJ(2jwDm#8{3MvRa}`R_*LiJw|~8l()yh8N{vs?NPX0F@c2Tp z+Xv6tYOZ@Lk?n4g{Qa-ZdMVqU@9l{aI;Y*F(k0t8OPb{^h+LQoz7jXno+Kq*}?6ha1!Ng`16!Z2Y^Xwck5~Z?;j{ zyVV_KQ%+ZKG5vFj*>i5rFU$I8{G8A3`A4#>{jr!~ji2D$YVF)#jmXhj{y7Yy;yxW|*V=uEtZC}wURAe10^i_Y}6Gy3|=LHSyZ@tic zzIp9phJrWB^MkZC&TWegafBQ8X_Mfv<{R?Yf zp8nIC@UPyzM>)gjKjY0U=C@`EtHv@gFt8;_2(k{+NSVP~6gT@uMmR2F6vME{-7xti`r z{{u&omWy8ea!i3$T(!HYyQxI9w!umBt+a>v-7k{ASd%#+Ie!e?w=hy#H`|R`N$qudqk!Kkn z6hGtGnsU(aF0WWm(-(f}DQ~U5ezJVdxcZq}~4+2^hBM`C5ThlF6v?h`*MrhIrI5nOxl9ozd!?4QD$C;yzg$@QH6>)X&+8=zd@IV*_-v=S zC^h#Sd0f(bn`hC=EoaW1N!;_ZA^MhTqKm|fizfH$?PhtM{xUtZbJ-=P4Z*n`^6PS2 n4u3tm`g2J9h5BE$C5+Olvjq5sWU3e#7#KWV{an^LB{Ts5(=^HY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_4.png b/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_4.png new file mode 100644 index 0000000000000000000000000000000000000000..8f100fe010698d1eac620d360dcc6144ab1d5dc8 GIT binary patch literal 1996 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-w^xNklmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{o;~Ta2G5`Kn%_7$I9ZNAjNEE|<8l7yf=Qm6KHt(`XDD&n zsbo7#@-O>({?Fod=QbKYGHnxSI_f`3W%|X=vj1h?Vb}iJ+*tiN@y?w%3m(I$d;JUL zfAgW5W-LZal(uLHdTyj#Ud?_%ir~vZiDP#OE&U5;$7AJY(+azUvVwr6;etcAe>N z3%+ofN1`z1pj7gWyGaX8^P@h8cFou+s3Ut&@?rP%(|e@iM{y?{*bmFRIUHX6LkPS&(>b#hNvX;+j{v`OZ>y@3d=M zVR%fWxTrJmPz{%-ZlEp&E13AmTO%sTQ#Jg=a<8wZA!|1-n>9Q8 z&V+xuCZ@XEt`sfj(=2_tuYH~Ew=16;uCeh;*0n5D?lbw+yY=uZ_iHaYcb<=2eE3$1 z&$PMsA`fqP^|UF?^5bMibnyjFFyZ^~gaPu@hfcau4Lrp$Y@;_j8krSjcO+#6q) zZn4ifdz$-**}9b}AqgU^b#hDG`QSs}qbjaEzG%?p`r&7kRam2M*EWd_zprlkC{mPI z%F(?gclPpI%GWpb@J@?mNa~divySnR=ARPRQu}49!W_kTu1`N*?{9u$w?ira)6(;0 zF`e@{ZK_SpW~(PyIG>Z*&Tf-1w>jQ>Le|9i--lUz0!7W{1c{z}@mRG^CGlOvEv`LI zm;Y(=I}^o-*!g=+}#$I_ra9aDJ|RP?KJ&y+zA=f0u8Q-1=f;_g|4%h;r%8s$KmGuRgcnIpU>^HoN>VV$2-Y2Z=dKgx~9AAKe=|>_w}o1S57;%wjoV& zg?N$0F-fBb7d92MpL}tPZ)2H@@vS7@+c#{s$i4b4b#L(|=Iwl@FVtrJv3q>R{M4=B zXRf=va!*wWH*;p`tJ(Uhamy=3PMaa8eJeKa?*f_9Sueb99i8yIPB(kE(?k2kasg-f z<}aJDLT+c;#g^FrE)ud+9Bij%=Y6-^b9dJJ>sQYw8-ITgmuy{W<}bJCXzm*;zMRh- zg_DGq&vV`R)6=VFn%1*ZQ%jaVNsgH2|Lgo=zDZl=IFRFa2@}{7mSGrstcB-yVazk_KKaKrj6W64 zLQdE-Px^UZAjPDy`=+1+U8$8 z=;5j3k|C14^^`rPSE zPo#!cUCNSKofA?%74DMw!z7%3m3eyg!+FnZ&s%

    JKR7-uh6NVQbPu>ySH2(Sniw zDxNdh*Qih8FFz^XVz+kL$tkXWpHvOc%LYATtlqhZeSKwtvu;Jk#|fR6bAM((XV`Ie zH-k^DrL%5CLUm=7E~B#0)TQ~KUtHD7cVawuw<}F#-H99FU%uA4{oSMxvY6@X--X*J zt*-XFZvH~|EklZSlj)LITLivr`+G$G$+0DGVixV^3M%9_*}C_!&RjK{NZ z!tUm7^ZnWNDNI(qzGuH%+8^8fiodWRC(PTrQmQF`qSLejckR^YliuYuC!~wZJ2n1d z+MhhRXwTF|Rn-SSs70y0|73T^dG@-i^}p{f>JaQab^PUgBk|u_)jJpc_*dGWD7yX0 z3YC9}%0heFdp$zRy8k^;H+~@@@wh~_ZSUqaYj5`HC%-LZEl;mbk9=Hz)c&*gCTk_r S_7DaJ1_n=8KbLh*2~7aaQM3a9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_5.png b/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_5.png new file mode 100644 index 0000000000000000000000000000000000000000..f43d6b4065bc8996b8165615e51426d312597ba4 GIT binary patch literal 1977 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-H&%s2lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNUGdo?T?3&hzKIW)aH~??)CktBaat?0GYey^g&-|E*W*aXE<# z92f5j?N0mi`MXK|!^bfK!b;w!G$U)A_-=}p9GQ1M^JH7?b@uAgd%d%(4<(*h{PnpZ z?^b<@{(Sv{3m<>g-6;sRU(}~}{?&!`Q)R8P)L)(0ZS40eXVbp$Lx;=0-2YrwC~a@g z&L&}-biw*@n|gksf3|2pN6k0ZwQsD&j-7aA{r*9`mXp&%b@A+7+cs4jtZBIP{<@If zv3i&J-=`LGZo9!y#Xeg!+<3}K#lGpH zdwjuiX@f^K%-M2>-}SYA+f}*#y2pkh^$4pb<3rN=(|=}sFu(pb_*i-TGe`4pjS>88kJ}r;sXV zx5u!GNcz z@Y314(#7$g(vp4%=D#z3c4pDL{R!uEUQO8v`*{31OU~u;fo-fRfudM&= z{LE7$$Nh8<-(uk|ZgrPAO=snou>Ve4UMTLG%6U*WwTN~a+Z?RZ8@z)3*t4GLEsd^g9Lg3q4;|Y|P)GetD^zMC%Ia^SKLN z%-pOfa@frO$qJt<{mmDmW;?aZIJUZ6dNGYf+DY%}qLcG{ofjRmSAE8Xi zShsgk6OYZDZq~N`r_F*{Ew9eEDRxzq1WqnrGP6C#VA|%ZCS4wrssCzsSXSWk$4gx8=P!S&^?4Q@ z`7+cnapi*hmYvQ|*p8JPx$UpoeOM`+dHTAeeC&N!TVAh~zq!CD%5vjlb(i2B!Yq)KC2<&?LE3hZl zwM)xDiLYbD(hAYGERzyPMn|t3Yl3oOF7@{@ex52Mzxi43m-0f>qs22?*6aJPeCij} zU?b9dKk19@*II{VmC3Fdh=n1fkRT$1VRp-l`7jGdk?jv*GO_f9&f%@QbceE;Dst92%|o%V3b zpUk~fb5haG%M-fo6Yj=L5oSN<_vn#ZP*Gsg?Uq}cqNDjXrEWIf&3?-5OxN70cW=i2 zm07lRb=kE!e_nl!`&&2v{`cQ??-|XSeui#Xu#=%-?y3#4XVyR3=TIWZ73|Y_*;OOv zTa6@~}Ov)LJR-r6<2 zUD1$stuTz2#dF!!Uf(%KOnkm?T@;+tIKlg&t9Rk!WaR{RtqUm+8{STRUp6_*Wa_

    9-fW&Xv>$_K7q?QK*`f2%H{ zGLtQw&vQbG)U7V%S%xd7RG$!AbFjlPgmb;><&@voLl2!W8D=psFfe$!`njxgN@xNAEupem literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_6.png b/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_6.png new file mode 100644 index 0000000000000000000000000000000000000000..af4cd7b57f545018045e319f4ce19eef35cdc2d7 GIT binary patch literal 1977 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-PgaFQlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNOimo?T?D$@AyD<~I%wMxo;mBe$C0c%1)vhUXiL_3O7~*@_-E zkWwt&-je*wzMlWHxZOEcQ@f61B8!h6SDznq%;oLBHxt*y-+z8AZgP8Rv3)^AQqP|J zWczQDuOGf;{g}SjW}WoP>oIaZS zr{+Ct!j=ZtvSX!c+kW&Fi@UMRu}Hr1wYPVp(eu8_wJq0g%&h*!a?iH<(79)u&-DjL zNcTI|9D1=PxT5#2(~Hin+0WbAmqu)SZ~uOS^x~HiwdvDqS%NOkS+XwV8c!Q*z^5wR zM?!yC&!on3PFFh0bwT=u&W=?JUHCHiKV8wdykOrkFHyy+>vI!I)>*}6pL#TDb+?GU zzLcMXzj4BmLe}h_)bis_+4r}6TfOAQPC*^ngOU$>`KMQI{h@ySZAOn~tkP=pu#VHd zj7mKx@BC>K6;@)^7cUN0eN>wRSq$UA-QVJav`n)jKhd z+dk!Q?999sbb7AUk}I|Rwq-AG1)pb*lD7H7q0A>~b?Jn8cKcQLYcD!?u8&-N_*Tjp zee23(-qT9cxo5pq@i}*3#%GpesYVQryHCyx{dCXwnOeHpSvOIch{XmcGfgC!oA*uT zZq9pmZ^rLQ=E8s0R}{}TOjj%Y&sv-oR6gVPiQC-QqT%YaG+%b6>-$qk;o=xphGO_O$6!ov0vipP~mzCGTG}xZz2`igZ`$Q(IUw?WOYr^n9$M^xmBn z@}7MDi2L3gK}Ca-pqu#*m+JiRe7^mgt*hDcD&}dV@TQVVg@5Az_#F7)Wuhqq;zxc2qJh#eb!v)Rw>9cw>Pjk1=st@18 z#{M`zt9be{xw&ofTEHcdE4z1D?(?my zF3vUmw|<2>sNb+;A_W<6iE@I@wJ>MFK6?Zq-!`yPJ4aYQ@}b4U^ZlhrHcnY_Tw~Bw|`+|#W8U-(|nV`tR-DebrUqm8Ob{h9}Rb~w4mw)0(_`zz_y z%V4Xs`B#59yqDc%^4aqI`%;THnmiMxKbBAaqFLtttjYMwiEK0enW6p)W#1N0^YcF) zn6;EW@9g;#f9p)vGylCHB$r(M@bn+{gMa4tvFy(hKJr~(r%6ZR6vNX43=9lxN#5=* z43!K~3{&5n|C+lg?|q1WL5c*Y<3iv@6W))8iXKyHtbB!p#3OOW)Mc7Mn8n>JhiIhg2r# zOu3*kWmce(S6*+y*``_EhLaKx^45xNmt5SlQ#*g|xs{)7-~XPwkJ)a?A~UUbx(r)$ zA4h9tCGS+)mFT4*Gx5g1#wYLjyd+BBE!hw=alz!Nt%tX?91^swEo60gTUiikSds9w z>-9-POS?jb4SDkzXGH9}dSwx>||c1GDxqFfcH9y85}Sb4q9e0Pl&a AasU7T literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_7.png b/src/main/resources/assets/ebwizardry/textures/items/frost_axe_conjuring_7.png new file mode 100644 index 0000000000000000000000000000000000000000..0824b1eb3fd9f38e51aba36b085b5ac36ce5127c GIT binary patch literal 1915 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 KxvXx} zTkkBC+0@(l@Y&h(3fk{%{?GXH=y-Mi_r2c_?w@!3&b##zzO6P}43_H|*cbC0c=d0~ zmhx$_j0#f?tUg>csP0{B%e#Po#q3PZLoWOD#lnqL&IayzH1nF;)w5eNu5~U`*|4$r z?B~7h;WbPOc41--t9S3I`t^9W_l|uYkCn97=?B@yOn15|_Ean;UZrYRTfW}qJLewm zeR+q+nnx|&x~b>SlSg~6eO3Kt<*?G)ZKdR$iUjUyv5L>6V$#kRKGMG<#kW_P|5bm8 z#%%^i^X!!^3+0|2xhOKT`DB2P%9r!2O{3QK@8|yV+RClPnt~{&Az`&U1>Eak-aeC<_e~sos ziR1R`Bhr>;x~Sco%)HetEBaEI!qP&;?kQ8kCQXw0lPNBq*Qdh%cEeP+j^@R09BwyG zT6AUGp5WkH)5;<)pU>p0+J5iHwacGhf48x%-*-OzQNM>M3#aPI{fbk$&h&rjdSw0W z+d0=Kk*3=h9jS17w<&powZRG56012bkGn3IOe+60BO^v|Wz&L;i#rbeOZ3?4u=LjR zd#~0$xx0n)@z13!1=j<#*O;|$6BVmD9C24H>g?Gicbgd^a`~1VS!ouQK23QEm(!1F z=j;Alc@gEwr((*Kd{Fxdr~1YNZ0nbat;m0VL;ldyH_2r+K3cn-oIEF8mt-`Eesd-C zDZ_=QSM}Fb9ecIjzsTHio)G_?^!c3e`!{UeymoKHe+>ttISYSnY%5tdaq7{`X*REK zO_k`?ew0$h*RW<~D}T=po4XOYd@GlqUE_Odf9vPjHog)!N{vb`#G5T&6tlr|{qX>e c`%k1Dm$p3Z$c+qTU|?YIboFyt=akR{0AYdC%m4rY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/mana_flask_medium.png b/src/main/resources/assets/ebwizardry/textures/items/mana_flask_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..e256f6c5b75062abe8caf17eda3eca746c845076 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lx4ba4!^IGsFaa~5xN z<4)D)Ia@@UCAgKDnVFfLx6L;_-28mKb$`|!u~@U_d^H>^rMr1s<0`Tzg9+QfM7a7BUft!dwQ(&g;__WSB`?{bK` zVm0G_K+c|mPZou22lhOh5%MKI;k2I{8yj02^P-yng_Yumxp!{e$FsbzE`7q}X-PjG zJU(~ez<~n^33(?IG=6q9YB2wL7MH-m8T{}3fddCL)OEksKdcpGV`F1G_P^-g|IRMf zj6eUTgLKxWiXUDZzFp$pXK8~y)juXRHa0dIs_L-p=bj*Z{H%MpgkIgQqXkbs#Ljuy zz&ZU$bE+?o%=H}-b~PgDD>ORP?>6{;K4-LN_t%bxcekbUxIVnPWa$xO{`pDWDO;ng>swJn)x&zbeCAgQ9Et$1gT8 QFfcH9y85}Sb4q9e05{^q%>V!Z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/mana_flask_small.png b/src/main/resources/assets/ebwizardry/textures/items/mana_flask_small.png new file mode 100644 index 0000000000000000000000000000000000000000..4d85ab29cab79826b2d92bb43737869dc9f17533 GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rm@;DWu&Co?cG za29w(7Bet#3xhBt!>lb$`|!u~@U_d^H>^rMr1s<0`Tzg9+QfM7a7BUft!dwQ(&g;__WSB`?{bK` zVm0G_K+c|mPZou22lhOh5%MKI;k2I{8yj02^P-yng_Yumxp!{e$FsbzEo0y z|DW>*4jf2G$UB*!@w2N@gZbC9xC9Q);I_}=_rw!HYJTWH_m9z0IQqWcGE=i{_3vc{ zcm67HhR+rfYr4;RqVw^oZFX(l^Yb41vitl{v0PVZ=)&rwbibi|yPV;cmh{Q15nDforx>3=9kmp00i_>zopr05oB%3jhEB literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/purifying_elixir.png b/src/main/resources/assets/ebwizardry/textures/items/purifying_elixir.png new file mode 100644 index 0000000000000000000000000000000000000000..67d28d410d6fb7a2a879c7a0981a20505b8f6593 GIT binary patch literal 1946 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-w^fBilmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{9$EIpjOWjD%_0`27zVla*VQ{6`{qAV+PeGpJW1=!n~#*Z zSXOf>r2ew6=l?8T*E9d4qscM}-8#FUMG>x%6YN-U@3nJ3#n zHvV<^G3&?W`)$5UuRPu-=REys@`bZAC8rwu^(!9VJ>T#4lFxD9tYoF%_02hIdoEJOrr?#)yB_N*gN(S%>W|*Z*7wcbxmy3h-L2wpa_s)TljKT% zEGZCgVD(qT?s%T!mqWKqKVNQE343$=KKq+v8CGuhSD&_HTA6Wf(YmE;q}aq9US7)< zoc_Rmf!=Gc9U|Uq81^=vZCWkmb;O~1!g9BnY+pmeRux<7mZoN=MIk zvvqr~lPoy0uF2F~a%b&A)BLEvV>2$PZmLRV-Cwba zEzjrKGug!s9KFq%5kJ@4ZaSpnav<=af7|mnHsS^jiUrEX2YQPIpJ<%l`LXYU)ak}@^C0dH z4h}&^)03$ap4K+h9nm(K(#(CYMIdRy0>xID*e`}hBvjAIOg-8;T_MmVWKv4$E7OdS zz^h9v3yVAw6_2W@WqN6*`^-wTdi=IW&{AA)-47uzouDmCCTTwjuH`iiTNxF6ws&?m z$A7WeGnVOYy|dEU>+bgp$cd4IgZ#VopBemDyd-k;#8_Xm> zXV0;TaNd3*wJFVtbF#6)v3Un}_^>Ht%$pOb`o7Z0+;VfLph)9Esa8+F#U~{szRb1Y z*|oFU;Jf!dpAYvR_3lqP=kw|x|Fbho-Why9cUyhU);(n++c{m2om4e`ptNZVTOhr8sh~)5@zS(!R3yZ<%&`)w3m24ofjhEbZIY z`{l&#J9ql-c^hkA`gLQm=uN-WtFpfrc23_MTD|SGW6GQJ-o@oR;%=>))+pe*=+7h9 z2Pe|!=sWy7d!b(E>}>UQyY^i(o^@3(pYP%_HRZKszSn0Tb+9lJ)r5U>I5rMrK`ERJ`=rG z#d{w3<0Ty}^_7Fa!ZU6EQO2VQ?ZUF|H7NoM-ev^#XXJm}wk>;B%u4Y!vR@Z|bej6A zfa7V-KK|D(#-|$fA8rX{Q*-WUSva#w>DD}66`t9v_A@Q}e%g6=>Y^JD@7tQJ*ZX(k zaCPS5nCx%+t`&W7@tZhj{)OJREIVCi-L`XIqScvuxqr&akM3*szkK2S&HJuh&jVJ^ z7b>DJZzL4;CECBavFR;){?v2cb!l&l7QVL;`f)M)xyZxK)~BB?aW{DucDCGGDoD@t zT3zaigP{|Q`E^)1H@~s+b9m_!|MtkaI3JDkOP48EFPXT)oKZO1$oxIWe->%qR`fl8H(!f$(Gj^4CWUaBpxM?Z zSubt7v2b0w*!ij(D|MsixYcQ;uc%mlsqO5AnU^IrceLftQ2wxDLw!T?oBLZ7XBvbZ zxN-QH#R|Ut$`?f5%({2A=*`*SNZB8Y?z}!?ep&t<8f3M_WKvim*stTmi~<0^x|(<{v4^oOOd>8tnv4vxj(N-xcSHCuKo1=#w<+zpVsiL+I3X) zxy7tVBjq9 zh%9Dc;1&j9Muu5)Bp4VN*h@TpUD+S;Ffj;dW!`wF!oa|o>gnPbVsUzIptZ;001?}X zT_MqqnMe6oJP26mJ=ZJX#iHg#dPZYj0kiz0kY;(UQrz zChI3ygcx^B__piDmTjIF~>67oyMj&5pPF~gx^ zf&9tC!CRcRbF4b1c!2e3PRp#HC+@k~RrqIIgGLt_h zOT3q7Xn0`~F#87MOm!6&%|{-10&lqbsD UD;?j+z`(%Z>FVdQ&MBb@0E0H0&Hw-a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_arcane_frost.png b/src/main/resources/assets/ebwizardry/textures/items/ring_arcane_frost.png new file mode 100644 index 0000000000000000000000000000000000000000..2ee2a69fe0e3a38d816e6154778b0b95f3d84c67 GIT binary patch literal 429 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_blockwrangler.png b/src/main/resources/assets/ebwizardry/textures/items/ring_blockwrangler.png new file mode 100644 index 0000000000000000000000000000000000000000..309cb388113ef66299389ed9f973dec088a28d71 GIT binary patch literal 5961 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 B`oRDI literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_bronze_generic.png b/src/main/resources/assets/ebwizardry/textures/items/ring_bronze_generic.png new file mode 100644 index 0000000000000000000000000000000000000000..73e2daa1685fb35c65cfb4fe01f559d720530a42 GIT binary patch literal 5855 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_conjurer.png b/src/main/resources/assets/ebwizardry/textures/items/ring_conjurer.png new file mode 100644 index 0000000000000000000000000000000000000000..209d95db0de9b597cba04d5c86b7395068bf9321 GIT binary patch literal 335 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_defender.png.mcmeta b/src/main/resources/assets/ebwizardry/textures/items/ring_defender.png.mcmeta new file mode 100644 index 00000000..eb1a25f7 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/items/ring_defender.png.mcmeta @@ -0,0 +1,12 @@ +{ + "animation": { + + "frametime": 40, + + "interpolate": true, + + "frames": [0, 1] + + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_disintegration.png b/src/main/resources/assets/ebwizardry/textures/items/ring_disintegration.png new file mode 100644 index 0000000000000000000000000000000000000000..9ac2518d3d06fe4d349bb6d317ad49b24cf8725e GIT binary patch literal 424 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^PXNr}OT51_lPs z0*}aI1_o|n5N2eUHAjMhfq}im)7O>#A(yN$v+R18>){Lx46>Oa5hc#~xw)x%C1Cx| zMX8A;sVNHOnI#zt?w-B@DSD~w3=E7so-U3d7N?UF7O1{ho1gY#ZT_*l;y%Bj*j@j>g4_TgpEn|K!4+|g*u@ZwG~51i8ed;hW(5B~o@ z$@9PR#?61zUmO0JF8tuV!!yn1d1uM+eewyllnXI#y_q0Mp9rSP`wy7!VPKX*tb#Jw;`P5ANaw|QY>MQ~^1 z#BxsQI}@JvEBveZ{#U%Y@uj}oqM!x6yhm=@yvg~{uw|p7q2j`9i=vjq9ZU?9ugACF SpKbdF6k?vPelF{r5}E);hq3Me literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_earth_biome.png b/src/main/resources/assets/ebwizardry/textures/items/ring_earth_biome.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a9e59dd9b1d14f50f206e3db35108c09e8dfe3 GIT binary patch literal 5746 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-u2zLalmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(S9=S=w22<(U`tum-h>%-#@PS`Q9$)(!GkmUM~$? zsl-&ou-WJT^Y@AW4n6)LA@7phb@9>1lj_qA19s2fb1&s@)%?!AZ2Tp~`W6!;Y~Qau z=KOwv^@rWg>)rj>Z1)IH`4y?r&;665s7fS8s$Xf@+5>V2)#M%D^rh{8o+^L(*pg5G zIKF=9-@NZm!~B{0=N~0?sL18NU*q8;v3hgdgY9O#vR9Yx)SsgK;_#iAHGF0}&m9qa zZ=stq<9w%aRsZ(pZJrNZIV;*vn(MMgor^eV5nEUL&t~(Tm}T-OnQQ00dU!@W>$ADrWy4=~vEKyU`<@3}54^@v zlUkMiwkxA4euLFq+i0iYB`&TqrYw<;tEZe`Jmxr0Dpl%Ac>KykF7J0S_jzo7HDeWH zAfsDR>A|<@iyyKaFb`{p6XfGrwL5p=QZwDssUls{D;>WGv%^g{V0>K4&m`Q(+)(^uImHhNv1 zm6f-y&{=N#jU}1hy5+ApmcFZgvC;ebyec`4tp^YH8$6n@PaoHd!_x3%YubY{s}zt4L# z=YM;)Un1`9e~w@Ath_Nv*)~BB^tK(hb!DiGaVdV`fnzv}XBtYu}0TWUqCI+nl{-nrUvkYw-Z<~b;D8DB^F!nth>2D=6KxY7XQFk8p_3bM-Osr{`PpXZ;@rS%(sdf<+ydn z#Sc9YW@B}JTX@)J&+#|QnKy0UbJSqfMA^9QT*1oas}9etJbh<&{T0h3%M-_}bi_W( zZrq#WR@1X>+JlDLh=qC~uL~!s9eHxv&fLHD?&ciPTg#`N6;W|tX?L|^PSk;_#ot79 zH|BbGtgKwf9QJMpyWW};G0o!D2SvAq-e~#Hshj6qBEeAe{3@&EyMt3Z%H_7rU2NR_ zOS<~ro5<|97i$EC>_aDoNglK$2U3`tlE zxXgl*WKaQT+j)?;!GMSP|I8-ANjEN($zI~OmwThX#w)@5+RbgR>rQP`UAEBJ(qitX z^)mwJWgO~jQ8t(&vi<9ndBNIS-hE26-2W<1-)NS|lYffJ^BEZULo!1mN+NuHtdjF{ z^%7I^lT!66atjzhz{b9!ATc>RwL~E)H9a%WR_Xoj{Yna%DYi=CroINg16w1-Ypui3%0DIeEoa6}C!XbFK1^!3Zj%k|2Q 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�O9$af2qiSyGiZCx9pQT*O}aA^Gn24 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_gold_generic.png b/src/main/resources/assets/ebwizardry/textures/items/ring_gold_generic.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c80af61a01153b112a6d396a7f4b420ef9dcbc GIT binary patch literal 5866 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-g{nd#N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}k1Ttm!Sgp=bT5mFV%yV%w&HtyRX=Mb-$+fmvbrQGh>gWV zJeE`D^1r{A&)Qc=^cPAk^1l~tqqp;jWN*gx$JZ2g0`|uI2s^E$dMI(B#_7jiR<+&st7x?3_IzV$WX( zjRt*BqpWuGZt3EHO)sWA*gK&~*UW6eT)+MM>f#j5)xY@uWL_HHy>G&O!`x-g=NT)L zPQ-s*UUX^pojbu+mAf~;`J4LF(XQ<4hUb&Fetf<6*uC4gV$0;Bzf}i64@=|z-1l(p z&Qpt7{#-fs@J*nQmy4IkkwDi8vKp;Ih8b_3tO#1>mwT<1OTj8nCcs!+OpEOhhmp{9 z&+XE!R_p@ts!ea23IsfU9&);zGwT_btHe4H-bL*TdeU0{ESOQQ_SH_P>%_6s;RlW? zUv5Y;a8J=ml#*DuZ|2TBO5Q=$$r%S-T=xpiaJtL& zKuIB>L6MR9+GLH&O^oc(3Qfw&9H$!WgkCY|E;%KtaI>>wLbFao?ix;$<(obUJyu{5 z)Vk-vVD8~N;prTux~A@qg=-f1h3;kRon=z}QTgy5{<=9UEIkSwoB0)wOmH#_T+}U9 z%VT&>f@Sn?3d0t^)Zn3#@qUb4xmCbX!nhgzJNNp_J zwPUy8a<@P4KcqRZ{AVjp3;51fEMNJ%XX~uzuIiH)PHa28GHgO^Z|xbGV*mD#J8Cx7 zok68uKY|}Dy>n5j+&=j1zBP?a($}V2-S$}JSGl!1Eo)XoL5VEio|Pw+&W4@t`7+1% z_vTwQwvBnuYVYWlGktXYexohr%XEdA<%%}f&rf*p=6++!z7Je^UsI!2ZYi#q+^4@= z=qu;OpIpComtNTSvi#$r#nx#p&fntKJ!v%!S@>-I*%|!`|GN}#_gAk~n_qRM|Hbpg zmDlIKKDaJVQ7@JE>7;1}O6|9NrcFD3({Kq}v9{eAuVvB+GUg9WTD_C3_qP6HTD`Me z;+m{@ zxm}<7taY1oLDh6Eb?3!8q59d)Zr0Pvx}_iNFpl2U_SVFm^ZtYG>&m;Y^wmwgQ@D6b zLYN0@&C-YG7OZviTF@doclVu~TgM!p+hyKHaoo2RKQhj&e0eZm!FavRt3Q0z>vs8T^*cYg z{F!xoM{UoO$zLZrynohzR(n&tYS_}^e)W8dW-FP9w});wnUq?)y7jHE{1LwGxlU$# zNzvX%@~_PuW|;^4mwnUq#(%~S`8uO->=WL-oz4Dizw_nb+=zwC|q4DO5hfN_+aCUOH%Yb3rdnrDsl^4D@yc@3=AxE z4UBY+EcKD~SL7D>`oeYR6+=TYIX_pwBC$Z zIg%0nMVaZDd5Jm5t^ygAl9^&gXkd||Ynf_jq-$boZmerzVPULmnQCfbYGGiQ zXlkAUHVPE5R*nIlwn|2N1_+UWoWzo}{Gwc2rSQzWl>G8ygj7goZfbBzA}H7lO-;=V zO^hroO$;nd4UG*Eio#NhiZk=`K&BcR=$U~fQj)FQ@{4j4OKg=ga}(23^$YUS!4eg@ z1y;^Qsfi`|MIrh5Ikrk5M=2QT85)2ygMtkxS-V!0So!29CxWsASaE8K9XKa|^P5v* zx;~g|qmNH9hDpI0`Q>?FjgUNt#~g%GxG9cBCFS`=+5ScTNm;4MCHT$3rWkHgP-=Q+ zaY<37Cjn2Psk4EkOOMRrlKi4dB>RI?3n4s+w{kMUL8YJo&c0TO$)HfQRVq#_ONAr@ z1(;NFMq*xiYKpBAG?T!@GqI&tV^hPlR1BaeJCFO}lsgCKXc_p?=?wPp-;CNQhfF?6daDsrVFV9E?r6B`DOI-sKT_cka zBO@zQ6Dv~_B}i;5*yw{wMwoAHKxK!ouN885*nr9wD^E~@3ob1v$jMACf`kk>-2|r= zLQJyJ$Ds~MKRDUt6V#5Z45HgPzo4=xGd-ikzdR4G^;i@_Oz_D}PR%REYd5kINU$JP zAa-2PpbBzvv*WVS2iIbt8VwQ_pc;ji7@GQMX@!Eqs3jzY?`Uw11{X;oK$7Co)HNDh zB!vJ;ibqoy)q;x)(N#{(OR-fdSF*R$yI^#mfq{W7$=lt9Asz(pn;h$9U|`@Z@Q5sC zV9-+rVaAH3_GJtV4D2PIzOL+#StLZw%o397y%`u7BuiW)N}Tg^L7gQAaC;~0(EsYGx!cRvdIa#-xYLHDB+#>{{I+PV*(U*lnK%4oB* zY0g^da?;CMc}kgE%<1*9PR_aCwmwW?dGd(y(>E)I^Y8CZv(wXloW9rDPW4%`T{CGd{?9?XhA0 wzrAy&P0*85yWi@l*&p=yM5@%3@B1IHi*@!zcptZW3>p~mboFyt=akR{05?0jGXMYp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_hammer.png b/src/main/resources/assets/ebwizardry/textures/items/ring_hammer.png new file mode 100644 index 0000000000000000000000000000000000000000..105676e24c68c68d2d363aa97e5c7c4581cf57cf GIT binary patch literal 367 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Kenyl43Et^L|7 z1_lPs0*}aI1_nK45N51cYG1~{z`$PO>Fdh=m_$|<{toWGHKmI2K z)M_UA&)?fF={AdT>BT+&yI1>2*xCO$`{CVT^R{yNeSiJGrTv@#=4{VHDKVW{54Y*x zD`;+PY;06q?J)h}=jQu7;rIV0CnW6nTL13a{vMXUeL2yYChz|n#A(yO>m6ToD(n60m;f zqSVBa)D(sC%#sWRcTeAd6une-1_nkwPZ!4!i_^&o3shgM%};x=Hvib_HqPlTPAO7{ z?U%FjEU&n3q~fydp-F?_^p>uP9CLJ2j~p+^IA^=&RYXDNGcluo`T3a#7c5?P?!bWq z2MRL$M3gVqT`w>E&(GZbP43VB_m7_b-#ks{xBsMPt6ES0%Z|AD=lX_CKjXI+-27iF zuK)l1>b3v-&MGWkb!5ZO6OKD7X0^*VPhH8$tgNi8e9s^uB_-t#NKx|g^9B-Kr;TPvNg2(t vtCw4yw&#Jp(1wkTA3RU78}O=RFR^A|=;^C3KdK{j78ItQu6{1-oD!M<9_hCU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_ice_melee.png b/src/main/resources/assets/ebwizardry/textures/items/ring_ice_melee.png new file mode 100644 index 0000000000000000000000000000000000000000..319ad2b2861b7bb0922f2f11f512e7c93bb9c50a GIT binary patch literal 1889 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-RjWcGN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsF8JkDR8W&hzKFh#iwq_XCSH?|-t{?Q7Ouy=&V$$^OaLIW--) zL?*2Wdpm#s?qA&eo41{^;R&%?fn#oZF@`?iF3VMO5hsE%IleeLmyI{8;JseK#t`18-k z%K3hHULtW$PInRO5*J6AP?ktHZIMpLWOeVULZw-o^+Omg7A1c;ai*15lr@n-a^mSF zxBJ}Y9(4(JG@ad4U@+lRYwNO`7H37d3}Q4jT=*Stc1-<$<%+-9S399DkM`5y2aYOV zZb&k4Ut*FdDY0 zo^ZDVz9yV0k*@{plbDkopnXP>#W)Jn#p2OIV+W~?0UIv_q*L+E-ZfaGAZ}+uPb$prnlC7Ov%!j z(rxPD+Q%jJ^a$^{0}|0p4~--g7SCW$x0M*q%#Smwa;pYz$31@G9;*na-jwRP4r*K{>!W#0DSt&ZQm-iY>)xwJ#m{@bg} zMNjvNp7EP$mTq#(I`@_Pvy$`Tn8*a~}vblvM) z%&qhR-P^jOkDo9M=ww*=A+T_1l~o6GQbpCK$l#aS;_@~tL8 z1;z8bwNw@ytSyw${8gay?2|*FecyrnKg&z@s(vZlW`v2hEnEGMj@2WZTzqOpM$^N`>-r`*D#R=a# zx@~o4{P=p`^6sbg>vycu_`BlG&U>yi#lJE=&2J2mzfkw+;Yt5j+ZAoTyxPiqU+CX8 z##j9Ze#VPDoWCUQWB%@6;_N)H4o9^YnKLjjuqAoByD$VYgfh&OpE7Gd0|NtRfk$L9 z1B0G22s2hJwJ&2}U|=ut^mS!_#KSHmFT>gPAdZ27L9)a(qQp5rH#aq}gu%HeHL)Z$ zMWH;iBtya7(>EZzkx!g~fpLbXi(`nz>9vzLddoP9wC@+>Ui+@gcku#`96pn(s3jdN z){Y#TUT*OcWMO@~&g*Twz&6fr*HaCh6t3!2-N{s3{VYc%DQxG%D_=_#*jigX6U&NU zRYg1rKg;v^_r2=R_Z+x+pR`M!;NQN>DSD5=v4V=a!k5{iGLqi_4XPuEY@#3b8|Ik-A~nDb@3aw?p9`4_3v9O!-3a3D;cDu zQ{(!2gj^?Tig0NxWeD(6T&lw3EVx1{Os)HQ<$s2ci@%nYCP#)PmC3L(+}_4m5IbF? z%Vj~9r<$kus()sUt5gMLk2_}TZn@^LO%1xS z&G*|~apno9pUUwnU0U|O(tmyD>ptahEm6Kcro#Q)D*X%qT;_2(k{+LCEkDK|hh6czO$r9Iy66gHf+|;}h2Ir#G z#FEq$h4Rdj3b_tX?R)0MFY{siuQzxV;m2y7K zPEE{7HRN8ptY_22wR%VG8>XJ^Xr0u1bd8#C*CLh8GjvQ&UUIiwcBRz&tkcZogSKa{ zCWzUr4$j{{?|JPx?X+X7IHl^GY;{XmS97#vW#(lq*!a4oezGWc!ciuMDRoewgn3?gibwBe6egzgacz%T_(eA%?)$wep@=)$c4YFe$E#*{Z-|J^E&!-m^jMA zK40ZMaNm5L&S@tv&W0(Ij&2ohv--?%OLoC7k+_*}pYO3)@X$rc(QNin6W>D*4PGu* z|MqRY>&lgW6VBY+P}#VDz31VTAzlm;Z3~qqdfW`PRaGngwmtRPXZerr&ZSd)1GF?% zFJ_1wHV|pZoK4d}`LO5kGruz)fP$Ce~)FX pco!a_zF}??TWl!P|IT}ifww0<61~p9oPmLX!PC{xWt~$(699f7;oblM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_leeching.png b/src/main/resources/assets/ebwizardry/textures/items/ring_leeching.png new file mode 100644 index 0000000000000000000000000000000000000000..ff76f78d48bd2936db78976db46f10af8c775918 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Qm)@V?2hUIqpR z&H|6fVg?31We{epSZZI!z`(#>;_2(k{+LCYTT@fTHg*dG1A}CVYeb22er|4RUI~M9 zQEFmIYKlU6W=V#EyQgnJcq5-U0|UbcPZ!4!i_^&o60AKtR31Hk{9pOAxL(W&k1dQJ zKYsl0?d>f&&$jy5hu6PK+t%OSW|%X1!htLfZoRYq^0rAg%o3TJkDZ>*v*+PMp1za?_q|8FFjudfd0QIFe`Fk^SAw(`Y`63<@$j{kaEoNcFh pzQi_7O~af!J0=#ITuo+YxN92`AL_a+lYxPO!PC{xWt~$(695&Fm_+~p literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_lightning_melee.png b/src/main/resources/assets/ebwizardry/textures/items/ring_lightning_melee.png new file mode 100644 index 0000000000000000000000000000000000000000..36d36b7135f58eb906dbfe61b49ee5232fcf6c35 GIT binary patch literal 589 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^IrxLK$YtPnor! zfq{Xuz$3Dlfk96hgc&QA+LtjfFtC?+`ns||;$at3FiClvG=qVGL9)a(qQp5rH#aq} zgu%HeHL)Z$MWH;iBtya7(>EZzkx!g~fpM#+i(`nz>9v#hdq)S#9JLSEWn>ptnfilS zXKAyj_A#%`Gj3gU^a@+ZsBX^w@`{t=e`diDfu+t1*tm12=~(^f;SxNe{_JLiX;O<# z(^lUemX?m~%};*%#5Xyg|Ms`&{LgvC`@cJ}mh9O5qM$s~%4zD(8@=*||DVowEW0IZ z@wTr^DU@O3-{fiLi*i;PHXU5xIB(9($>(?dPEnmW>%%3jS8;O=$22yromMiJ+c#Ea z&lauyZl>$z?|<|?(k<)Mk_|#D*45rQwfth@JiZ^1-SWl4fBl>ncf0?(5}`0jd9vm5 z_&T-l%XarJym+KDcb~cfL)5RDn438}>i!i*e%sgKIB#ADOKkuHt&`S-YHr{23*l zxZKkgs$9>Zy}T{e_~(4nX-<)nj*@R!6W*Wi{VKL*)^v5&Kl{vH-RJdeP@k)t+Rm~1 z`t!`LlS%I$J$ZYAarQ6n#BK4{9F^XSHeQ&e^VacOq9DVw`*i|5yYssvr7U s$DTGPK1FkDeAohwq&Cr?`yc4fZQ9s%@$n}!1_lNOPgg&ebxsLQ0EMRe^#A|> literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_mana_return.png b/src/main/resources/assets/ebwizardry/textures/items/ring_mana_return.png new file mode 100644 index 0000000000000000000000000000000000000000..688e63d0a405f84eeffd6279074f6b8ae3a8cf78 GIT binary patch literal 444 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Qm)@V?2hUIqpR z&H|6fVg?31We{epSZZI!z`(#>;_2(k{+LBVR7;avR{t>r1A}CVYeb22er|4RUI~M9 zQEFmIYKlU6W=V#EyQgnJcq5-U0|TRqr;B5V#p$CH4ZROLNVLt@o~!zJ=E0Sx9hc=u zayuRW(;)qcJ!bc=R=%5em9Kn#p?~7dq@~U;vp&vNauJYWc^t4fq)62DLuevzdW${@@xJJ-tB2s(Yf2it}rk#FnGH9xvX;_2(k{+LBdNKi`Mvi>jw1A}CVYeb22er|4RUI~M9 zQEFmIYKlU6W=V#EyQgnJcq5-U0|UcZPZ!4!i_>=}tmisZAmMu6B+==j0jt>kubex||l*-2lHaex0Xm;ayjE-miZ zsYlNzA1`dl-7!%>Gbd)X_>Fgd3^8HhKH0v9cX-G%{wrK<$-E%y9K!|aGcRYDzkGc2 zoPoZHs@|WySI=?XE|_1{5FudnZr=SvcOT1cwtuS4x^xQ5fi2ed)Zu@VJoUwMSH~v*--m4&q@O44Ut05d0RsaAgQu&X%Q~lo FCIG04hiU)- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_necromancy_melee.png b/src/main/resources/assets/ebwizardry/textures/items/ring_necromancy_melee.png new file mode 100644 index 0000000000000000000000000000000000000000..2d59a223b79ca0a3eec6d7db54efaee327e215c6 GIT binary patch literal 1997 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s->#9N`N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}k1Tp>#`EX7W)TaM!Va1C?9jXkkC*TCsQPB{&HJoJozhX( zj71wyEc^fYyFvZKB))4FycgBq>*`I9dDP>#<@c%Ap4ZksuiO~^{P2#Q>JrXPVc)X9 zr0+?dvvJ<}3fm&1V_#hZUZpRpnRCKj;P~PPmnuX!b6LM}nEm7svYU0cPXBkrwdE3V z{Q>8H6+W9T`N8<}LzNBT{s$kvywUbR_}9d>+#8~2JGehJ`JQRnWVd&AwkET1x#Gr( zU!4IA@rzPyB>lN_uXl7D4t^>lnX_>tu&E2|_ztrw}W7GHM{K9pM*T`L) znz?rC>BoFOR`y=L@!4;OveTkN{Zez*JXklS!|}0#d#@4itJP~m7%vv4e>ibwYU`?l z2`rMGuNU1uJDZK&^OA$9cdNC}uAj%8ymO;oX}N0TiSX`eSIGHwD*x`Yxvt4)8k9DD z+$LJ^vBzY=j5C6g-VtnW88VAs8GR_N->0^oiLG>|<)en1(=-{sh%Y_9GeuB0Vns$d zLvV&WgAWS}mw`&cfhr+Y{`3U1Mvk@~1r27a?#E0~9#f?qHVJ=JU=L)tdqX%wH}$D) zj|+!V$exJ|d6QBmJe_l>zN!1e!ZnNhLie)u&N8X~Xnbf7e_h%Y8I>Ii4z>#P+rWqw4~>)e zn_Lk!OwMHB+OTK0gx|w8>8})PS$UkF9#Sj5kWjjWjX&sawezZf#_!A%&WCW<-!=L* zC89ba`lF(F!p2Ra?Z>XfI9NvJueACzH+Npve6y$@45jmV^12MJycL`oB>Q^`hgrSI zB9;4Eh%MUo{@JeC40lWXK{UdZTr%1m(AvD2;vtu zu+8sq{t)^2tTzZOn?C12)f?-_b|SSl=7D?W9Iq~} ze)Vv{S&^!W&nq|WuaRpIm0vb}mCkY92bqu6lkKN@tH%Dmbe-dDdWYgSiK69-U&QCx8%WnVU_I7eNFXTJM6^1|G&R+ZRN+Q{NM6wx!390 zsI4t2N^-lq-(P>1aP->pw*o1BsSjkb|6bfTU+A`U*|p&P0qbTh$axcVJ-um%qQt#F z=C^-tFPK@*eIi`+!0D;aSI)LBsJj{U z96K4bg3oJf&bRDi>YcwiF6{~3a*rW21sKjL8*QZiM%W6;CEz#v)T8d2h$pPQSSSHj?2l$uzQnxasiS(2gP z?&%v4-pD7;z`(fL)5S5w;`GwV_8!rJ5=ZO9jkW|U9pmHj+$GsLX?cKQ3CGmDxw}eN z2D@m)a-UP$ky3ogk;Chtqk62@ZSxyqNzQVUW;8r7ZWIrRds(gY&-}V0Z{!2!`+na0L$*dUdFrQqzM{OyrBfsD*22dR7p$MN`TzBj34i0{>(;Md+mWt3bK#oX z8MjmaMOO0_8O@wB{b;(6ZjF$js+ZnsQ)>$wtMsCGykTEw#jfUX&|7V2XQaGcEce>< zZJhCYrskzEFbcf>-N8^N8f?1z;pUod-TYm@Ao%t zbi4a_t0=<{!>_Ie3-81}+k9kyo?Twcuh4bvnbGT3>qJ>*{Bc+t_VeTp*3<8|a?35U SO=4hRVDNPHb6Mw<&;$S+WwNgT literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_paladin.png b/src/main/resources/assets/ebwizardry/textures/items/ring_paladin.png new file mode 100644 index 0000000000000000000000000000000000000000..a4a7c90e3ebeab9f713dd6f9db96fad4d68458b8 GIT binary patch literal 577 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^IrxLK$YtPnor! zfq{Xuz$3Dlfk96hgc&QA+LtjfFtC?+`ns||;$at(RZZE-b%lX}L9)a(qQp5rH#aq} zgu%HeHL)Z$MWH;iBtya7(>EZzkx!g~fpMj$i(`nz>9vy#J){#wj@QS}KDuzPbDkHs zV2p~($wq|^O;;-okCP9A0^eLYyK-`#>>Vo+cJ_m11uJ^Hy*;!i$*t`6R(5fn;-Pd$ z(CO-xFJ3C?cI}gt)uunV@c*0K`~Sc1{l3@C$MrJNscJ_sC%;tltE+nFN*ldC+A7-i zEL)M$bxZIO(;P3spWlU!cNI>mYG1Y@r#^ame6sK+VHbuN@kbuFmxNid&F_y%>%1o} z9dt`=tNn5db@@u0NReE|r%TQ)zGzZbG;MY_%i-?2W6hD45(O{#x$IQsCRw}@W%&Ja zZy3XY>8*MN39oCq-g)`#igpFwE%u#<*cyrAwpX#O*%Yg})1bzg+!9SNMQw`rD2Zw*&>v&)u0OeO5O+XWGYF zzQwl)dni0D?-X#Cv z=H@lBg4wg}Q;PY#zDqMEe0{p-LGM5P2+z-dKA-#RwxWNb=Bv4P*56+`O*xBug|pPt e)PMTBSaq~FMkHQTk78h8VDNPHb6Mw<&;$TT4eiYU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_poison.png b/src/main/resources/assets/ebwizardry/textures/items/ring_poison.png new file mode 100644 index 0000000000000000000000000000000000000000..39782113f3b3ef6ab2fdb870084062173817fa65 GIT binary patch literal 5591 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_seeking.png b/src/main/resources/assets/ebwizardry/textures/items/ring_seeking.png new file mode 100644 index 0000000000000000000000000000000000000000..4348bfe946d0b4f9a295cb4e59ddfb68e78fb20e GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Rl|lrS(P+}~5r zz`(#+;1OBOz@VoL!i*J5?aLS#7}!fZeO=ifv&itV^QUQRn=>#lNS3%plsM<-=BDPA zFgO>bCYGe8D3oWGWGJ|M`UZqI@`*DrFueA3aSX9Iotz*cq!1GR!d}l(Ey*OEb=3ot zmevVtWhIaCEI+sRa3&+S-tw{(31ge8pA#QmJl$Urd!l2Fa`JwK69^nX5#(k_@0Q^4Zl8FyR}KC|7V}6X=GsFU~*W5d;TtdQFVci)%yFBW6EFI zg|%L{uTAtQy_Q-KlO45KZ7%}@gJg+oM2T~LZf#KgUJ7%POty}g6$B4u-V!C{eROE5)u+JY`#ojJO*NBSp0Zke{q|#cH2&- z*^E9ncrtCi2spnvcw9b0H|3z(j7*)Q2M!!KpuqEW`%Dr2!zzopr E0A@CFJOBUy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_silver_generic.png b/src/main/resources/assets/ebwizardry/textures/items/ring_silver_generic.png new file mode 100644 index 0000000000000000000000000000000000000000..81fac930b979193940a41c53eba94eff23f582ee GIT binary patch literal 5910 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 evp@Y4|HJh1>BLj>(-nF^<2#$J zU|`@Z@Q5sCV9-+rVaAH3_GJtV4D2PIzOL+#S)>FkIseAF++<*2kSuYHC~?lu%}vcK zVQ?-=O)N=GQ7F$W$xv|j^bH7a+@6%^A92HP2X=GbH?Z4*SP9FYuH3<>sg=&Xi zbs9^iNJvQd$jC}2@qYTZcy+p?_>aQ}4t)4?j=jxOINc~`r$Oh$#>Pg+3Epq^_b=8x zEU&XJ^-!9UvB=>A`D|=${@?c*{yCb&z`g81e%twSJA)%t?ZzGjoqy9)6A}z2nx|Pb z`x>ruIAeU`@B8<%2S2noHabP0l+XkK+lY?t literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_soulbinding.png b/src/main/resources/assets/ebwizardry/textures/items/ring_soulbinding.png new file mode 100644 index 0000000000000000000000000000000000000000..5fed6da5855d5b7e4812d59ed742e5b0cb3c829e GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^Qyvm@$ODHcDw{ zU|`@Z@Q5sCV9-+rVaAH3_GJtV4D2PIzOL+#S)>HDyZ=aFyf|+dn z+Gd9n4qUyf$uL{Gn&HM`y}xDYObgNuGZ)0&4=$Fd_L8VR_4%|eL)hYZ&y;urjd}N+ zF3vP_{Bp9y@FmCDLrPDBSR0lU6=w1>{C_(y%4S;s1ctj;Q|0FAF=$NJTKV(Yn~o@( zf1x20b%hlC#MEwf-aM)wc6x=<11Hv2m#2FY^~)ogJGY5-xK5|K^)ZA{CoO zW?gM~sl=HSut;!bpHSI>GfJ8Vk9F|=dXN_!rRw5H*dZj+>XCjJh#lZ;$&DcMI~e< z<0cd4!xq;H-53}GbryMf8pW4w^#l*KfVI~gM7lW`yu6;>+|3o5)v)U7 zEYJTnudkiG?!Bo*a(Uj2nTFczqG~rcY5PAtc%ez{3kxIT7A8f-SyzSC+e&QS7r(h5 z)V1eNaQ1lEX{1!{zN}CG{D*Bw=R%!4kRDgF` zT(CeclSW#BqBeiejTdzak1lO`FUsKHv17u;sb?z^jvPJOw>d%1fIq_cdE=j1?1`Ul zKVoFaP;?Y<&=qlsKE)iovuSUYqN&IFb1f^L{#g*U)^VwdqMZD)2oJEXd?uZ1l?hY+ zB~H@p&`Y=JaA9d_d2!@W^JnH~jIV1iR^Rgfvi|O~J@YLdg>EQzHWjO{mfR~=F~Q8? zVME*6{pZ{dHrvnrd|>L1gEk3<{5hW#-ZHOzD!}^0RieJ?tYe+PvS)dFuWo#?Tkg(= zsq#yT=5On|HskOghx4_6>fgW4y7gN$>(t~QKKDJIF?Lsexc1(>&2!l|-yOem#H@0! zb64qp*|SFQ_x3AE6)(fuZC==4`&xQC=gz;M-X}VlLo60pK0Y|<)>(~T+visvNRr$0 z`7`@^uW;-2;&T0G4}MktI>G+r`BTkX7`J%1bR2JA$=UG4JINql?sLOYn;#bElzS^g zr#!j4u{?9t6^7i~o7?yOd}<*mxN`UTi8p_3<_lWNwxZ^E=B4-gXWyuaw)1>ecwV{S zc%!o16a5J9yN(HG=T_~Jk!LP2{>`(+!)3>fLNSJbKr?ZM316l>IP%W7Blkyk>)SsM zLSJS*v47=q{@49WeN#3@>^#=o^vP;cjpuQjj6S)XgMSw${kGB2Sid+!fMd(N_Tx{F ztys@@Kr;I;^Wymx^(!PE>zUWx-)fjzATs&TtrE6hx72fI6qGDZDzUopJMs*3`_IN? zxsD{khhMC&{10Y7-)*;7GjTGzTUycERLynrH|HH=uKwF>aPmyE%;cj%=jR^0;qRCc zA7jaK{&8PsWrCE?rKyLd7zopr0ICc;0RR91 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/ring_storm.png.mcmeta b/src/main/resources/assets/ebwizardry/textures/items/ring_storm.png.mcmeta new file mode 100644 index 00000000..4c786d66 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/textures/items/ring_storm.png.mcmeta @@ -0,0 +1,42 @@ +{ + "animation": { + + "frametime": 1, + + "frames": [ + { + "index": 0, + "time": 20 + }, + 1, + 2, + 3, + 4, + { + "index": 0, + "time": 10 + }, + 5, + 6, + 7, + 8, + { + "index": 0, + "time": 12 + }, + 9, + 10, + 11, + 12, + { + "index": 0, + "time": 8 + }, + 13, + 14, + 15 + ] + + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/entity/spark_bomb.png b/src/main/resources/assets/ebwizardry/textures/items/spark_bomb.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/spark_bomb.png rename to src/main/resources/assets/ebwizardry/textures/items/spark_bomb.png diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_0.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_0.png new file mode 100644 index 0000000000000000000000000000000000000000..2d5e513c02b4021ab151df14454923740f0f7f1d GIT binary patch literal 1651 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-{#J!VlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNUGc9z97}ljqNKk!ltdfsV%?dS*z!`Dk7_U*0+o|hdyjt z#3c>ugh_E+h<4g%i6Z-oj$%`wz09+^7(SkedX43%O{`P@y1@~`Jb2=wY<6V z_iI@sd@sDXQBeLwXI|pDM-Ljk^%h_GdgMsP%&$Ll?G6{eIkWZ`!@afN8s?r|ez&&m z(2WAC7WN)L>yyQA#GLro#2VNCa=7dE`{S>MyAr;~UsRXgWLFS96M1Fplu+m6Od5Bk z#0uR1uzcO|t|fZo5v~i;H*|KaUg*NJg}pLsN@hTO>QXLo+wwk*ncBOrF4HS|w9Dh; z=Vb>4znCz)-3Z8l&uhmQyF*bMdSCdfg`B5}Gy?1}{eV$%J=jkV2@oN7# zYRvHPSW2GVMeddh7BfyAD!=>8`OXdgBUT0)+-XOdHtXJY5!`irTC|Pz7va~vcOUv~ zlx1$iGdx!7bH7jX z;O-C*k6|(OP?+#^uR`6T@FM|Y>i0T4CTM7R78M+1=TtmmV5;RVUOPo1sYfdK%&RM_ zGcK%HiLn2*`Mu8@8!#$ zY`Fi|QS0oCzK=$Z!G0-4Y{za0OY~1>WHIqSw`S6Jo0+rc+&tpJmAJvp=wzmeBy;mV z;nNGG%gdkbdwRB`zT3R+=$x5X{_;LMv*ew@_o>^}*KFNWCbFGlR-}dD);xzB7Zzrx zoh|nN_4d-Am5u*TUeL&0ujk+)Xc5P8Co2BWn%e=6pVx3^N}0Xk>)iEfm6FKOn5o~r zqylf7O|SA1kTQ;ES~kVl(tF;zgB#g;@2yjp`n~$bE<3I2{aUIHu^S6h%|4&CWI4hA zP~vIH+I`V{r(>=?^No@Fb?Z&&=_%L#oUzOKF8K0zGJECJw<1R_HZ_RwvARZaoeS5y?snZT0s;3^~3um8jJGp&(K7**wA4>+RZxGNrSJ1^^?jwvvghS(2w$uEYj7QqeB(EIjas-$MU-DdpxDm?}f#- zo2q-YuZd-^-x}vRV`J)jw>fToJfXJ}56(+<4Sy9~-T8B2-AUEkiuaE!ym$1Vy7KpZ zAJk(R?fSX%-{wBkjotg_(Eb+h8xtpL-{wh=|LV{5V#+gh&q|9Hjk^mkS%+w+OxrN^ zyW-EFS>|TP3UXt-=X~zGz4+WSeOb48(ua2H%>2(Vx$~vl`iezU85kJYlDyqr7%CZ} z7^c2C|22n!fq}EYBeIx*fm;}a85w5Hkzin8U@!6Xb!C6d!7L~uef-^rSOx}$@18D> zAr_~XP7d@w>>$vxfA2Eh+tc}&$`?{LhXppj^w|_2YZYexa>Ss<%0GtyVMmFU+}AE)i$m0{rXFq zf^4UTJ*m3QXkGg{!ACyuq_(kM^j=HvAj_N6zwHU!_bO12y>QuXp)~hON3F{OO@Yfp zH>geiJb^d*Zq4$2x4eGaWmx-0hi;pq&!;$Hna|^&CO_)m_#_;%`ELLC@%)1L)e3zT V8_%ts#=yY9;OXk;vd$@?2>>Uf2kig= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_1.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_1.png new file mode 100644 index 0000000000000000000000000000000000000000..ddaf2e8eab2d168fd7a0705060cf1e1cbcada00d GIT binary patch literal 1693 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-#j8RhN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsF8J&n!pHnNSAQDiy%Xni?wR&I z`9*r&u^lxv0)Hj-DdJpF0%gyre&=VmTHF0k9y@A=IopJTtxpH}?OLQnYn zljG^~jBdg_n~c{PZ#-)2qu;|}QRue%HQ#ZGnSX!kE!MxEoc`_|b4B@kM(f$r^eLFY9)9T-*7oqF2*>dQ9w+ zAC(si1izRtyUB!aI3`h6uCwLOvZw1O9V%8nQ^JzmqF=ZBOnGyC(cQLVGgf+Q?3dO) z@-&S}spsUKJ;`Dm3kwaVw!YtWX8E3t^E*-vG`Q1_GHuqq?IQT=gl?RT@w3ja$KI7J zztP9&z;eGSq2pi!uSXhJ%HraQ92QzXPIlbcSkB5bp(8tmZAT)Xg8SVsz4=OOclzCt zYunPm@$i7)l?4qB)4n(T>5QA`92v1kaH2wB$fPF+4zhD99x*W0a__VA;xTmV)l5tM zswHKzD(ljmm?V!GOC~JxoE3CR($Cl@y=JbV^7BVr;_*vbgu17N6uJHiiC@|#wfb5} zadEHosr{{DzL%#(y}L5e>u&kWg~!*~ezlp9-P|s3bg0AGUFv7r+YP^_npP#eOTYGF zgPG*#?6^M(yoU|r)G|(W`kXs3<1@>#$0-b)Z`IPnPF9=GoIU5}lK_!N2c%A_EWen- z!}H6}kL~WAT7&P(`EGxr_v}nRGt={K{lPgiugE^Dd;V7XT2!1hmwr>4sGpB6KZmqh z$yvY8cP9VaVfz2tf&VEPQ?`YRD=hJl(Pzn9t6%pmcg2FrZ!IRg(%)KKVoOUWb|tMl zSFPK-B6qg8tr|z~OnyearxxXt(la>LI4&-K(Rr*+d)vC{ulB^x6<`a;^T4X%&cCvX-)sR77x7!A>HV|w zD1Ny_>Z(HWa_?=mH+ZMk=ETnYJn`l&R?DT;i7S6{9}B;Iqbjm(*`=n5s}Fs-BD&

    $C5gjhMJhgbfxA9v&zDJ_V`(~dP z>z{B-KxJ;rm*VsJ))zilE;ZU4Q}wL()|zOOhbxtrm)TgTKRK1&{N+NKomBVS=NzX} z_UvEB@+|h`jzf>mCq9%(d8NDN>$!!8KD&Iq_bvb5mpcu;MlsSiMY0e7RQV)b^fxv; z?vq`V(SL>uZI7AFp7Mw=FfgzsdAqwXR5C;{Onr0yYYqbg180FpWHAE+w=f7ZGR&GI z!N9=4UgGKN%Kn&xSx|)ku8E2Q0|O(wr;B5V#p$J!9lZ}b2(<3MtHv9s=<3fXn16Qu zw|0>|)o)Bia{{OIhQ7%Y4VzM86EVfabM~u4ac!0F&sJM=|F_ASpQilYqNPQkT`AbM zDRx23GZmQ!KT;Z$mZ>aKS$5>as<{f&tA+SFIXgHy8NEA`U70MHjF!&Um8eu(=I=5; zTFhRU$C7cugXR#|+*9TiA0r}@p0En8yc2V0+k~!_qV3}TdYh$goQURKJi9|@J&)!3 zD{5yvuU_1?MLk*npV9Q!Y^k@qE`ObRLHZQ`lB^4@3&OQUbxvG)`Holmx7 z`HT76-F~-sPUF@#+c)+6H`RcKxN5t1f9%cFF5I;-w}1TjhyD(I55GzKBo{h#CTsuz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_2.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_2.png new file mode 100644 index 0000000000000000000000000000000000000000..68898fde03af2f0768af2d97427c287947eca104 GIT binary patch literal 1786 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-ZL2~eN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsF8J&n=VD$9R@(vYx$bd(l^ejf`IV zrlrO-ELZw;z|h3NL9^8{uTlCLPmxK^{Rrifv%H!& z47|8IJmy3?@CtFH9G$U1zLSgh>JiOdQ-b^^nM@5aem*1kT;!*9fuRwLR8A@_3RjShRFX)Wa=@N{+tjlH9uO!j7ZUqVg_nnHpyO$ZHFv~=~FUkPtF{F-K3mGtiU znv03K#$xL$KOK^4bIlXpa@zCOoW_j;oIR)07@GKI8?P5hzHuh^Tn(p3m&gIBrM~AD zoRyI1nd}tx<-xnwo%26E3;H9L|Iql^on`O*4W65ow(tDDr}n_D71uiti91?zn=hLu z&Lyqpv)1vo-Q>F6rT?!Vh&S4DYs1}CksuCrHKy%$+jji6E5ER(x^s)p{9LDnE2~Ns zk3M;K?t4_!qQhsVYO=N-dpnzF`b!J`mG3SH+;HgKc7a>BdREPTxvY+lueS8Ovf6v) z!8ciBmQSu0Vb;ObbL^g+j=3s0H%9Q7-JiRwL-hVD9?5y={8By1t3&LSZccybrR7c?+q|EPe`kG?^S0~XYsHnVTfWV1 zcKprA%U6=2GZ|~{x98er#kAj%@#4olF73(xAWfV$vCR9>eI;; zk(JLkR%b7j;&_;I^|_Qb^7l`_l|V2{=0p0%I*@sg-LdrJ0nkb8S@ugFWd5Gg}^ih-ui++ zySmT5kXP^etx;Te_0yZfBo<>2tPEe$TlxmD)T{3)E8#g+F>G zz4M>bzxwAZKhKw|&)0FCQAs$_{&bU~&)GvB6_%Bb-tmi{?rT5yd~NlC^mK1+xs5C5 z>7*UCzC2fHV!C7FiElYt{r|oz{c3nntS0DH5b8*2z6fU~$fiY0)njEgHo? zNW>jrZ7<;O{K&CMS4~PtQI%zDv!a8~&)9$|SzH~H&t(1kesB88-w)@z|4qFyT~q4d zF_*;!SLIgvD*3bBc(eGYLjNHp73U7u4*kz5%>KJ>q-^wF_bp>9I2 zK4?x56rTC0vtM7zzpaBqsY!ox>52Zeoj!TYk`GV6o}N)@dvW7W3FqKU z@WjCEPI}MkHz~|Bm<2w>tt$|!&NMy{xHIL;te7j-mv(-6vQSmYeD#feES@qr?!DGn4z`)?? L>gTe~DWM4fQJ!c~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_3.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_3.png new file mode 100644 index 0000000000000000000000000000000000000000..9d276179be80fd4933308d08241c554f07fad992 GIT binary patch literal 1815 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-ZK^^dN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsF8Jk1WzQ=lSzovxuch`oQA?=g_uxFY4jW_^j&T4e*B;(c!~e-N@Ro^97yKHD}i{q)A)+XEzK zpKJQka&cpDP48W&7oA(RKh2gmNd5hz@_^sg?pHT+Rm=!TDLK zlt*e8qw+cP4bKwGw#Q@~J*yq3?D)hl;w8s94*xy7&uBmPUpHI%YUD1Lu)GLGee>09 znLf{+nTIv9UTV&a`LXV_&6VC-g=@{*b|i@9Y`C#2_KL^%Tc5hq`%5pfC716M{{EOj zK(Wll=*htb-zUndo8HI>GrBX{v(B`Zk6~pNS^PRh(&r7z2(Z zcv1cQ0yZbcNJW<`{OpdrQ(q(-7#a6LZ>8w0 zDXmH8O?!5l^=z4tdV0bcR;I@`k`9i$PtFwOI_UdME#1tzL&<7`Tj8Y3nMQ1EhZV%9 z=H0nF^Y;XE;ltZ2itCfk`Mj!YwlrR8eP-|Tx2)NF*9afgZ(7EszU-Q|l(ZO+rr#-> z$#pif{=a%qU$kWF`@5mTa%A-if>@o#hA(Odza|c z?mpdYEY&;HoKx{J=ewktD-}2P$?Xk3zvTDzjN88gV>q&dgm=B(5Hn|H`Mt#s`#9RK zZQjzF7#sDj>q|mKszlWG>uUnyKF;ONT;A_xFIm0i`i{v?#$RsxW;-68^Cdc1dCl}mM$DsV)>#NyJM~a2_ z#oUNGW{|yZ=H8@oc3Eq`h1rf%zc|aC+p%JIRhMiPV~N{mwv9Vu-1aa}tNx*s@Jw)L z#e~xge)^Jvx2~}jG~AkWEbNwm)L*@=XK%$iDaM9weQ@i>*Yyul;~2vE^5k~B%29A54&d6jSWkAITU{0+Z6v|_Wo($6!;Ivft0vr;+w z?YGz+n>-J!H1mI<`yygxzklTKHo0R{n!oVQQoXpRbcG1?w>YKwodK%|Ec1`RTp;YNrh8u4?Nttw6j<=J>}85inlg;i)^DmCIu$V zZo8+qcE;?8I-6e?-@LrJw&8A-)tjovcRso??=3o)*t@7A)v^3e#-jFx)_k|pT}_v2 z{{QE>`l?*5LsqVd<;;uABpS7?ep{+EOp#mF9NL^yuQ>m@kYn8ACPzhv?UOSPd+rP3 zxXFK?@4klZm5b}21S?ED&%e=o4daH!ql=%|dG7JP^2g8ay{u;3yG=jE8(IEso5}fZ z0|NsCTavfC3qvJC6vNav=fCDKFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#IhX~7 z75x_P*I-~^jPZ1F46!)9bn;#==0Jhg{kxwX_nnrr=1xP$lAF0ANx8Wjgj41paB{KE z_C6@iv1#pE{)9)$5fZ1D2#TmGDx@8qpWtyU&2YDhqW!%`_mZB?F)n_`^XK!5$Vt+d z4!Rq3K3-gKg=wSbf>~P(JRe?G?RHx3K1t5XR_c3ll*$i+r8+nQf9 z8vJ?OGcy(+5Z$>pBIVtt7yQ0<8J8D&vUAHyGc&lWGPG$IJiW4cp(Dj52$@X9BT&Ca4P9AqL?R{e4EOFdp!eBubt1@@i^pP~;2YEM=_Gqw2q z)XBWz=WG}RZ>~KVTsrIJ6}DHM4_c+)@yl+Fn$dWG!^WWC=_Tz|PKCGra@csVv!(3_ ls%9@@a%ShxTH literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_4.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_4.png new file mode 100644 index 0000000000000000000000000000000000000000..0548ae6028a7800438a3c2a56dd5c2fec3a404f7 GIT binary patch literal 1833 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-eXBwuN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsF8JkDMl>$@AyANHI%`K-1$5`<_dm`KTVT$*g?q?p*(;tC^-O z;Sf=rnEGqKecMlVdH1AV@m|H&gpVIjs!zYzSyo@>eQo`H;|<}@Pv+&B%lPz6`)=^X z*#5BIclImt)s@?%*BC-!ZT=D!=S*!Foo4y;l)^j&{KHvF9ep~UrHK&i}etLaF zyXhi}TiLNvwQWCmi$&R({N`Ld_O-h;apvD#^*Uke;@A6F-e0TkoO|~8x$_GR%;s=D zRCPPfmuBB{x9b9T_VrW#=6^P1$=ma9lwN$)@YlWAZ;TVUp5?r{b?Q}OQloZUKWj|a z`UUG>d+ku#79seB&5V0pmc~S97WT@lDVYKBxl6e^?v*ajn7g`fy6&c3PhKeT6H zeBlC*L}AQ9sl#vbA~M#_zE(9=DJ-vLX5WLJ4@dl`|2*--`uf?662ZG%%kg32#5Ep{w9z zv7t#yh3mwpxCQcG1*J|Mdeqy&64*IOg`LmNgTwLgn!w1&yD#5bbk4?%w%0w&jnkgQ#5{b|Jtbhvkx5?bCis61%~}za>}zU%eTU-T z=!~qWoRv@gWP@Jq^X8AOezWp9<62(1x)U7E?lPHAq_f+vreAx}y7PSG;={L6&aAJj zO6N_xdYbiYk!ivF60%ZDObK%E1qmTTV|4zOoZ~xCnmFc8XfPSJh?!+ zy!@Hn)3Y7_#q!_D7N-S$H=kiVdDr1P=l9eeh&uh+<)Q0^GlwLDPcygj3Rj)cdseCT zw=DbLm4pAEWK7vsE*{{aD5KAkw^qOITkeVlmET&Dq|DxMc2@PQ=GN@mX>~t4Gb87A z?5kM;8E0fzbTrco)hnHtH?&FZU8pYgd)ekw{^k*HCOh1z>+%{I0 zvR@CZZVkA0VT)Bjddm63JJkcl)8dVnwjQ>W|7Nz}NAsM(wA5zjz!VdqJe|T6tV{`h%HfvwW`nX%%{N^}@FmtSX=G&aW)fdFQf$k0Cpq z;R*YX-`C#oeGl4Zu&d#!V7b6#+Z`XC?OeJ<(b4pqLypO&+svOEvr@GWE629oz3ueo z)AJQ)&YL&r$(PhE+MQX-?KA6p=8nk|1-QGWUr%F;7MWM8k@wE5Nn zX)%pi65A^k>OaWU`2X7S_QdH^HxloqvK+s6!G7I;w)T6Ry>nUOr|x~U|D0dgAIEO~ z8*hxaoql&_)pQFt|Gy$WOZJzqvz@ZQ&W$?MZI-aq`waNlw_uVUWhlSOl%GOt(M|L|H( z_TR?v{VgRw_@5u;_uG5O>MR2T16z`}y9+}lLlnc*H|M|RFfcH17I;J!Gca%qgD@k* ztT_@43=Hfgp1!W^k2#nHg}J9nl>K91V2t&2aSX9Iy>#+kufqW%$Lr0%9lmlQL?*{E z!0Lw2rEiK|=O$fsRrI)fzxbWyhx5w+Cfx~Swh>YDv|*VRp=8MYWldGTn&jo=h%<^8K6*Z0{P=R<;+HJj zvQ8egd&`rXY=fv_TiGo#;WU27vD+`cw?l{@5jl^;Jt+5 znCy*LF^965FKv1G_NvDAhPO2W`Jek#&)l!k<+Gc3A-jQp&DHEF`HMd4%{TlY!C1rS zd|<`yM`t?SZhg_X}0{bQR5>wyJVO-C^z`)??>gTe~DWM4f D5S(hd literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_5.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_5.png new file mode 100644 index 0000000000000000000000000000000000000000..47e5608a8e911d401fbc3ad5974577eb0692983e GIT binary patch literal 1809 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-9jihjN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsF8J51;hZjOWjD%^DUZ1KIYCr_4WmyvtLSdB5fE#`#$;TuO~; z<{Vi*|DV54{CBATr0Zfmm-&0P|H!;_L~?G%_x$ZCrFYLa@3rzTE3Q6hz!`P3f8YF% zl4a%d1-{%kz4>lS)t@7eUwo>OIn{IK#hk*A7DD&Rtj?>=t&EhPR{T#zM|}Ii_2;D= z+=>mjq~AFu6@EAFVrW!3nelj+vVqR#{qOzmRKGj3_P5i$wciiTJ$qd5e2B#B^9=tF zUEDai`uyFb7p_~iKV9Y)&)LwwpZ(pjjKZFM;nS}+Yv!L@v~KAdIX1BX&FopnML#^h z!2jB7htjkN$ExO8tl_3pIu3qQSn4*D?d#RBRShfdST0Cir*m3Nwcyb%my4AbA23wT zY82BEUB!8(=CG4?Uere|SC_n&i9Q8xGd`Y9y(jtq$u3K&yyT?qc5}AG2J2>|M$73w_K1EjRcQ zJQg&3Rq3<2c|fM)Kyr(n=ug zAX`(!D!!k>CQ9u_-+HB<&nZ9XIz8swqpQ~MYd>sud#d2r%x%{q;LK&|b>+pPe#K)m zlKkedsGd=s-{fhybc%6P+KzKG<{BzJKjhja7GA@tIxVEg^;gK+b-$#t)~tMX%vWk# z{b$`7V$oSUgWa`C->&;DSM_G)^TrryqmmsD-6aZ_Ow3;;8#+I9vG`NF@ZP?xV8htQ zhhj}HngTgxM2#`D6k_{?XY zUyrZ-xpMITlZ+|b!k-6vOtg5#aVtvK>i4zq6E@X-NmAF|Gj>+>tnLmedG_j0ocH0+ zh11PO-$#SM~bb>JSml{;lN^vqJ4{Mc%w`GQUH+ zYYJCO3mK`dsr+I0X`+9`n+vyYrxjQjh~Jc-qWeo$Aaecf?gdwN^$N9KJRuob`d~+- zU6$;PsrN;4rrb64h_`k)J#kT3`t~r3$jSE~Y&pk2MRcRZ%gED$hKaqk%7z_vpZheW zi#I8M+V<+sx%(3?>FCDZXW^Oo$MO2F{W58LMC|JWrHcCt8h0PuaI zx#L1^Ij0<+@AQi)YSWh1j344mTfckUJ`lg{<6&O={#jGE$o?;F(MsR1`SoA3(W6_Q zw)0ko-<)%&+w@J`=I;H*UXQDP%`2~8v2ccVqM>5l_MSc2XZr-cx$$mY{NU>ivyIdI zOtmf5WJ2BdnDJ}wd>xSawoY%WQfK#r5Nl>u=C9g{@ll`sUNSE}v@m9?So^=ZZgmae z<~E;O^3Un%fA~`UVc*;dSLZoYvh7MZxBl{8S>8S#k(0 zQ$PR38XDSLCJ26DnUIxsWXH#nT_i3)X0&M9l z@@Cfe`}tkvylg!!fByV1!|4CP_7j^I2fmQ$=enivMDt$mD~bJO>2)X0XK-fxV>Nog ztrl13d60pDfi20~-G!l&A&Oz@oAY0D7#J8h3p^r=85p>QL70(Y)*J~21_t&LPhVH| z#~jRpLKeoC)mAbvFa~p$|L5>mJPhW|m5xz}EDJd)b$)xrUCDNJmIdrJ3~o0ApUds= z`<)Oesa?OLc9E~;DgIp_+(PA6U*2ITytu)j;NEX3)~$gb6a|=nH5jtp&v2KGJ|j0x zJNH!Ny(!+dw=Um0U&7{g_3+`ZyEmo&6qJZNC{dM=;B_?qc3h(?Td?@yK-cVb^V3eP do!9=GDfvRa)qPRF?+gqK44$rjF6*2UngGx(S!@6R literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_6.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_6.png new file mode 100644 index 0000000000000000000000000000000000000000..47731927a27781cce3241d7652e627046d605bea GIT binary patch literal 1797 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-t*SyIN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsF8J&zw}O&hzKIW)VvZL+9fSVNcmC>t?mT`B?ESUueJ7<_Le2 zyOR>`{CWQV>Ayqj0YT!EGxRL0Ymz!uLrSj9Kc9K>`0Lwj|E^Vy_hj~mNH-Zyqq^(d&3_eE_>7ew5ZU$PR^ZC zQaN!_Gxy|9+kKzoS{oa!%@9wI9dbd~oUCq|YI^WjMH+en@ zyPNsHtbM1~HZNrN+CQ(_RpS0Ue%`oyYuh^0^Y60GBxqURzLKjQ&fmrx^66{TG36iL zFHV0IvFXw+n_#yf?eJw;QLcpQz$K1T#m=sNdxg=kO_C*-!}f#ea-D@Ob)7=rowYfh zNb*IoybI_xlzkWRB5Hfg>(Zb#HXPF$AM|`UHv9Nq^PlSH?_P|uF6rEJZzt2b4a@=t z+lqcmhY7SyE1acQxBj^8k=}ZNX$uo}WrXEy_*E9O#YKPP(dp-Sc0XDCS^bV@ntV-EN_Yos(3$JG>^YS`#=qO*B+D z%3GsHXquPaqpoQ|Sw|O%uG7A^Zo`VLt;ck?T`8KpZ0(j?f_Apwt`tvSxA%+Hp$Cm$ z+d^ zvO8;r*v_2`V*M^%1Qv)wzYSzotfUS#Dj5F;H^hIx4Ik;T4*kD zEq@y~<#&kr^hfFEz0vwKehMjTiL5_d;LWAvD}K>Vfl4Wz>Nfht!!(5 z`}}%*?eDdN|DR-Rt$HR^&ZQjav-``n8)fW`Hy3_>r+R5q%|4!>g)6Ia3cK!D+2>?F zO?Y=oD|WUu_rcGtD;J769zVUvU$R(yvF(YSn>~Y8%FGG$S1)H-_PTCv;61~ixfUgV z{2AwMynpyw(ATWp_uBpJQXb~q6UhGFu_8O`=svBYmk)YR>^I<>$$Pti&Bnw0NJAL2 z?1z7=#WvRL(#VNhmSVT)tW3|ERTotz&ssb$?^;5Gdymq|mYAugmbXi-K5S+QSzEE= z!p(F4uGC-sRFW&RbJ>@x;XUahCmbFe(Lbp1sdZxS@dSfS26jJ+pB3oN=019;ko(c* ziXU`^64;|Zub9{86Eo*HcX%8B_nSZ8Z2oa|`JxX|9Oiqb*{S?~{UiJA5AWIbz2S+? zW=q5}O5J0(TveYYzhl46)x)g~_O}x%W`5Yb$%^|{EAyvt*6VLYUsMmJ7mmwL=> zV_NY})b7A({|{egf4IZXo!Hr5YQVBrwde3!mhjESvv{xaP1UWIPG|c6yIlJ##~Z18 z`YP|9yWjeq-g&soRVhp(K_c_%5zbL zDY2GatWTdkf2@4vFW-4-cl~mvyX8zAsjM}xPuwqjUU!^-T@&lekNR!JFK?cCJt32U zfq^Z_+uensk|By=>YMXla~K#HI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_QxE|ft+hV}lvA9nFYD!5Nx={$YK zlZMMm&FX9BGw!nsDoAcAcI4R6IhTul`F`8;B+RLJ)%C?Vr-7gMtN2~^1oaf>bd`6Y PijKk4)z4*}Q$iB}P@Y?0 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_7.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_bow_conjuring_7.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ee0d92ed2c5601a653e50af9d19f2b77cfcf46 GIT binary patch literal 1786 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-9jZbiN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsF8JkDjEg$@AyANHxn5??)Ck%HPrfKte&<1L-CX*&WWl|r|8rvw!h)BN;?03OUmJWubcN;$v=7a?U3V>i@!e4 zXzSCTaQrt5pVoT$r){%e35J$rhPBp3mc4jk5$JkP*7D`%lUD0n+Mm9-|2eEs`p+L3 ziG(j43(Jr3`rmsrZ<;7Sf6X`6wQsC>oHzY?{_fh2@EbFuzjN-1e$Qzg9rDiJDKX~~ z<4aEEslhe9cimoeZaw{}UA!=2TmOFcH_zS}J-1k`t;o1Cr6llrP#Hh7_JS|fQHPHH zaQ{*nFF8G-lXpS+hR8xw=b17W=83EbUg(*;y;mxRC(pv|bxd*H=_8v@ugeWOv@64k z&Gv2s_jBop&jPz=>u-7cEO-6H14ZgRB`m2elJoUGd;L(q?t5{Lc1h=&I~$tf^H>$` zM4VY`?bawTt1I))k9VhSj`Y?lTx&kKBT-Ce!;PwtD<0o(e43r!UwDx%*?)&{c_>3i zg7qQEPYDOqK1~#gEbHrRSllq5>HJ*&bxn+27fX$V?^Mip=-ZJhT|DDkg!o;-#akLW zUQA98Xl7xGRCGDQ&+f=G^+mFQ;V}_QuQMA}<~wz1s`{;V6a6M*QIwSS@Qmvomd;5n zt}5Oq^{S_Am=T;dS@n4gSC7~Vy&16vi>ACaG%54Uom1cK zdhhXnp4DtU+wVph3RB!93YQ#oc9Tn0y0&b7;<1@({xd75NoSvW<$mo&=g#$!%Bi`A zV&5$GZDuq4ytFCIva{RR;2Be6VH}Ubg1e8-aJ4=VEABR)EjvlcYJ*$h#LJn6Y;1=W z#MSTa*lqk>HD9gm{-d*dlh5hAs%x^`ydwCS-REyjTjRd zl&$K23$y>NZu;+eam~9EZeK5}d;MN0R63Q^ zb^DjjoU`h5+B3D%&g7P7sTV>;RIHfY4kgdcX~E>~AnOrPd`qyB2_CwC*M)L3V&bK-Mz=EyG%y{G?% zUF5UlNAZJ3UZ)TEP2YHIv7F_SGonggbDzA~68)xCZPlqI`$8nT5><~xGVrDBeI4~_ zL&5raE2m}eZrhW0Huk{W^OtriW^dR~)4=iXp!L`I6NQiK+NQIF_v|rl37N;Gx!xwv zXVnb%e{ZH$u5OFGySgA>Yl=lcOwKQ1y~Wl`_LipEpH&f7{S>Qpc2#$?vBhNoxU{U)xe z$p7BX^g4ABd7g<ubF1@r0(yv#uTS+H5f;@b-FL)*tJ?e_S=QV*S%= ze?Bhzc4b!Rj`hAhpEr3N|M#mWaL(nek5eP#ZU3&CR9^pK?>FOrcSLpfUzsfG{yL`o zLe9r+y&iE>m9qo%YUH+Qe>VQNC%D93mLnlsVO91@M!kPatv(z7lX3mQ_4?)??oAut zPT+2@S72aZU`z6LcVVbxh+>%f=KR+j1_lPs0*}aI1_o|n5N2eUHAjMhfq}im)7O># zF$c4tkkqry>AnmMjMknmjv*GOmrgeHW;PT#UT?X6?NWD5uGr`posQN#J-wzc%qM!w zHcohW=g7stg3=ui8z*NMthab2e!@M^ ze^cg`d!tcp)>*ctRo=QKe|}z=dO#_FEiXx9!>Mm!yw~F2d^kCuZ=UrBvo@vx7Bi(4 z1^x?f9$3G9%JxV9dFFH3SQO}bwJ`O(%4pbEyE|uP68nMweDa(&#{-z8CI(tt&D}qF zUDT_-YjIXP^*=}*R^K2adG-8(>q#NjqMt8)z2C^M(9vUc<^Z!{R`B_PYJaEQxBdJk zo{c?Wl6R=tD8ZA*d%xSYc1@KjMUbeJ){@q9=kT*11{3xd#2@&X81&m$U;+aJ1B0ilpUXO@ GgeCw(Mp2Fc literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_0.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_0.png new file mode 100644 index 0000000000000000000000000000000000000000..43689fe4da8d676e86e338ca25d6c96824a8927e GIT binary patch literal 1588 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-PFICQlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNT569z97}ljqNKk!ltd#-_&~dTvO+`Dk7lvh(&`N$Z$cjwzqDt-O^&JFL1<>ud++q?`; z?c@D>BmKqShq@R&2vAC#_Hug zeqOztVR5BKD{r~t#vi=JqK+(+RFZpMi*q|0r%u{n^2M_3nb`aTyO*lJ$+4@dh zP@+Y>r*Gb$=Qng)=0)rdtNY%tDD?NY&uqI5qhuDpznd!F5Mq!Xd_8O$%V8#sRA25L zBJuglUstNe2u81A*xPuvX|^}!e&n8uyFe@Sbw-T9fF(+>Yrkyi>FM}t-hDFMNHsf zpb}SBfP=zm%l3c9$Qkmf!R1#pLsjP26@Z3lhJrShL7)FI#BuEED%my72Zv^{2?BSt7w+mdO`+u1jt<)+y49S+e7iw?CLA1BG|?gX<|&)6+m0B%u@t-=u`xaTb;q9P zCQtUqzUr9XpB;UcODizI9LMdT%+HY|`#km%nwdR@Fg{oMT(;-8ahZ9X`OwQ9fk^WaX*lE<|-rp3CvxY-!9|5W^v z+Z%gB)@}Q+FnNajH;FBi_7+XC+9A8G>hYe3GvBKnex>PVWNWva^=<%D>g(5fy}uYP zX)SCiS6VR7yzkl3Nq0XyR@MCW_D5rM?2ehTc79uaoVHDBy0YmuuT;XfcUKDCla0#O z2h7)Pr6lf z-Vg4J=MoKstD-;qfB5w=BhHxRfwkjoX`$|zt&$(uHh*Q1o^X4zPT2#|SJ~}LDk~5D zUT`Vx*xBpS)@4pia`OA{s+^U7vFU%O@}IYox-;t;neUxDa%PiL9|HpeTavfC3qvJC z6vNav=fCDKFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#IhX|n7~>wCQD$IZc;)Hh z7-Dhy=wyHYLkvyl6(tBiWr`ne%N1gZoUw%_q-6PwnB>du3AqoB@X2Drc7ZuM; zQG37lC-?u{S22f9GM%1rKzkZzqr+Oc%N$Z4C5*V%MO^-BC&bC3GtJ94Si9nIQE#Hl z!4>Mi6g|w;jTgD>VUenQ_1KE_&WTBy%SndbH&#qVUxG;ys`|I?rMea_FY zTO(tTVKXtx_RZp(fggYE`7~)#)3kD}(&`B(`)cZCY31d%s2dixvX|1B0il KpUXO@geCyQ$O)7H literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_1.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_1.png new file mode 100644 index 0000000000000000000000000000000000000000..9f3141dbb987fc37c8b05211b70f749feed856f2 GIT binary patch literal 1593 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_3.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_3.png new file mode 100644 index 0000000000000000000000000000000000000000..1fda3e0a68bd6f71171bc4f4a062509c74c13ae8 GIT binary patch literal 1673 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-zEy=plmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNT569z97}ljqNKk!qF}fu_eFdTvO+`Dk7_x)kJi%WlMJjuN2Xz}?`;E}xk%avv?Yo`A_Ty(C#bmb1; zy1H*%2D1_-%q^VTsrxQ5DzV}~r}3{H?+kh-Y6_p;wfy>xnX`Ye-1DtEbncn)Ir)VK zW^*_naxOOZ`y{oy^@4Er^r!s#bE3BPUuP~$-eTc)fAwiQhLs8D7Oh*V!zs+Y;K|oW zhu}Xfo7PRcpfoLlv5I*%>sl$VCk@{e{CkafU#(sr@^Df4UCpZJs~($*MaCADPJEQU z_@T%b6J|G=@D0Z#%FN?4Zu*{%Tgq{|*FgAWK;rekH_og+_i z%ph=Z+X2ZWg9K)$Sxk|oew_`;EcTM~tiP>mU=%9sJ;PvrhVhAudG2HBrKZk_s`+x+G)yOT*Bm z*Kpa4$=*FeYMLshn#-mXwO!=7DjA=C=ETk&hmMMCF3jjuof;!(cQt(F!mM7?t9N1^ zw|&W9xH5C&(rMPEEkWO7t6tnn_P6Cfa_hmv_8x)lle$8M_)yf5teknz4$L6RTteecpvSs$1n;!RepS<(rj9U8=0rqPiYL>lf$q5(A zi;P|zyE}L1_C1mx_aB-4Te3JU=)3w1Wu!eka^;gl;^7v# z&E1vnJnz3d`(EqEeod*Rc^i-A#m<<-yq@#xHEvFed0SJv6hrJ;Q|y_JYjS<8ak2<} z9X-eTv;LQ7N4ayi=4_o~b#UTWgT<>qJu~-MbNcKX;oh%Orq*pwm-e5S^?6%Z%e%O! zUQK<$z~}BI&lwBTuBW`2zS?~HhsyJ{IU6n9Ja0%jsP$aV1WjW1q78y`D;Q#)&9 z>)M~1vq83KErIBjd#(PNMFY_xI@%>7(=cy2(;uCvuE z8BgZ@bI@6L?@scD+#gwQ9|mMO@A<&_Fi9>soM*!Qps#azW$vt)_C`Ny-?=Ay&Cg$X zbRgq2=fRGsTFKtI@6D!q?_C;r{b#4Ac;~~57uoIKUjJia&$)N*iVI5XKRAhee7Ys) z+*#$96IV^0>*BiO#+vGF;a<#|JJhCrFm3q7_r$9-w`t53)?VGK?bU3`ZA#%+1e?|P%Gv7~3 z_9`52bvnGn=Bz(^AzMTB?8lc*t%=e3y|PS3?bB@z!~3fw&nt$#)>B^UDtD&jkz8kM z$8EprIjJiDvd;cXKKkE2yv5#i@x%LDe~MpTd0+OZ(BcFJ1_rhyZ+91lN`@$gsc+7I z&0%0*;4JWnEM{Qf76xHPhFNnY7#JAXOFVsD*&lN-3-XKnOIHhHU|N?ni*ui;9%k-}(E8|Fq6m7WYZGI3sDxk5-XMr(dkNyZ`Pa-q*EuZ?0A2ZAgw=L`ArghH# z^toK1;i81o`<~bH_8hf77iwek;bi)jUH2j+Cf!s&AN@(ny7;wSWBF^_#PrV-e{T>~16hzP7ys~xb)#fC|Dbl?e z%TIEw5`9}EBzIIy+aW(;^MjRbLY50`H3Amwt3SsWeMdo72jusADVAt?wow)g6gKK!(4Sc zB^wHojm+;~U{W;UTejyzY=32k^lyhX?9F=;!g365Z}JscR-NAIGK%6yVmmrj^p<6E5{xmf*~U3xEH_T-Hl zzC1Z6bwp`8=d7nK>gfq*SeYIhNjf;}J~=a#>!9y5wRAH}6;|sFZZ;<~O(dC{7fycc zX#Vcqnc7pcAAZoicgOwAOwYUX6VCa(;wye%S$#0-^lO)o-3w;63J1St=aLrLmA1Tc zo~M1@+4oXE_Df0~eRlP2gWz!`j=9b|`7Yd@$t0YfWx2(`-a>TA2{H9cCTrgHiwT&m z?%wb}DceqJfnebrpUt65Pxm~wRMIq#xv9L@VRioYGhe)qf3jH``9ICPrDV+xiHUrd zS)A7v)enPL>x4VymVG<(rs?O~`OB>S-d^#j>Bg^1Pb+i(xMtf)OgPP^rQ7$g z*JJbExNNnm2w~AP9#ZPEJHEABR?YwXM1Aj<%QYtpGru0$a`ZpvN1X{PAAj01xyi?A zU0e2o*6-1q`SaS&Z(DZXpTGQ*z|F+g?d#bRuLS%lU(tM}@$^r}vKH~yRqyg@IRfUy zE~sbc@LQd^DBfBk-k0zG>NV>e`}ppJ_^X8+^yP3(sx?`WYTfYe>7ts5oOaF9)rrCT z#BLsCSlWHq^Ub@O?SHj+-YVZevv~5ZtAVq!gYS0pazFDAm6TEIxEt$jUS53i&#MNB zrB9iYxmH+y6j`+<-}LP2mCKzo?EnBVpD(~r>*Z3v~zGhkdww7=GV#dYx1!wjhd(n4w<#Od)jQr~=9J-E{@L8sK zc5OMo^}gHjf8TjH-xZ$x!`-O+@I>O1={5`u3~Wi>?k)_K3{ebI-<O>_ z%)r1c48n{Iv*t)JFfg!}c>21sKjvT-7$ePdNDhSwC=w- zqb1?Qk^LK1Ds@kYkhq{OApMc?87~X>eD$LxVq#4kWs@$68^rdwZWG$%cri9$+Km`) zXOkIMeHU+++>yTT@Z7_)Ki&sZrKry^Mf0Mt{ai=?ch;$0bq9f?7id#Eo&y>37 z$@lTrwTt15>#ak#KB?83x$^Q%-g2Fi=<*&usZ)37h0UG+*!a?RH@{i(YMu+-JPQ(f z=a}|>d3(n?S7n=<-fTCyXHEOp6p7uiw+nAwZ2!0Sy-#NH0|)Nwix?Of7(8A5T-G@y GGywpu-5XE< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_5.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_5.png new file mode 100644 index 0000000000000000000000000000000000000000..164c0c4509f0cf9c63737ce4d655e1ec2e9d587c GIT binary patch literal 1723 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-1*$?KN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsEj3kDT;o1>fIv(Y-7xY@JUH+`jPL`}Eu3#>}bPS1oG0E}!cz zCD}aT+(eelU;qEfJ=2fzIVUCWlH7Ii(WjH@=LD|2%if;yw`!hvHD~^>vws^eKE1H( zuhehJ`4{EogpbVs_i5XG58J9Q8oNy7Tl3bP5jbaI+a>e9&g#9|+{&BwJB#c5rgc?+ zc)eS^;Ubfjtn@p+fQORLwfMw#JTZ!j_1Ec{r#bm^Mb-2B$Isn)#9gudOVix5%kS@P zJ#?dj?TC1fpMC51jnN!?H7r?9Jz|Eq5h+kH5IR`;GF1u4fjdJ2$ED=rmkf zn<=>cfw;oyUBY>--J%Q3H$)bMJ9nlf@O`?Xae2YMTVA4SRqu2%W@_)gy4=sAFm}n0 z%F79iwr3jz%S6{$mVD0TUR!!OYW<|7r*0A_SyEdh>+d|u%c|?X6Y1)_8D3LYT#j+?!fn3*2*d9^HI+N5bBX)^|K_ z1u}GOC~Gi$a-gC236txlLpm-80uTDPJ$+*%Zs4F;plp1gw^;Cr#`&#=?isyL5A2p+ z%Id-*KDR+iMc~9IJB7L<+DRJh;(It1k0>}gb6M_sk=$YEHOEw|TUg(5QO63EldrC1 zUs$ndm1pszCjp0?x;%X@O$j;|Vd7kR>`jlLrMTX@A3|O_L0gtg(mu5OmsHl8psmYh zNt<7v@K4vw&^J13XRy0Q>3!$^*j?YQe0EsFYyO8rnNQN{(h2kI_N&|1T;wjEzuB#Q z>&Y4MkDnZr+U2SzYI53h#+*jOZ!E`BjT#!Botzo^X`XuVWaHTqo`Mo<0%trinbp(i zc)#=Tg4w&-i|2nzYx*yi|3|PmE$I9IgmXTx_=@X4edEj4T`zl7w<%4`&u6W)MvlY< z)6LIzs{h?#xt z|M2`rsA+D!V11p&d~ugKtqC7Cm!17p^}6cm-etD}cmGE6$(r4bH6YfAaCZ+mDr|^LZB(-r(NKWhS*RVC9zBgm1epYfFYK z&HMb#Lg{zC)Z}N2`4`6swl8M%dhl%B;~fgqEzezy5bEQ-aeZ5d)yv?Z{@#!yl>K^tm8LJvNf)lyt$!cG3lCZ z`mPo0u9#=c$bZloVwc4fWciWv)U6%gQob#JSi0a+xz(Rk*K0N+F_EeA$DVyLn3lL^ z=i0e^{}jRxd3rU+Y*g20|9$AUbEd@-p10;ohmYHDjoENWDf<*(*M|)zx9yrsmWOe! zUr~2q7B7?R_X%g#zLGOoVK)0wtD-`Iv?Iff7ooc=+rEU%vx?ERwqf2X^QV!~@Lulz ztg!0t8I|%*wogJMR!nc*cJ9=srwxN5_mhRpl60?(e3z{YtoDRm(Q!} zIw5bdYsy@uxj}yKQuwvJq(Wxxo-4~wfD z(D=?<G^4$A}w$E$% z|7^cv;e5KYG5oPZvbs9(&Dm``eEIcLlZC@K zZV=rwG2MFS;a_)kj63E2*2>pQ2t<`;UaR@2zw6P(Y3&d9iL$Lb6>56yQ0esPA`Vk3 zUtQu6U-0zCl1R()%2UU#CY@SpykqCr>V|1ujlVDH&Ta1T;;|Co6v^*x*XP~hwIT3~ zruz4nE=;RUrPlG@nxQ-GYNFzcD0}<))7mZ;J*jEw35(uSxFLJX9IGg)v_~_qJ(AWH sbwB;s<-_#Ad2B^TH_g)i^D@7NJ!C`XRn{pwpb%&9boFyt=akR{0GHD@)&Kwi literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_6.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_6.png new file mode 100644 index 0000000000000000000000000000000000000000..6d7731bf4529171ff88cfcb847c2b5d990c05d1e GIT binary patch literal 1707 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-1*<|LN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsEj3kDjEh&hs~2G?K}w;X+YGSSovD9bbRm`3kx3eUrUH?>uEo zQRK6lbYR*4ug?wYA3W~Z`_VDziiECR+}>S1ew%)8j^0$a_xyplx#dO0{~stMZQ0Yl zQT{JaWrdGG{gbDA?|9gjT{0|*v}3DW_vV6S)k}$_?N3XNxt-th=6=ren#gIL(LXES zu%63cbSgVmsQ(^r2`99iL7`8DQl-pOC~?tY_eBYO7cm90~+HYYV|SNe8W zu-tFhx5oXWO3ubZFL`ssY_3iaV!F)t>59hX1^aG!i3;p}?RUW{Tvk6asqob+rK9KD z+k`J%=8-6jIVk1)CQoO}wX0j>mbOflcDyXuBbZiGaVGsx_`KT}B#cWsb9U9T#^kXn zB=|ggCLN{Fa_nPf#J|}7N@4SFyc>Dg4i^<4V%w~H+lBK>hi;sW@t3Br$KDmFXC7yW zY1ztrK%kjXx|7*;)1x^82m3kyq$rfXiDhIKY06Gv+mYC(puTgb*)tB^Sn)ezi?=j% z9GJ*@MWNAQ+IPl}%65uvMGqeMawxKKYG$06xVT^Om`35X6*@X`O)i3-izW%H&v)wb z4Dy<_$trcqh6RB~GlH(p*_hGxvgf9xl%;t1jvqo^Izd4fCutvA{!1!rO;GUFS+le6 zO!%j3W~ghLyEE8bqx8OWe{9vOTb~`)@XFP-2)6f_lsuWe_3*3eYcD!?zK>jd_*Tjp zecQ?nY#UFcHllv^}mTtULF9tBF!B%T+J&`Uekg7>S2T-&XB*7hNB=tz<#OmY(8*-c4dl@0NO; zX1!Q*;73ySzB|qm(h=LOM4ngJ9d3GCYQJr^(5_7{zkB>iJbX>-%AIA&ai{C9%+ePP z5H1TZ`DHq9>hqgw5C2TsY;rBeVAl1=3-;dFIA`60IpsVL4u!iv5)L@Ev`%{ZGjpcz zelrf1UWvPGd&o4ynOR9a^qfYx$QG5g@(lJ@_WP?Xx-O0@&wa32c+vcd zyi&1 zP1LuT{6|s$>x>%9BUK9)ZTtK3`N~pXGkNA+pI1gMvYo}ghrXDgyt#*Ct`U>%-?u8PPjZh2&wX0-`1sBHf7UO5rMFILg+}Dz zbNdssKUZC1{qL$3wAnUm@A0i!M`!(w%&uE|V(+xy0TQ46YEJ2wTfBafY4}+$?As6mxO=SqgU-6hR@#wS1jN2Z0_Az;p+d)+bSMpweNrYEdMI& z!^mzOhqnw23~Wi>?k)_K3{ebI-<O>_%)r1c48n{Iv*t)JFfg!}c>21s zKjvT-1HZBZhX^Ln%=x|hp&!^d8-r?{s z%nu4#S}h9u1Xw(sjjWvysUI*D&}KU%#KFn!o%qbPgyq&2@AL=0dg|}ysh^*3{o{RL zD0|d7ot_582~5gKr4nNAO-~;b7t7=6X*_>Y>hjdndEHZ8#jnSPd9OAVtzme7V6kOV z{q4iIJv_JXE9{!f)AMZ1If_RYI;qc3S|^ox5l z<>pV@ceUtIy2{hfD*2wQ6$xAC{Eqrn_RM^(>eeW$ebb)LJg`4%26K}}*yo4y{~gnJ YYDzJFHakm?fq{X+)78&qol`;+00n{{VE_OC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_7.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_pickaxe_conjuring_7.png new file mode 100644 index 0000000000000000000000000000000000000000..845a98e34bc93643249ba29ea729ddb2c7543201 GIT binary patch literal 1694 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-S*k)JN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsEj3k1SHrWA#K7z z9E$fQvzYyTAAk5ytNdh($2C_bIBoc`^NCP;$(48a^G@#iYA65gQsso%uNjb@91`DdoMOIg3aNci=}#m6rk{bZ<7oa*-c#Y;n#Jx@#a`C5J6wEOnCpObg^#7v#P zKbA$}tg}YW4(`sQ)@MRlku%%hX^pwep_1l74yZfx&x15=pdNM>weOx4gFrcTPTYL3LBrQLeg=JPtby zXU@*gXcUlQ58nSFwtr{0bhZ1M2FLvgVL1l3H~EVAZ@)3==w^rW(dlpa%Ddi5Ft|kA zJ}fC@kiguz+`-JqUFpG!2kM85#g4P`O!$811W$pokVD_680lgq-Pmt?j%w&C9P*yP zku||V;k0G{k4`^9=bPQ-$ExLPzPy@z-m!_>u0`PRnm|jhl8eU$lCR823JY8w*X$PR zJ4;yIk@K_Wl8i~qrW74pB)QBuEj{B&%npyjqtgSDE>7}V$1(ras`U$xtunoOXNRZr zuk9BWW!?%pJ=e-<86zOiSQtbx}u-Su5BZrHMX%{i!*Su}5sIiu?m>wAyZm70XiGM6#d zm$_wAW-j|^vrq1t+Y@`9MAkj9Iudkknd-A8%r>*IT{balSFNSx z#aWVP<_ekgTyHGmZRu}lC|JKYcE;7ffZf-pz1h3{+sWw9vfJP9+2bHwof7h&HS(0* z$9uE#Z>q*zJD0Wj%CosXJ6@SDH9nYV)z`YiUb#2JpCQ`x(#G|!-cvq3ej(Fp=6SLq zG1aQ(aoG&ND64Lp37gnAu}=7v`cCrBGw#@{-c|?BJ>GihMyf)+GS3-akDDA1(`I{Z zYR~mN@yYhWWfQr-kr^pFx97!OSajg(QSYCZZmilCdpT>Zv;V>@F@ZO8XRU8|5**Cc zz*FNnr!tje`Mio4gmbTdkuTfct7n*-YWgKwYl zS7TUR^3_^^2pNnEo-(YWsZPX2X0%1_lPU zByV>YhDwGghN*APf6ZZFVBjq9h%9Dc;1&j9Muu5)Bp4VN*h@TpUD+RVFbndEoC$Qf z!oa{N?djqeVsZNDtg; zj#dMXmnuu+C-}K`ggH5^o**#!S>&5zDwB9U7xOQhIkURr`##AZ?~PK~7n#ddIk3NA zwr#RJFUHhyud<@VfQ9X-6w}65J$0GfADqVf%%s_Ow!8S* z?Gw6R%gvLy^5(`RsmTp1V*WgMc=q7Bx#yDiG8}oza52sBn631ggX?dGKR>R1>(ioe zPrjM4ytSEAI&Q~(F%!)Fx%B>)jQic!gfI3lJt7<&!5Ad%WBU8@{U5w;+=&}+=5E(w QU|?YIboFyt=akR{0FlKhrvLx| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_0.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_0.png new file mode 100644 index 0000000000000000000000000000000000000000..45edef5bba5754095dc52f34a03698fe7362c240 GIT binary patch literal 1668 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_2.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_2.png new file mode 100644 index 0000000000000000000000000000000000000000..c49f2bf09e239580a2bad543587dc8fa37f80e86 GIT binary patch literal 1777 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-^{YZ6N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}k1opAx|yX#py}y{HM3;Td|F;9bNu7h$v?tsPO(pL z6uLXK&$ta7riiU|LS*sqw)54%oW@3F_)RiTh_N7x>2Ck z!rs$2=ZR$*_d@n-dZ*{teK@yj@BcfA=5F1|U-s^P!#siOSxl*x+q+k#rV@0Bjkn7g`fy3VFuPhKeT9I zeBmg*Zg>Fc)q3n^Bs|1L+9xyj!B1oIDM9( zMSAkipT~3roE|4=ao_(sWA~1Yn;$ohg+m#{_Ufdl5 zOFEjQR0K|ZiW9JZrJSU}-EFQUc;qiFx>_drH8TBa^(=am;_U`bxmoW3#gI))hMc z+J526mK#B*=UO?f{H^V0*?(IH#=gAqh_9X)B*F4lLd)1N?E|eD; zy*PH4y*U0;+L8T7XICGcGxN${w&Jv)@)^G;Z&zQlb&sD&9LrgqIWwZxx zZ~St7^ykH$i?`&iejw1fd$#0~GkhF6Ed4tsicgvnHA7ba^PQ^wrt!WPuBDc$mM)zz zU482}x6IDDpX+{xFi9W3`%2ERdFp=GlQr#KZ=G^)e%HLc(MM@klg{?Qtzqt`Y+R4! zKS+st)U-Ku$2Q*Mar`>hj?WI?sU!Gkx>|N(wQ=Jw(`ygTvbvw$WB5sNUYtO5zwy6_ z`JSDNY_Ch?BrbcT@A^%{bdG{#O!vD73#V23fBpAiYQq)I=ON3@rPYp2?BzZ`>(8dA zaoZ*ZwX%z!iw@Qd=*ta`bPo2C`K8m7SEyss7g_%`#wHP3E*{{GMI z&zt4#1D$tl(o~P0Rg_=4nbG+|o!OLH`8&t21q8j_Q7|uKnOMHUEa@)CZC*NaewM$f z%=_jZH*0xbxm{klNZ2&qaCcwc@O#Gg3h8QR|5?ls$W)h1XZs~vD(U&VHfQ#F^^Dcl zD+(MQ+~7!Ee0kTiS6_?HF^X*du=Ca7JI+>98^R9c{x6itxU(D`1 zb%Zy(+^eLyp35{}y>MAjlI4LZ)>DFt^RF*{AGJV@ed_`Z&eYpY?pKNz*%l?nJt{x6 zk9&3{`#k;`OLFfX4t*PC%Cq_I5#N%Q{zZ%xj}&jMURIdny*BHmli}3YIu1U|)}DA& z7xZy{!cUpddj+{C4stZNe7P@rZQdHuCv5MJI9RE_)9hPu`~Jhf9ABUAY?IoVdR2Mv z;e$JW3f|?LlD2=H;WJmmCy^X-u0z}&OM@u`0I`uNI<>YQIxhkIUgtLOv`>!LkC~3 zii2Vn?}FouO{}cZ{zdK8MdyD0`#*2>5BDEN$t_Cl$NX-k`77y&umz{Rc=7UtAlv+g zZD%r1o^(DFQQ2@PEXs&=UyotZS;eNsJt+@x&&{w|Ud3QrUF?2T{ z_2roPK%~ wFzgNse0r*?aWPl4?u!llB3bvPJ;dWR6l*)?&u?pHU|?YIboFyt=akR{09$ZJyZ`_I literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_3.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_3.png new file mode 100644 index 0000000000000000000000000000000000000000..e5a4eb38945c43c79cbd77ce2fe98200b9c793da GIT binary patch literal 1791 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-t*b&JN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kDPQ^gXiyakz$q>fu_eB!p`zO`|&wqPRXUY_g1~_I>@5( zah_PtuloOdpZWFNWqQSX6-(IeO(#%=4z#c`F4AmHVNJL*Dsv^ z(^I%pKcN2D>Bl=RRy{eQ{9;lK%cm=EE?9nkBzPpR|8k}I%QdI}oh>`pU)s6Dx32Cx zm%*%r33ChQcIwVc%u0+n&}n>Y$Gm_ZLD%_~4_-#t9Xoetm;ZyiRsJ__)*SmO$d!C} zrocP{tH&zx$=e00lHOkW^P&BF*xTE$dCQWwSh(HaecFy;Wx}~->(;K3QxofWv{mOp z*dLbK*z!ZN8;^2bkiMa_WA#Fp0w3!W!Ha#Ge`RTh&Ug`9-gRx~tBPLNu<0?eOMX;d zF5s$~#c1899g)nld$#VDFUyv$4{CYlHsdA7Ar9?(cb_djc>j*MW3tb6)lDDUMBfx$ zW=uSml4obg-EzTV#;HT)cc1m%zhQpFNMZ_W@e#Joy3sCzyMBx5&y)Ooq$+v)?#bJf z83Y`+ACO2gNMPO=ps@O!reHzO1NFm2$M1<6I4G@~DEWZx9)HoI*}FEnWu7g4^vxiM zyF;L*qe+TI;KZl62llU&Yc#mK&6R{)RJ|t2So}~>WZ^Y-Pfh)*B^6?tbxFqZmxiHB zui>&8lf8RH)HGF0HJ42(YP-a9QF66$+LM@=hmX3a1Z+7n$!lG~{8y{51Z+JvD=TkZ zq4SUJ7p`o%5p;U4Rm{rYdbTBRH!h#YUX%ObgR`52)guq(`w`Y_>^8aipQ$}3C3{UR zx$f*`>uiazy)GAg)Qv2elg|lDTtCSmbIbQ!j>`MHDS1U{lbr)Pn6p(T&vBbTWxTTQ|_xs=MTPk!_mG-m1BCPg@_ibLUpub0Hi1Gh!?hf7C9S;9It3 zK~cYz+55I7WgBa6PpEA=TB7rA!;HiSHyu~Wrk{O$;>siCy0k-LDaYf!)wbQ6_-bb@ z=Yzeb?U8P%vhglvmO0eQPa0P^QF;S=^r!o z8{ghu@6M&LKmYP(-d&QyA*{K2shf4(Sl>LgxSOIfx5VM}>tlT9`etpJ9{qcr>H2>^ z_AFJ*eJ!;v>-s9SoYK#8Slyqz4YhD><(^-_?j7(wE-|4_dO5@U3e~RvGfLko*~xF^ z&3QEYc|=Hn{Nuj9sqf7`nLe_(%fHNZ=N0|P;`^yrWui{bHEGIUc{Tg$;$5#9CuF9~ zK9=a46>5Ec#pd~!7ga~L@HbALSm?L%hgn39`&9V}8OI81_NZLgY`k`@`t-0Gu{@>d zn(T$mtzQ(**__zx)4ww6zTdnvnGaI)nN{DpvKq)=$+TT3${h3dl$h;~72$k^27Uf5 zXN&`8ocw>C^~FZh^?m#wkE9eCXwNxR<6CfE@^Fdh=n1fkB zMe=*f*{uu=jIN$8jv*GO=T6?}cPK!lZGSW;V{1U^2HA)?R==70jFMC?`FO{ng2riWv$4vOP4e`p3eQ_R@joTvc`&aU(1UW^Ao{7 zQ*Uoe@IJhG=|k0%hYu{+V8baWtg}>|L7MBB!}+aG??q48Ej#ydg73d0AxCvvSF`zs zu6MfDcp>*>^63X__NpC^c=af}+dj>JZP@{t396QdLYBWQ&-Fh0`qbyS`i|;Tu0Pmc zqZ?WC+VPFu#l40W`L9KopHFC%F(^7%A~xHjZRx4{s1pY`1Iiw}o-qHcIn$q#nPz&aGZ+{c O7(8A5T-G@yGywowyIu+a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_4.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_4.png new file mode 100644 index 0000000000000000000000000000000000000000..d040f8e86c88b0eb045e62b7ed9a91d7597f69cf GIT binary patch literal 1791 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_6.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_6.png new file mode 100644 index 0000000000000000000000000000000000000000..aa0b9480d5f7d85325fb7910ab9c45e4434461b5 GIT binary patch literal 1817 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s--K#<(N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kDl~IgXhn4k!qF}hJ%F_ZfAJE{g~bG=GD5oGa>J%EaqM_ zsrAH^OIsxW|C{wpzDDL}O3eh3;vO;i`L$)NlT*$=?@9Ul@0xVA@4cI6|28*w8h+Z@ z>-?Ad&BKok6?Wf5;Dy!S~ zoynl8VdC7v=1$#xkE2>AGN$WET>f|L&<2iYXA-0DJijrs`WMSR+v-E-#I}B}*68Vd zB{1J0$h!6X#@igW8_U-IdB<+Q=EnB<<~PpXygcXen{_`pmMpsH8ykJo*dnau(cg$8 zsz11AoZe@&u0_|Z;oiZtqgQ!SiyW#aE%$3x>$Nq@^0>JBAGQkfHT~)lAO38OkR-^VasJw`^O_{ceV$ zu7Xm5%jzXp9TZOgZuliQKfqbF;DcI=Ky!;ok;cTu{ffsl3Nu3l#q=E)b*P*S5>lV< z)a4oEWjXbYk@F#^zDOTG%jZEGG8|ttE$6oJTDh+1tLc@9rORezXKKuU7M-!t(_44@ zrP$|v-`;QRe!22_92@VHOCOYbEK-(Cbf39m>&eUK4IWRKnKtifnr~$7c_~}N@3z@X z*61Gl^KCMFwn2A{V#Z0&h&hdh&pCTeCo!$?Ckf54!WNyuZ3B~={j}BMm@3outUS>)EhUJR< z3nR+Z*7o{U&Yt_Z?sNqW&8f0^4+spd_zwATH#ns9NZ`FU5G;sfSnzLnZ zZqb4l_u?hpuZ3xz@ND$jQuNAvx5l;mT2D>~adWsTw)8AMu=VL1LBly_d(7CLu&&ox zT^s#j)1}!dZ~9Z-Jnq%~4qv2603lb#)Ps`bWy zhEp{xFAhdrmx|l5Vnt6+-!{3m>t%Z?nO8(B-nIIYmA;VWbE1sbq{@Q*tRETQq+85X zw_N?$rX!i@NfTdO=cT&`qrNVTnxnNwOX!?;T2=b~FwaXHcoX$ykDrr^RSKUz!~RX% z%Drx@Lvt_xxwO<^qvZVMn_q49bC^H3T5s5G-tOn?{#IB@m>hb46F*_yxYJBCJ@tA>ufi20~-G!l&A&Oz@oAY0D7#J8h3p^r=85p>QL70(Y)*J~2 z1_t&LPhVH|#~jQ8%FM3ri#Qk<7=t}s978Nl&z)rJ&Fm=RdR`~ctYv~o)4HTYuHL2p zIv?=QaN4jzpvh--?S|goqa4g(+q$=w_BSe+t%}5*;UZ4 z-n4hmiFZ8Tcq}rQ)<@kk7CtD>Ht)AV&Z?#x8a-Abhr86-W=TyG{gV;FAl8`swEOR) zB^}Dv8BDql#50%`H<*da6$|XNFcZl7AhP7c(ageYljbJ=xZtoraqR=|!@H+_yL3cK zKy$I;;+n#^7FE{OT(7LEdNl=?=+4ymyu7VMT&|=v^}tbacHzY;2Uw+~Y@T*sikPh5 nm-bG9Q8OX-Yu&9qU)dSNtDY`+vhyJW0|SGntDnm{r-UW|zyDv2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_7.png b/src/main/resources/assets/ebwizardry/textures/items/spectral_sword_conjuring_7.png new file mode 100644 index 0000000000000000000000000000000000000000..35273d263682c6e63fbf2e1cb905108ce7e3acb9 GIT binary patch literal 1803 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-ZL2~eN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHWvmN`jTlc)86ahD|%Q{$1s2<2yN#eXVwGQ)SqzAGxVKFsO4 zN#njcr_cZQ_Y?meJRexl)|}yE81=`Zut-vL>+kK}oA$hWelTvT|J!HZ4lO*n_{(p@ zZLnbmo`i}%M)(M9GLbat#-=)#x9pOiHvGax>7DVOlgQgw~FtIw@B`}%0o zYHqIc-EG1TGTBPztY2WZa>s1lE!TXr_j+|rm0q}9*~d-dmu%ngRY79fnJ)e_+umq;E!ds^^XSdR@f&j9 zl$B2^Q)_UEus$I1Ng+Y`r^CcG7V0h+0uQPmE_!}bRA7NXjI!~8W4}2pUOl@dp}ghS zt_NktLEH{3@`74c%p4nLF#mCnc<5~TFYQy>R6$2 z^3_z+jF7;qODuOjnRv*l%hTu5l%R7FCdsdQE=t-K>8<;5NOelYk_=DP@E!h7rLxup zZCy5NcJ@BSKhZf!v$kC+TFw{#>W*`N?5=NDJ~yoAwXbLqZ0C{9d?LNo`Kz&MmBRN~ zQnFc-CDzv!EpJPkn9ViorHW6Q!m}9;F=~t!TV|hGBeZ$;6E)-6GEGb;<-^)ImtRz2 zYr1o?)zQ4HyhwlN%mev_#qkr3h40>1NLSnC{4PAtf5p~4Wg`0-&T7n=6=gr+#)XC1 zWwV~o`||iw&FaS*mg};@Q)cm(%gWxdvEMHcI&(M=UvV3P1j~= zT4g<+_kGdf&l-1Izv^WNo9&Kv$$K64t@-*I`F6rih0VFVvz7cy*NbmC_{)0xx4k`YZ!Tr~pz&Qi=lmK;;g7=Q`%m;* zp8MH)Uv#az@j7AUT-S8l=Dbtm6s z-n?8UeemVM{Nw9?x$Jt}V0(7`E-(7Vn_vAlW#QJZnTZxJS|8k+mvbQlPu1h4y{FCsJLRBX=0bDxMeY)k$)RViY-jzuPS)un^i?o>k+ars2ehrwj!*7>_V9v|EkEi`S_%r7L!;CZk59fZ< zUiop&BL)Trwj^(N7lulPD2AzT&VS8eU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=if zb1(}i>F2flU&X+{=$`z05-IC(5w5$Lkv!!?f@#?ud&a}*;Y zIJ$jS*KX+TJ<7qpCPzHmQ(4TcDdY80kv$?@LQO8d$C9pZ@bvMpd0MdVr@nDlz0b)| z@5?G~#xHu_iGRDZ_)MUkIG>BP0y9Q|FHDH&Q>Xg^DCaNxn#V{{71+G zrKapVi^88@4OpknKF?ZgN8f||gp*IM7VOh)dfxSD=OUBC?o8&qsSzfPr+$8%JENKF zLxSygZN)wM1@g`5z6-+sgtf1VER0@|lz7JB<{<_H4xJeeYk$_e=Db|MRKqww@Sc^y zO~Jfkfn7I*Rz#nW@(^4hyFdEmF3EcWKQ>G-`;hkVXw^H1s$B{p$DEF_WSwspWEN(d zm-9nPR;gm0LgKSECP-9?VVDNPHb6Mw<&;$Ukuwg&| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/upgrade_attunement.png b/src/main/resources/assets/ebwizardry/textures/items/upgrade_attunement.png index bfaad40150515cb9ac107992e48dca8a5b0487f3..01e46ac036816a59d82cfedee4b0cfe00b097fe6 100644 GIT binary patch literal 5741 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 P0L8DTtDnm{r-UW|*NXKo diff --git a/src/main/resources/assets/ebwizardry/textures/items/upgrade_blast.png b/src/main/resources/assets/ebwizardry/textures/items/upgrade_blast.png index d3e98d96c77d072b33fc491c61f579c330ad05b3..3c3254f8b962f85330c3d2513a00795d9e925445 100644 GIT binary patch literal 5553 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 T^1c}i3=9mOu6{1-oD!M#kW$BxNm%dKDDPM$9@ zp;coQi`tcce=on3k2$0`>9dqG*TDxxCsj|baM`>rbW`Eyozl<3ekLsc+HkaJBqD=bd;cf-DvyZ-df#H5)Wy0ad`0C0y(68hIpt+Bmc`G_P9I_wm}?R^MalKe7T492miPqT*|D?R zX`Yvv(`=@zI%kTK9$MzjdMw%}vD3(=Rj}vc9kb!cUbtYsiMx-%?BrGpoBPG5{pRZa*;AMjwrle>Sq72B z9DakGg$-pQ-OBhV!89S~OW?eHk5XrD-0Hy5 z-@0f58#hOi<@1U5uat^3s$a`izHbhful;0s<3SU@VunO@NZ4w>y= z^cpUkFw<(&27Z%jfxD-L^_T^l^95{nf{! zw=SG9yRIsnH|=UPhurN>`B{#Jg*-<~H5yu`Eu7i;W)9EOwlpc|y zW0OD5^?&>BRPAc%%J0f|pJ+eL@c3S@;qJU^?Va?y^Hzj?{8TRp=jenz=h)$xmFyql}Gys#4c%NmfK%XaEU`sSDG zbe}VQOgddzm0DR`_hqZ|=j>TGUhjTt>haZM)}?S|g{2dFR{LF>Cw$_#QQv##tF0@H z8|JSyyY%sR$GX(%yxO8i^a@W4c^!Tw6qVrD!p{)xGdr>O?os1;_hZtGm35wbWbYG< zKOo+4>#Xv;z4z}lqTnb+D zk@bMT!%JH&{{>rcS z-XnkHo;VzTbxnz{Jx=W|XS~~7Sy}H7vtKX!#e3Z%{eRzMVSQW1KL=*+bTOJ=u{&|e z{7Jt;U8)@4-B#UOP~jT2mfLON0zTop=Q!Q@^N#23EIjpJSIKwTyiLX2v$xLq82;o~ z{=t{-m(~Syq{pwf_AL0Z^W=>d#~tyjCDOO=fA&JgwQuSo%{d9tzTbCVmc7Hg?NqfE zYyIv^t5asF?k)PEC%yY_b!fTMtWVP~|Kv3Ir8+^F-In2ng`(Oo{@-rDR$TXI+{wVe zkc72(%Pc5K1{H6%ox6D(9C)06`yAx>8R4EMJE^U&>2IqgXU@s0ZBO^So0Q9`H?hEH zOVhv9+@*5XhKHRGCmA`O`zkWO`SpWeRUO~ML!UAlg^1jFqi}+t zIX_n~F(p4KRj(qqfB^(->?;Zqle1Gx6p~WYGxKbf-tXS8q>!0ns}yePYv5bpoSKp8 zQB{;0T;&&%T$P<{nWAKG$7NGtRgqhen_7~nP?4LHS8P>bs{}UJDzDfIB&@Hb09I0x zZL1XF8=&BvUzDm~qGzIKpzB(ZS!SeU$E9FXl#*r@+442g6~^eb{9HY4kC_w)^b>j4F0dS-3`SO-WovdWZX zxVnPUq8zZAlw|$XoYdUZypm#lLp?(j4^`wAz%^j?4%l#TKv}uuCzpau@pQ3O0y)4c zB|kYc#R|+cHcv`SN=Y%-HMB@e(=|y>HP*FEGECM@F|tgtFf}$XNJ>dYGRiZrxFj(z zITd77MQ(v!W@d_&v89QriGe|iuBm~Uv93v4Vv25}k%5J7VxqZGqG_sml7*oOk`ewz zndzB%i8;uw0vVN(nPQcgXla^aXoU}~D8Ym#V^qHAevVxgO6Vw9R{mTF{Slwu4v z3KXzbjsc#wN=AAH2$6uC#FDi9qFh_0@XWlF{PJRiR7hrSYH&#+DA){5P0dWqjLi(p zOpS~Uj13Wr!cvQhGxPI6rWzXPnSmuzlC9kGi*gf7Y?U%|6Vp@m3-Z#z5*4`xR?bDK zi6!|(A^G_^wn`vJDH!P)8h|r{f(QU<#}L@kUWRS9E4K1DUL-Y<@rU~{zd*tS*gh-_|3tl7;aKfYIfoY<#nUP@{ zs_Dh~X(i=}MX8SIsd*)~O75At1>ksA(10d0O;q*e8L6N&WMF8iYha>lWD#O$W@TVt zWniWRiERZNeNf2=^Q{f2?C|xqLJkibP}yST2}*Fmr3D2!nW;sPkO8Ng;M78hNjCa8 z)FJ5yC%b%t+L4t(bUWu4R2F5XXO#Gt=i#*;i$aJAKAFj>dBu3`Mpgm|7NiQqjtd%8 zK`w4~TsHdPS`1X9LBax5qtFsVQy(p@P*51Pgrx8t4X)APA}It&QaqZvMuUr_5FknM zXzHR`aB(5J%BguNwo2tn_I77j@@*Ix7}%1$-CY=h7=jp_t!vLJFfcH17I;J!Gca%q zgD@k*tT_@43=Hfgp1!W^k6C2+8Q20#@{<`D7?nI-978NlFP&uQeKI}e?jr_b4#PeGY?vY6cnro;8_tFq}#>e*wXY!q$5~v z{W4GaU(0?!m{)v$=l28l^Do%HtA3`A^guro{%7o;|6}ZInBS??owFMA;?#13^*; zoi{KYD3D2uy2R2lQ*zrKf!WdWn--V!ugj>I*t62_AGE+e?RBKt6y)T wqyv>Y`>#)TyZlv!%lF@Woj>;)H6yOtPpC+*?>d}Z4;roTboFyt=akR{05OS*)&Kwi delta 401 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 delta 361 zcmcbmJ%@RMvH$~HlDE4H!%c>N4FBK%6K9xQCn8sWpPQY>T0i=b+II#9Momu_#}JFt zdnem_GaE{@*B4H_q&YjK;FO95*P`y`FVp0HFy7g9?}@m;Z^ka~?U!8HUnVKWzEaT$ z+VHy3nN4|%^TR#*1z+DT@bvYse*TEN(fh>bC)4fO|Afz#jb&!|#jC~tvg~^8cj+f8 ztx8q_J0t{O)|Z*9|D2bmTXW-g&gLG2(;Ugh2XFWkt==5Ef7D}f+u;?@7Wm=NS#c(5-S^Oa9jo^;Ywa4W2+1G4)d)SGCf#JDKkQYNkP?ycY zeAO0)=Xazh2OW}Vc51v-l%*|MT4tx^ls+wf;L9wn%kU VKFeu5!oa}5;OXk;vd$@?2>@aVqFDd{ diff --git a/src/main/resources/assets/ebwizardry/textures/items/upgrade_melee.png b/src/main/resources/assets/ebwizardry/textures/items/upgrade_melee.png new file mode 100644 index 0000000000000000000000000000000000000000..671c09faa258b9282dff1ed6bc9d6b1d9e52cdab GIT binary patch literal 5965 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/upgrade_range.png b/src/main/resources/assets/ebwizardry/textures/items/upgrade_range.png index b7a21cec78ccef18bf8a917ba03fe019ed5f14a1..1f9f08d9c7408cbaed384af58af3f03e7739a4bb 100644 GIT binary patch literal 5613 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 QBcMSSPgg&ebxsLQ09L7+aR2}S delta 396 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 g+VXT< delta 341 zcmaE<+rd0RS%85p$=lt9A(Wwy!A`mA!qdrJqH^{3IYot)xU;jJ*%=rZMLk^{Lo7}w zCrDg*aPCSa%T7i#URGIskgXEt&$ziyV0xFUBp@kipd0}D!$B$*EyI9xxoX=(Gr_Eg!! z>m!3D@7W6_Rn#OhwkcM`e)w%G&CJZqe0cTwNj&D3Hzf1^9pZ5pD`7mAypJbcWxkPJ z)u|8j|4ubIeDl~}9{nTt3}U9%9XznQR{Ai*n!w^`4}&Y7EU-MC*v&cTKx!yM^ZO+8 yOOuW6RKCAw{O9lQ{u*W#3rooz{~wgAGDOyw?ejiW>cYUlz~JfX=d#Wzp$Pz7p`MTc diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_lightning.png b/src/main/resources/assets/ebwizardry/textures/items/wand_basic_lightning.png deleted file mode 100644 index 7fae895e27b5df0a5b8f7d5eab2d08b371a7009b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^JY`{xdkbG5njt zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||ViV_-kiJy;U@8Lx!w*jv#}JFt$q5St z3?{Aq`0w!X|N3z|&mC~-Qu8;y_@7_S_GkUGLrecpUw<#<#*S2NW^T<{*=o7TJIY@3 z9e&(@U-I9^4TgK33#r^=U}Ixzi)HUO-1GbRL4}1H#|s|56K><(%iE(O`Qgb!=Cd@|eOnFKyBPr>Yi`d@&W=*Ij~E zlrLNT|N4Z-|NM)r7VJD55&Ixh?brOq#>PgG*$*`h6&fDe@4k}F#_p_mX|Almfe-Rb zJO1CkVIc6dM4~}`iFLQDgv9y+0|SE^)stmzY;0_7($Z`@dfodbOmk-ZvZ#dnkd{IQ Q0|Nttr>mdKI;Vst0MCGs&j0`b diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_necromancy.png b/src/main/resources/assets/ebwizardry/textures/items/wand_basic_necromancy.png deleted file mode 100644 index fb7f48b2aa8a284c75f1f739ef3e05959d08f485..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 361 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^JY`{xdkbG5njt zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||ViV_-Fq^(?&jSVqhHsuOjv*GOw@$YA zc1jdER==J_E$>om#s$Oh>DG4-e$D$H{ex3#k^hBj<^=^A!cry~S_P&pT>lg9YPS! z_zC=)H)sCckAnJ@@_HM-^{zhGYI#9mN!i(oIiGg^O-gcSSRr<2%Wjp`mTWU_mwi)i z+o%3Ds`FXyqqN00kEKKj{F)ci$9;!?+PNjWex*JRS@m?$is}#VPwp3b)3wO6%(q8L zrG8S-`l(-T1h)KHq2cJD_GNC&#AR!h&wN(g5V%yjLE(Vvx2j$If7vR(7vJtV`TQLN P0|SGntDnm{r-UW|9w3`O diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic.png b/src/main/resources/assets/ebwizardry/textures/items/wand_novice.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/items/wand_basic.png rename to src/main/resources/assets/ebwizardry/textures/items/wand_novice.png diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_earth.png b/src/main/resources/assets/ebwizardry/textures/items/wand_novice_earth.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/items/wand_basic_earth.png rename to src/main/resources/assets/ebwizardry/textures/items/wand_novice_earth.png diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_fire.png b/src/main/resources/assets/ebwizardry/textures/items/wand_novice_fire.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/items/wand_basic_fire.png rename to src/main/resources/assets/ebwizardry/textures/items/wand_novice_fire.png diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_healing.png b/src/main/resources/assets/ebwizardry/textures/items/wand_novice_healing.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/items/wand_basic_healing.png rename to src/main/resources/assets/ebwizardry/textures/items/wand_novice_healing.png diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_ice.png b/src/main/resources/assets/ebwizardry/textures/items/wand_novice_ice.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/items/wand_basic_ice.png rename to src/main/resources/assets/ebwizardry/textures/items/wand_novice_ice.png diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_novice_lightning.png b/src/main/resources/assets/ebwizardry/textures/items/wand_novice_lightning.png new file mode 100644 index 0000000000000000000000000000000000000000..3da8db4807299c6914ec4c1b925b92f414d3ae78 GIT binary patch literal 502 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RZp^ci-~Fuxbd zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||VwDv%XPT!b;ljYcAe$KyQR1ARo12o-U3d7N?g^-tEQgDABtAq~0V6eF@m0?6#1wCL zq%|#er@b476$Ftw{1fIO8l)AS*K%`w%paZ>B$L$r?1%= z*4&m}7bo+r%iZRwal^7_3WCK?BaB?ste@YVn&ZpR%gIxyz1Xe6=iH~ZR~zPT-=FNW zT*>t5oTJu?j0tz|uKubpx9h|TL527Ymb;5vimrVu;C~t7;^)hA;^4joAz4Yampf-@ zGtLUU#&Bz2!iky*RlnI6e~c3|lh?dCYsHTFS*()s?$-pSEbE-~)oPD~{`12f$@UKd zHkn?OeRH7f-j%w=nU6HZ_^n(P?EdT?v;U!V4`X-rq>o#5LBa3o>gTe~DWM4fFyY37 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_novice_necromancy.png b/src/main/resources/assets/ebwizardry/textures/items/wand_novice_necromancy.png new file mode 100644 index 0000000000000000000000000000000000000000..f13ac75ff8583c0277508940096ea8b866cbcf5b GIT binary patch literal 496 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7*pj^6T^RZp^ci-~Fuxbd zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||VwDv%l~gO;ti`~ZX`i#W z4&7szI6>FkoNqBiTwPUmw-CesAJ zR0BC_js=O!7HfP)Y=R5ZPtNIAN~bL0H`uaq&tumZUnbjI)6{JA u%){0%{w7^IS26kFA>BFiX3CfSZR5XmVuJ96Kgaig0^ZZr&t;ucLK6Ua0>$V6 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/items/wand_basic_sorcery.png b/src/main/resources/assets/ebwizardry/textures/items/wand_novice_sorcery.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/items/wand_basic_sorcery.png rename to src/main/resources/assets/ebwizardry/textures/items/wand_novice_sorcery.png diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_0_0.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_0_0.png new file mode 100644 index 0000000000000000000000000000000000000000..78375f2e66fe466a5ceea3018d32c9b45729d830 GIT binary patch literal 1695 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-m8(J`N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kDR8h&G#o=bT3Pb#Pq{Uitq7N{gmbLtkSr@Dtf)JwPLE` z5)Q>ntNwqN5Bz^Hl}9o)w!^M+ec{cN$tNXT_O81+dE4iG@?T6VCawP5+}LsPbJdsH z*Xbwj+A7}A)jwY(`f8i-_JyZEnVm>ZZ9aId`?kPr)#ZQJT$(rit+U1N(}}YzPOU$0 z#?bRjA!V^odQ$Ih`PBwC4~|II9+_*wqq@cL+m6S-q^wKZ^dHQ<$X#ZYZ)xwmaLawJ zf2@mj)xVpT2`?1Cwr=YDx(;9VzZJF#>X#OI#9vH(-8d!OdWH5B%cdm8DcrpMVjoH+ z+HVR)xpaswFy9b)VbvlRwhZpbtSO!=&hHCq?Y>sRyrb9f>W3+=2j=_CU2@~1hYy3T zZ=>vC(KUugp8aqtzH4%QwaCUISj)CC`dLi ze|LdNQAIk~{Nr3-+b6ws3eyfQm~G(BGNUw7t!uIM_KHtuE)?I=+IwlP(`_~e!E0p& zZ4x{g{%=l9<~zos^g!aEf7|o6wVDYHbBueZG)SlM7cG*^PWD@{GJ8&B(iAa)hZ|g( zRvctwio9m^#D9aJMUoH-1aOi*^0j{RbI zL?ZaiNfkHF;*-l41o>z_?Qu2sNk4P$!ik+T4jmN>ui;dk7Ea^7t#urDMx0r6*n8t4{I56>;X zW1O<@@}B)WF}vv7`U>OuGlH9U{bw)E3fMlg`uSV#YfB-E<5)(1|s5ZNU z|JBD=l8wC&EtZ7E-wz4cHqV7?lbUzD(nbrrU2F3zFNbB>gc(P+^FPkmeRh@2@z%-< zWu3q8|6Xx#?w`5+ukN1Iuep-XvG?bi9-iPQMXxjhjH`N?6?`O|+<%pXtopg+{;vtu zvp1`1&t^%}=RWEy`etJpcXsTpnR3^JyiPaYS|~kt*OSI=rvhaoIk(SdO%Rt@bebz> z$EF_@$JfLq-uvQVTqeUly>;6}W*hTkclDnxW34P%lIpp7T0x8H+Mm<1cZwPBj9u|d zI<&QRPlBwp^C$O+?qcaMrGwoE84FHN<*jM4)LoJ7@h{>->e>{Km_1AG-TQIeGWKR* zzh21C7X3E85N7U*pHl)E^8ErmE@@o7A29Q)^RtqavwDmFF>1cs^RZtv)N!@_8~t*h zYqu|Mkad+5%I?n#veuu)_*wq1e)zWp>rT7Eyw#T1IDUN(^3-3l>-oIA6<%lbZ}0nQ zyL*1?&Sm>}Jaxl1xWD&#?VY!Hhw%06`@gR-H80YNWBtazGT-N2)CBW0nqK=DH-v|a0EpVD*LnRggDguHZDSZnN9`@AagbkFqDvkSLdG8=zf zYPM3nY~QD!?Ru;8YyT}g{c7|1`(N*D-nS_@qIBo=?f+D2cTM*{y*lUU{2f~QXN4x- zdo42aq{Ob`)uS zn6KLFshFWCSk5i)ARs93bg3iEuDNS#Lbj%6EraeGof<}EGqYLe4yhe<>X^#X<90o% ztm{b0&C7RYo|gT0STgU@%MyoK%NE>z+oW^aVV~}o^=uE;-e;FC{+w`Z$|{$jl1tvN zm7lD5J>MZOB>TaiuS-?f|2{OY`0 z-9P18UpfBh;KdiSUmE|op6TjT{Ybwj`xno#?H`xzWZ%Z8ua=kolJ6fwmXgo+?&UXX R7#J8BJYD@<);T3K0RWF+C~^P* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_0_1.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_0_1.png new file mode 100644 index 0000000000000000000000000000000000000000..6b3bdae284bcf73600f7d2b23a228b578043bea8 GIT binary patch literal 1719 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-O{+p8N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}&#qF|(pop2=s{+|JC1 z>{#U0(f8{AKcTPucGsfT&gqv4;*gS`9!J*SA>e$@?8NVHF_7D7?*gf}~`%buW`S&Ap&)xQuUm0MP z)BfSe#ck66Ez2h_RKL1zrv0A@O?|&Uem*eQBYEP!u<5Z3!H#cTW4&kET8IUB7DrrA zPHDK(Qx?N1p4=(A#C%0$L1^lvjS0~`#%EKMm!01>i>u>Y8TYPGvO4zU`2BrS9`{Ny|4Z`*7S_K@W^O#N<}_E}o}It<} zHG{^XJ8}s;j*PNAmBKxJ*W8j1C_B&Rc`|K|Zoq+x{Mms_xgAVL60M&dn~||>{nxUY zfl&%A$Hh7)ut{?ySw5d=f6=f=qxzFy<@@ITd9|M`0}2kd3nWRHYPomm{gO!PkqJKI z^X5kJgA->ui#K%!9ID~cTy;cq=^VpMw--GZCFLx|qgU*Bz*9ARiGS(U>jBA6 zXJzGW3q1TSf1&Hu9ZRR}e(ACF-LCfwkDs&ss&m3rvG9?qhsZRQpDVV7{#`MvGU(mj zthCi;BE^^W@2xs0^H}syPtl|Hw16{K%ts#wFmUF!r_JguF4HhKxqLDyxPtp?kNhJO zW0B^jb<(eo%Dl~cdhgY;J-;XBeJek;Qt|Hpg>$4X<_PqbF6C$+;8xuDKb)WVbA%Miyh8h&6Z&(yd+?KY5C%y zv+92@9lLW|MmKV&3P-i8M%}K2{;jtoUVl3GEK$!eQ*njtzBgA>`_p#IT%S0#;jRqF z?h^vB*ABI6c|NE<`)cMh-F}nT#|jHvGiF;}C@#KpxF|1bg8T8PX7!Kv(tWnMr)IOR3N#6 z(Z$*>6$-spPnSkL?Be>ExB92>rg@nq@s}4HHO7|KY~TC+_}kwnr4n?*jS|Z_<3f&2 zma00Ic|PX-5$`HhXZ|afJ!LfK%wOfeoxR~v-T4;ro2HWmUwzeClvkX1@MGbm!u4l1 zR_s`n`|dW+)TNgS{cDShr?>BU>8Dd+zJHBhtmnP=tAgLIvl3<9eYDx<&^>k0(5`nX zp30sL8rGcKjZYRGn>Oi;d0*8>@0RapqZ9XY=y4T&uzq;gTyeF&VZHFCUqYXipO~+` zb$HXhGSMm1t-ZgQylHv2cJg|g_1}-I`Zl+6YSm6-{iE9QbHtXdS6q2tR@lCEMV!Gu zMVGIpz3h`le^jo^*mEgVaem}393m?3> z#Y^|!+U)Il%iG*#HhrD_KI&EVnwnm3-Guu7*XpYT<6I~I;^z_f*!5?hK|ccn16z`} zy9+}lLlnc*H|M|RFfcH17I;J!Gca%qgD@k*tT_@43=Hfgp1!W^k2wTI1(X=)bsAj;KYUTw44Nj!Qo< zY+7`2!(6A$(yb|>MxCjWN9W#5`MdH==DV{ecmAyVyxTHx_g%I^nP$J`%#&0YZ_c`4 z|F&_t32S%qh5Bpi%$2t4 z^Upq0UaQz#_g(Uhj)~W~1uJs&|Nq~)XXB*VGAxrbvVWZYZ~Wt8CLhPaCmX&l&$X1S pxqqztFYkt3m49BBP0Rbhs?OoZdUxVkQw9bG22WQ%mvv4FO#qc1IQ9Sl literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_0_2.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_0_2.png new file mode 100644 index 0000000000000000000000000000000000000000..7bb1ee5384b38ff40e4f66b4273cb79cc794ec89 GIT binary patch literal 1741 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-J*q+?N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}&)oDyjpxt$;3pgn5&egkt-7Od+<&vg`OkZF<5OoCMu<6; zcpEwYoxi{J-=X6YxhHlB)P9P4m^|56Em`2|uQhSn*6V+}#WwR7S@H9@^vt`y_I{G+{oZH@3KwQf%Azn zY2F!v(Q6p?HlA$?^Hk4m*p{(+_PMB%`L$O?^`b8GJ}^5LayVFwvEHb3Qj+`SB&HXc zEM+|58`$h_$i#n%F+cltRbRx;%nT{s0UGQQ0G;D5_d#mFf+cQqP;|7M-gUk108sdj4M3^S%6aS60Ya+<4H$uXtpFQ=d$3$;IOW z$v%ealO~;s;ZC8q}%Pzcn<>tlrKe?Uzr+)8D_?e3f-u+MLV=JA#v;3Z2;@YP_-5z>gIB}?PWs+l}aQ>#w zAB*JH&)c}sP)2{{)$8U{Urq0GIr}K$qVq$IZTosWg2S?G)HZM9i$7NVHt4O?27zO( zl?7#;zvV4G`1$|eaIC8MQS#yJquqzy+B7feE$_QzqN_dSpTTqv*~ZI(i=WM{dhPr! zw`Xq3Y?iQ>n*#2HIF^}~p1HPb%jUXB?~+;0;npRO#U@W%@cqY%zKWLHXSpUNH!H4M z)5{$$CO^M=ne@4{y(Y=WyB}=2U{=)d{Me5CzFE7jEmG9=j+)x?*wHt8-_t0*HI?s8 zO6&9Q`zTsE-tv6-+cEl^Ha3;)ZO%KLD^mXL>znHMsFsx+DRbDr zHRqb{7g@I_(N9paYRR{*w|3q9Yd58oZC$BxQTNVe!kb(Qd(h-T=|JD zd|W@m)`@RBW0838%&xPNGdj0VxyM=m=@Y&zi+;H~R{?Pg*XKx+R z_*As}=bDy>M;1_F6?LW_UTU^-}yr4+` zvP^B7{D=1o^1?iy+-GpRuk?fEL)XV!JC606cGda(TD7g5_08;GQ|127x-Y+H@q4cq z^&k7{DmLz)@8Y-Mv3|_%!!!LD*!G0KzW!Y7kNh7omS0yJAB)#rR5tu~W4(T4^1*|~ z4|jah?^^GuF;(W&B?bltwj^(N7lulPD2AzT&VS8eU|`@Z@Q5sCVBi)8VMc~ob0ioT z7}!fZeO=ifa|ntGC^63Kn#sVx$mZ$d7-DgH?PYs?=Rk?$AJ0#Xy5)FCL3D3(q>57S zN$m-Ghf+Rp{h6(LuQ@M{fqC-5G-a{Ld2HVKJd>gdgqL0^cqi)>Q8oYR$&)|l{@Hh4 z|9R)Fw`MD@W+`}1D!AAA+sSppoRWjdvzmV0u#hlJnfl0r&C+vu7%$6A<6i~eX1ZO_ z2tV-faIGUt=6mKld-gW$&U^9M`{2z~g~%Fy{=WS64pzeAE&-aod?^OjwqJuUxBqhU z_?z_Js_E0`Y)6)zpTkRqeAY}mbT)0-jal5aYgw!2s&CkTL8DFKm+1$uY5y{x-O1t2 zSbW#z08{(o>^%C33-?TWe$eABk~vu!iJKl2dhKE{}<-jaeGmwz%aFfe$! L`njxgN@xNAi)1|B literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_0_3.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_0_3.png new file mode 100644 index 0000000000000000000000000000000000000000..97cabc9b3dca1bd6867d6f5cd8cf3e60885352c2 GIT binary patch literal 1769 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-Gpa%&N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}k1V@m!Sm<2<}(hKgI_J~e2B|4I6nW8(#Eyhgw-W4PSfCE zYSdx~S^e)lf8hTI2FEf|V>|3B*B9PMnS64F%ig|H)!gTm_g`dxa$NV0olWW3)az^C zN83BUJI8%6ukxox_`*EvLg`&P`OP+AW;1g3?%>@RS#;~W*4yu!YB|&Y7tc`3d-{AY zFT-L>j++{nXGT1Jb6ksu-=grC=_4PRHlbrPs^`qS`~1er>R$}+=h<$!TzUGZvWVC3 zwGZSaaxHhB-#DAYHez?!zYhwPvR__*Y?|xQtyJqeeJy)X+}j1~0-o`7u?BpqIr}>C zQuC{h*Akq{N=LXZNZ-(r2n|$X-qNaLdP?QW^Q}Rx-PcN(cTC)Q^}`g`1M_|6F1cao z;lp6-+bDZjbdBMWXWv?%?aEviu9@`I?SctQvPoqP&)1nB{Ey{&q%6^!*k>O0;dBp6 zi*)nO!ZtAu#hWvBb-tH*rJDbRdm|6q-4;uw18Ytj1a-|tu zB5og)OfpztyHVNSNrRVSce2?9}Duhoar{G|_K$3@|d!N~^ z7s(xl%VtdW>=Ao5$=`A5jG$AJ-Dxw$K;6hbAuwY-J8U+jLCr zUW)L?_PRamdJY^b$q9NLbw6ZPyp>Sr(T!pJt{=G zZ}z>3%ij6_NaLC+JY}wk9sjLM?>ehG`&Z(&vpIC~)M<|nF4f=J`)F0A%I;lPZ?&3cmV{O(=Zc5@W7U4Q zN3ugyHnHof_|vChY$<+URT$zq8y@!ETsD1SkK5tD7SY@5IzK&%xZxI)VEFA>VQ2B0 zS1B=c2?v{)xJML3-`lZy-{FT3C{C08a?%N=*|4sVFboU#lrrg?bY_iCfHIH6zxt+|a zYPfbwA8%Lx#9h77M|<=iPu`UGy!)Zp{;ciqd1J-g&Y#;K^wlNz`UgG!3T>&=UEdj zE@>)Yl#pTSTy@06f@PUB3#UYaFh{FWT6hlgs_H9q=AZn2&fM~1f&oLJOtXovbKQg! z$t*9QrnC4*vRzAyN;uUL=sjsc$ON0?ZyhFRD>tovzu-=$$-$qGolRK+&HgZLm(PE& zPfTie`dWtz+$^o)>h9)(Dczo~awgfARr#lhKbtz`dy)RHpS@MGCUN(*l{BW*-zrWh zvo=q(4Zjz`S^1rhXL{U$k6FtX#Y^b-Z2RQ=@!Ps4jiwhHZ0vWk|1bNMT(WonakcLW rHPY+-%MU#J=bCBVJ$L1t2jVlh-1uw09Z6+iU|{fc^>bP0l+XkKmzPj$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_0_4.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_0_4.png new file mode 100644 index 0000000000000000000000000000000000000000..c24c08d41fa697a16a548b3dd8c1dd7b3431997a GIT binary patch literal 1748 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-<(nPDvY- zT0&G$hW))Czv$n=<57>NJQk?^6!-Y?ByY21!LJ`J(-z;|vrf8JZ{LZl{|-C3%y_xu zYwgSQ6F+YW+?h0eeUa#^O~TU`UjAg{@i?XX=%wz{0ymxWuI=^8jxXC@aIOE4$;PSk zzw0sd921xnx^1#z?`rww0yYa=B#Vz+4Uq7XNPb(W`sn+Om3wO%wuke-DTyok#npPL zPV)!5n|Iz1+cM#W?Agyx#{cVB)V!}g??&eqjZ6J6Hhp$DwOaIwtqRNW@3swXZT5dM~BQQpEn}L)qFCRh2NgcO@CkeVX^yDhl8wqb}a(VT$Vv46BqX@ z9-EQmXC@dWp+3LK%W&xwW4^Nnb2nN$D?d--77gF=L&!^K<&&;2E7ui$HN6rMeD8w=*-Ymx?XY|I`R))tp9TBNfVHyh7=lMy7gMpEvHiLnH8^E&C% zNoM8Z#qyQGZ~k?d|CTMz3iw`cu$-;5duRB)dmFBOs#$bFB_rhFfsn}yHg;~m=~i>G zzkjB{jflSXD~8v_r@rEs?QCoDT-|;sEa$I*lCSm3!r5nz8SZO&erx3|-h{vi@kIx3 zYQD2C3b3{Lv$6Tr!-tm-ig&N)i4HwsLNZ{T>N#|MyW)_&%J+E`LFH80ZX?O z9-h=IxQAnoShnqxn|JyICqJ8%?XKJtEyH6o>-AczAVE2E^%dQ%%`b|M=!AII)JSiu z>dtwszUgCMPW%~@TI*%gHA8l0aYjd7F5I>_%4|j@>&#vIm9}#WUYR9g!yvaXw(D)c zo0DHQ9nAR2az)DV;=E6DE^OZD#;UgeNzN>4_tU2lF zZGGc;&m_AqF(T`tZ(X_7C*q=C`dt33Y{XCLuq&CVIcr`p_ltzazj)OA$7f~Soy#X} z+2Ye~7YW^MwYn}F75hu|)Y*+2dI}Ua=6$Z{C|(o3?%~>R9P6rIWhyJGK4Z5yyZ)|i zjOlvugwT+w&(>R9Te!4c>*cKtU#jf)i->b^`iAGrW8S{XonK{G z^=(q$^hr_oWY^W5_|{$i>fOEj72mrq?hd;W7iSlCU)<(Lg#4P`y>+IKuf4O4vgh@x zsXTad^Dn&y`>);~w|-y$=hvB851tC=YrL}Wv$T)4mp+ruz`($kS{;Y;^12s1*CkE zl9NTRcgzfUYjJj``g8Ad<^R9WTXFq$qeY+NtYr)D`L;Q^OqloWVC}TVrzbTH(vEa| za(?&3Ft6#F+uk*@hu(VHH+^p3oh5T+(?RPURn?5Ppz^%XX= Rk_-$C44$rjF6*2UngI7nLVW-L literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_0_5.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_0_5.png new file mode 100644 index 0000000000000000000000000000000000000000..47c0b845c1aa007f99709062da4610b240b99b98 GIT binary patch literal 1680 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_1_1.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_1_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d7c637d10b4bda608fbd93015172ab8d0430dd74 GIT binary patch literal 1737 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-9jihjN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}k1l$n!Sgp=bTdl}!@;78u)DHnK0W_n@UEnM((EfUx(;SV zdOY_y6!`YOeeB=n(+`5Kd49N9-Fw^rUOB|0RG*Sp`} zR@Zdru71bePk#c}Ey=M?l-{M2-)vK67Ll`e1MkMjqFd*+-hH1`%aQ(nqmQur&!0EB z4y@pFGCO6Wc5TP+jogQs`{o$1-|0-%NbK2qe6Ho5<9>6W3Rk3mZJFyAeNKL1z^#1N z|1B4%O|I_0>++&=YxZ+~dzXugZ-=Oi4vSK*%VN-BMt#9CGtizyuq zQX&E;HeFM!Kf?ATpy`ChlYtrlmusCt}BlZ$6#Gq2tc1;rML zAd`s~55;^54B;_6Hf2L*)616a!X`nd)QY#=Or5XVE>o=KF+ZtWd!GlV>a-Bwr(K`c z@9SE%@YpOV(crM_cgwEVPM52C^K!$s$iF9~Yz@DgW^ajA z-8@^MJ4P*Ii?F!`bMi4EiRlL!gl_SiD^bWkn~+zqY_VgY1@pBNyhU2P#||vWO^I24 z`0m*|)Awkm*B_bvv&YhO#c%r=!OgqQ-qFs_k64{KPs4^&D%8T@>Ya->7F=*LQtUO( zJZtN2KRvXZZ@NkO>l0Ro{g!K9j>*`2tNV~&=&6khDqlTet31g+&AIB%?KSIz`w8!Is}C}U{Qmg4 z^4+30Mz=0bu{xQ0u%+w9N!Kh*9*Kfa3qqn}y=z_W=^tISWlG(XsduaF?e@rjauK=7 z`a>_#xv^)f$&$3!y;o{vdi z03Z8-H_xF}t6?S96ZgLGf(y;_Hv6P4B9*4vG|$D%|O9KD{;Y zU0m^F>+g@Irfp}eIcjU#@qFf0Ki$c)(}OoZK60~9?46x_<=x*4oePT9uT8t8HL+#! z!#vsWN!%+gmbVMvYKl`#gH(cdm%5`Lne9 zRd-Hp;l{YB(jB{h-?^a9DptOKUEAxq9gSrSDgX9| z+41W9>IXVkw&f|CHyzSn^8R)At@ZCMqWB_yTmOuEES|vW`u3J5pDY6d1B0ilpUXO@ GgeCy+GdXks literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_1_2.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_1_2.png new file mode 100644 index 0000000000000000000000000000000000000000..55be8e7a0812a0e6d1615062d4bfca1d9e00d748 GIT binary patch literal 1729 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_1_4.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_1_4.png new file mode 100644 index 0000000000000000000000000000000000000000..45f97bedb78e681fb0eaec290fecb9f79d00bdc7 GIT binary patch literal 1762 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-Q>#KEN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}%ii=_hwsmMtu#&!MV8YKBTcPmJoQgDICrx0?#}y1L}zO_ zb-bIl;pP9I-wpmBI&S&tSog6BP8)vwcry94gv)Nb*PhqnzyCdaubIEB_+Np6;k-R{ zZTtQjzxm`7u>bAT#dkCA7Cz!Dalgk{x$cd@jk-eir0s9E)X(1XJoW#kxqnmlI>|i$ zem{=UO<3Zlfx~{JZAjJZ_Q=S>oV+jW?sI2W2SKp^ZTBA8#Y(o{;4c- ztnID9J%d|ilh$wCEl`#GHty$P`ND{;>*tHVIhIk_v#)G=Ekn@3H@2dt{5q$}u_<~Jd)c+0 zJYB{x@mNaUy@#w$896>r4}ITtraSKq_eLJJr%jeg%{QlsF5_K-;I$jo}w48o;UMi zltaq`7m+Iq8XTs5XZpLM|3ZM6SiXx&hu0Jp%YqM%P8?Ec{ija73N=}gb!CZV(U-ua z4yj}xL-pwrx;{Z3SwTLUPkUUAozl;o`*33CjzdSqH5X=ds!okjod0U|m4L0sW@Y8A zD|G(3{lb+kH-b*jwOVqecDmfIZ#RO^Ge=3={Fxxw)@O0)MElmWuiUS_=-oL#a`D+) zDQDvAer;ge{7SYd&3fWVNr~cl2X^?eDP)*iZl1WOeDcndGky7775Uao^eK|^J$7Kh z`zI+E9==O_=YFr}$Nx_A@3O^dLErx;ob!2QRy@D*chlBs>xEnOo6T2G{M>dc z#on{;ix;=;_qebp^~ZJ2S=)K+RUo@Q|p#zE8H^8*023L z>plN{o3nBmC$;aKnBu0Rz9_!ts>PB2E^9Qm{RM@ax$e;{H^3 zF+S_D)Z5vI`l5F(_kQO1lHt}9Hj}eo&Q7h*yUrK*#q!?nut}|xmOMO^%e$$dkKxOL zcvroilqJ*LE`D||&fY2~v`t&yvwF|1-mJxfzP20MY7W2ZpK?oikNBD&+`UrU-EMAo z_Ue@uE!n8}l;y(H3!Sf;}DyY@;{{?{lxc1`$u zLD@EK+r1?Vg8gnpRNKtH$?5X{lEMY?@`>&`g;NgZzR}>dGqqjiy*WeO?r-5S?%U>F zRWYB~0(ZP(E{i-Q;hFKoUD{SJS99+vkKnssrM9-Zd#s(QD)Hj8=K6cb^=`b_`a5`r zXk{DM#*2Z(EZO;^7^CS?y}jB zm-+Wx%Rh6m;PIh5J{NxL-v4x2@WV>SXBFNHL$*wezkc7i@K53NUvpi~Ox$(%=QKXo z@Za5RcD84g`KlLpO+9{-f$ziC2KWA&Pd8Ug?^`!F?boy9mwUtKJ=H(IQGedE>CEZj z0oyHB{MpVP>aV@n<_7=w+j({8&fT!L=c_++ZqKss{+o>Jr<`4XQ%vLc*>6A3EZSmPzp$Z%O`qH~NJ9l@smDBRl_o-gCz5&FwvI-V^@UGcIFsUMnlru#ka) zfi20~-G!l&A&Oz@oAY0D7#J8h3p^r=85p>QL70(Y)*J~21_t&LPhVH|#~gy90_ufd z>ckir82)*>IEGl9UVGWli#br>*vI=`4wE`uU5+Gezv}gcp^Ee9G2@P{H!2xfwfPq$ zEbNVlIPP|drFwSk76HL48Z1X6-b5EF-$+?r`8lo4{QplmVa{unbxg)*)jF;p@4mvY z>90wXMW5re)Pyq~Vb*(gvtI6S*9t=#e#$l;&aLrZt|EqcE4B?W50{7Ug@pku6O_WL;M5IM68I( lx$nAVVs=SY$Xl~I=4XBmk@cC8X$%Yu44$rjF6*2UngDWlTT1`{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_1_5.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_1_5.png new file mode 100644 index 0000000000000000000000000000000000000000..00758eeaf01429aa51b17e061ce8ea9d5090d822 GIT binary patch literal 1671 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-#j8RhN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kKXoJgXd4W=w=obf&Ql-Y?hZBoSx5=JZHz`FK5pjc`l{H z9T>v-aP_VG`*;1~woiLIMN~ef#P4zX;@&wIIDh?+)y=ei|Jrf>T=m_z^d;1qugUbU z)BVq~JBE2r?6*HT;rrHDB(hp5uWv{@bLNH4{tZl$c5k-K3ypa^sW#%=FXOtl8|S{K zzjkyJmEhIRYwJ07w>OeUU`B?}tp;mJ`#A-@`wrioWqxPn-MtgHSDU{pi7NZ-(|Re- za)-40X}?dicAvc9yS4b)a`A)N>*eeD?|hAOe*ZQib`zhEM2p8Ao$PIkrjiMw2^a@I9;yE8Ez z3&^|kkkxU8zF+DmYyGbi%zrsXFtes!lG$)z$!9?&?%18F%g(XYEn0iYeb?mm+6)?p z?l2joENCc8X_3i1|EBXma)TY`iJKAU0vcR)OnP_u!lTmzl02ub zUU}o+)zI}>D>g23<6U_rXY#XI`3sLuvnpCUJ8yT%^;&-0Z(Bm6SJ|z0Gk;j4Crbl%e4K2?W&g4tc<$v0iW@Tj7Y7n9<`6xuH%hB<6 z$I{E!-UYo|oagl>eAh?or&lJt`yb%P`*K>*{@34}w$6IinY7FyS)9*r>r0KCf(*q% zkHZ9(D-P?9=UB|Y~>)y9rYGK#USlwk@o}9tdD?Vil zlT@>D+2hBpFBo2&?*CZ1yTYCK)swF$1>3#CJe0PIq?Ek9F>9?{>|Wn1D*(#}shx1NUjhiQKeVAC;;-%)ZY zt6b}<_D8uLM*2ll+}#&)-Q4A>nYgiu>6+^PRDC^Ht=X@>zcb&u{?9sr%}2ZsSlpeQ z`|$C)bGjR6Ipp^LyD+i&mRh95$6t6ILt zUsySR($7D&hsr01@0Ts#Vwdz`{XOT6>oRMPR&e|9-*-)SIBI`ax&FY?xca8res5df zOTT~oxb#XsOwDPg%wLmt3=9lxN#5=*43!K~3{&5n|C+Ac<7zn&cML%(bL5-#NzbY%NxCz9R-ekyzeUZd?~;$KIeHn2N-F|6x;E~xF7V%Q(r>G=we|ga z`x!2x&C}C2?3(JgD(F!-4?p*W)X16q?Fq-GT(sJ?pP75^y0#*RPg8WmG?o_4dp?n) z>xuN7J2B07f2HYuNie8m_I{~T@&8wk%Y{nWsmsfDhly2O(D%Gn{_Mc<$ILIDWvVpo zeJZ-4zI0)b&eZLPkNxZwlbGA*7${Q6F)1yvXn~sGgfFYupC|tRBKK$I7wMmG|1&=l rzEZy?cHQ>(MmKeAt*rZY_u7X&wq<-09d?<4fq}u()z4*}Q$iB}2zVnO literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_1_6.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_1_6.png new file mode 100644 index 0000000000000000000000000000000000000000..86f65667db928fdfbe92b07ef7ca1f687381cf49 GIT binary patch literal 1671 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-#j8RhN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}&)xJ`gXhnA&2JnWigta6)34r1=-~%WZvs$AoRmmIczsvCNXat!>`4f!6Mdr zuZ}s-TeYC?A=6cfw9OkY%rQUrlZ*9C4ClNyfu3c3+r9T1{X4sr`Kw*fbdUD4q6IT2 zHZ&MckuI-r6nNDgJoC>vZ`&umbpq2CF7TPfEH%|%csk_Wn8m~DaU>*2_LhNlhwzyh(#bZy@ygE(7H@Ij zI4JgU0-H2PQl$0?`F!Rg4bJXRrAJ4+Cup49xY=(`@x5NDsW#QGk6OR4{cv&lfrD(E zdOrl5cr<67&`1=D{i4+-k?b|YM6u-13zq&Vn@-Njo%UwadBx*%xGpWfp>$L<-l%cC1tuKXtVFE?0v0b(XUQyJ$JY4<+|T;Rc|s^Zwsjn>&-h=8`e85 z%h}NS@1LboXYS2c%$Oo9Im^*7nX~KnLI$B*JZDQ3vd;$OWh`5KaG3z}RgX4{sclIC z7tD+f+VgPwqUtF)RL; zS-4nfPe1=->9c)5o=wi*DeM3E^21>6z8XK{wl6Ll+xIBna(*hb>&D(?A7+2Eojkj8 zN|d8pyvXz9uPtZpr?izUOLEiNCO&idG?DJzK|5P)ZRQ_VZM;}<%XjMJ3p*aJ4tXxL z@qVyH_*+lDX)0xp{Z>zIe$L=ze%4h?SL@o1&GzwkqE|gD$k9vsc{|EKO#5p9n~rJx zj*?4Rxl0~~;Z{4GMyC z!nF&e*nb@o-r{tIdwV05&nK*#Pu!vlJ>AJYk$AUc!81qUFG@%OXKRBYWuxy zeJ}m~@#E4f`+!`hS+BKUD=;uHuqAoByD(HTL@`W#bN*`%0|NtRfk$L90|U1(2s1Lw znj^u$z`$PO>Fdh=m_txhKy#W;upk2i!$(gS#}JFtYcFrqV+j;td+`30*>3GF(blA8 zOQ&Yovd%rl+!0k0*WmJ$(L=;!QNVh)Z6BFt%?#-9*q|bvBx)?2rZQ`9eet`W=l6d9 z^L@XiW9Pxo!V&jggkIUv!}#ehkBTSLCmZ%)HJ8^P-ie(l-E}tV$6On=&!?^__+Iwl z+Vp|7Z~giM-~88pNLU(RB(b-t^`1$^?>`+&7JN3+346P3Q?l$|r8RkH8@{(!U+}G- zDDp-}ukr5b&r$BPzsApq&2D^nk|QNj%-u0V=&`M@Dl6Y9=Jczopr0N=GJoB#j- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_1_7.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_1_7.png new file mode 100644 index 0000000000000000000000000000000000000000..83d962c69bca660ee5c7a6d7f3346d4b4a564b47 GIT binary patch literal 1667 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-#j8RhN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}&)xJ`gXhnA&2JnWigta6)34r1=-~%WZvs$AoRmmIczsvCNXat!>`4f!6Mdr zuZ}s-TeYC?A=6cfw9OkY%rQUrlZ*9C4ClNyfu3c3+r9T1{X4sr`Kw*fbdUD4q6IT2 zHZ&MckuI-r6nNDgJoC>vZ`&umbpq2CF7TPfEH%|%csk_Wn8m~DaU>*2_LhNlhwzyh(#bZy@ygE(7H@Ij zI4JgU0-H2PQl$0?`F!Rg4bJXRrAJ4+Cup49xY=(`@x5NDsW#QGk6OR4{cv&lfrD(E zdOrl5cr<67&`1=D{i4+-k?b|YM6u-13zq&Vn@-Njo%UwadBx*%xGpWfp>$L<-l%cC1tuKXtVFE?0v0b(XUQyJ$JY4<+|T;Rc|s^Zwsjn>&-h=8`e85 z%h}NS@1LboXYS2c%$Oo9Im^*7nX~KnLI$B*JZDQ3vd;$OWh`5KaG3z}RgX4{sclIC z7tD+f+VgPwqUtF)RL; zS-4nfPe1=->9c)5o=wi*DeM3E^21>6z8XK{wl6Ll+xIBna(*hb>&D(?A7+2Eojkj8 zN|d8pyvXz9uPtZpr?izUOLEiNCO&idG?DJzK|5P)ZRQ_VZM;}<%XjMJ3p*aJ4tXxL z@qVyH_*+lDX)0xp{Z>zIe$L=ze%4h?SL@o1&GzwkqE|gD$k9vsc{|EKO#5p9n~rJx zj*?4Rxl0~~;Z{4GMyC z!nF&e*nb@o-r{tIdwV05&nK*#Pu!vlJ>AJYk$AUc!81qUFG@%OXKRBYWuxy zeJ}m~@#E4f`+!`hS+BKUD=;uHuqAoByD(HTL@`W#bN*`%0|NtRfk$L90|U1(2s1Lw znj^u$z`$PO>Fdh=m_txhKy#W;upk2i!&^@m#}JFtYcFrqb8!@5dytyCw(bh-z zriCr~DpI1wuaI@Il2K?XyF%cF4yV0R7b_Ug?p-J_F~QS}<>=n--McTo`Ez!r@$)l( z{{NXQ9I~UTilsZdGf<?yJMR=Y=9I3(wy-j5--t`e4aD`+e-r)^i*G{QA%RNc+Y9 qjqi)_BN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}i=OmagXeF$=w_Cd3cdE}tKRXY{VcAy;b-kxo_Br5k%UN& z!akKXzxLO={B1rhVRUMjK<%fv$D2;7O*ZVPie0Uq`@GivMe+yNb?3y{l-$n0zW9CZ ze8uwXEeYHA)J$C+uzl_hUfF5e9p$v8dA7yfX}h6g`8Iv(w>>%X+cy7~S=Jf+^Is10 zfebz;vr{E%*LM8g$aR?6Z_Y*cJDrCEoTQWccc*@qvM%Mze=v8kbeUDYWqqqt=6=yX zyo+_!zf0}zywJNf`Ki8s(sf7sIQ|=*TQn|Rf4AwY!>QGKS0-y0vm9m8sPy}s!C2p3 zI74@#YtBZdFKlMqQK3^#FytzF_Zo42y&1l$;Nq-2hV6#Sq~>kn_%V6qWD#qrPR<3( zH8&*hXfl=SnX~UgjQQEGTCQvEaLj5;=uzw6zATQj{<5F5l5$CBiOt5Q_%s*ZI}&Gl zt+zOEoIG~Lw5a^gK{MTzvSNh=IeonQmSOcsH|KUhLUwsD9y!={X%kFYb;4kBJOf z6C4yyN45XpG*fEZl$<`b_}uOXi@f!!zg@F_U;AOP+tULF*~Du&6x&3Ko@6ZUwri6} z?y{VDL?cn}r$|Vb=F&MEGumGE+?15E6c65U<58FX!XuNs)^W_wTD^K-n^g9yoimT| zzPw+ujRM>c4f1|wU(n@!upPjR8FdA&%U~T&BflG?;{tVy_Imr zZ*RdywnC0}PN}Cyc+VY}v61E2;RFW8T()$pNn6tl%q=dTRM4EmnEiy!vX?D6;X;{_ z--{>jlHNt%o3gq7=}^4hGfgL#{xIa5a(d0F;+Pri zx$Qgt@9lqe^W^=XE9T9udAPXF>BY(P)RY-Y(}Ud`XYIaj!EmTWv82V{ed#R!Un}`{ zZnuoyw8=B!+lGKUA&z}py(3;Ze*W0ePJ~LY`^H|^G2OBP!6*W9RwBz^EJ6ja`{4ygitx}zHXx6ow(_3Y_XWrop z`P;h6Nlrh)J;|evJG(INu$RilScbfvn;QKS{kUIAO|sYhu_??*MNcj$U;oeJIqTl6 zaA#jtlNZk;yMj&Z!zaB(4EN?N5?B(rYX1VG*RIb>PR)vS`^y}3r}DA9_Nu0^`%l8} zF1aJDn!kH%p)IpR;jM`md3MzAZZ0~)FXZ)QXRz=yh2vEh^*#03cRin{x54Yo_9N~A z`m1GE-p+}=X`kR}y#dI) zZB|;_mQT0;8u9nZr{!|1-^cu0`F!4XZw=)`vFkWC{^R*wlFOU^lgC>7-<`0hOCuLW z?2edyP@>GjWVPz2<$AVXUY$H1ziY+3nmEOyy<=Fh=3zZ5>d=Hu3!d-Tfn zs#naD>_7R{%2&*|3w1pJ?0{3g~YhDwGghN*APf6ZZFVBjq9h%9Dc;1&j9 zMuu5)Bp4VN*h@TpUD+RV2#N}5@w+muW?*3W>FMGaVsU!y>GykTj!)>2mAUa)FtiF_N8&`5BmJH|r;Ga&wmyCuBZO2vWPuvL&d!IG;Im*}ctk zs{dD?`}zNm`Ejnp0u09s89EkmFkCNXJYmIQca!PEL=}dZtLGUk7N*R}Qd_H1_J%o4 z_PqU}H=)@KHhb6eXnI`AXLvT-pW)uNNwZrIeVhK|V-c4_(ZgAR2``=hNq;w*nf>*_ zF-XSh@1{y%SdA?tqconHPjcWS0FFfcH9y85}Sb4q9e E0Q3t9FDxGwEea3 ztMQX}vjpBuo1VUttMqo~?F)&O(oZ&SI+*bKXl}>ZNtf%wGS8p>mT3L^eBvyNsqfF5 zG4woBNLlQYp47Wrezk$kgCml)N9J1asBSU*wj@V5wG8C zALL8qTJHRQ!?z`GjjXo)-i}4hb$jGC2xkT^S${Y6b>o!q>fqyH&p5hR13t}pc9H2H z-(!Plr|ug`tS@+T#I~%`n8|<(^D)>P?SY5NsL`c}d zKRDrd0c*C6gk|l*oq4lfhjvBm6g1&IDB&xY@4Hv{-?F)FE^aS`URETr?myEZwZm|R zba_Ujz@*-lvwxghCilqAUf^`X1>YIUW;047)w&jIZ>#up=0fo;t-XilI^AYt5WH4a z&?do?;s55uWWHl8N)IFs`nNrATdSGSFvqxeN`rJ7f6*ez>}07Sb4*@40%_k==x{25F z7#K~z8t>GpIyFYn?rKwe2sy;+&=xQ4S^R6VZA#dDJXHM7;{*Iew~xju67*;@%` z{Pq@XWGm!o=ahPSg!kNm85>!S9Zq0i%wTHT^T@Uk9qt%~e#Gg6d zR(xmwJ#eqpPiy(Bt0(8zT+!#)`(sTHPwuV35lk$nW=W-)DRkm>-&H(%WJ6Dkdvx7yNOuW8|hotR2F~=`*^XV1!4qevyf0A88FTCphvugH~ z>P1g-x0|g?XVCDoHk!rwUA{b^?}wvPr(Jp0A(R@{Dzo2&??#_A7FZ zcf~8R7G-Vo78TvqTKx0-x~{M4v7P!GvhQCAdH3{+-WF!N=NImZ&J&HE>zM7l^U%If zmv6;dKPp;s_NKY-zO4MUaMBTF;aQQN-U%1IJ+=GBH1R1%V!|%1bJJ}rQ(bAFwT}6S z#k)mTJIcAAN*#UeFLJl~E3}rzbvkROeb{*CZR<}zw;JDg$)MEF^CpT$E|!yB z+Fw55p~u>%{d29VzaBdsZ@Kbb#ZPVZtKtDl8F4|cl4q>4_g?vaZ*aZGm+kjf&R73a z{r+CUmt{;_r=RcHl_@NewLJV=|IWJW_piyF-c+ZV`SI!JXDq)Tv(>$r9@Y1^eE+^g zUitZ)dH=bO<=ZC9v

    ahfh9Q$~`qfJ*u>Sofi4-7(r zft5@*-CoOH@ZRF(_>@t@LxoE}!FBPbxlWsfTT?=fI#VT&o>_C|M&2`%@Arz|?fkEQ z|0M6Pzjhpl1&$Q*EYe_lxlE_tkY&9mQ`qxo2dB(3jGe%x+PooFNxbmy+=(AwT1JE#XV$!`+qy@JqpE8id7@3URu z%cWByO`iN$zAyMCo!__Zz_D{TkKDhxqbXip-e)G$-%Z~b7#J8lUHx3vIVCg!0J6t7 A+W-In literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_2_2.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_2_2.png new file mode 100644 index 0000000000000000000000000000000000000000..d6163a6e22ce541f7e3a1f5aff7ef27bce3e8384 GIT binary patch literal 1694 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-wW~rRN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kDT^ajpt9gXe5(UN1|oV^Az^Tx~_vi`0lQ6Kk~&iVp{78 zA)&Rm?CZP0 zE0`3eQ>BEn@7$fy`jFAx?*;R_BXt@Jdp91wYgFGe*XpqNhjTAjt>U3|C(tf6ci2UiOQo?WuNyFM;h zuC*a~M}ukG4Vn0ibJEXiTA9+;vG_V0xJ^DjeVLumzh$z{d;2e_UV50oy8jG^!w$n4 z(&ZVA0&0JSrW+&)(N!jUifbm!R^e{qRk8op!l`r8Z&hwdQoI4-kJ0} zJbdq}g~w(|nYILN_MMfzuT?DiRmawIcgtR``z=@X=H-TMk+o^PaWj4!XK#s=?zy@0 zdHywpZ~u%OmFJ##z|$k?op6VrP2fUW!7}E^Y_{TNV_9CaR*4O6MkiL9NH8~Vn>f+0 zefR90_Mes=`PX6oS+Y1Q;CsEna<vJl?AKGj7 zR2@5XtUzSt)#>J3!xxal2hxb1ScIn_jR+ZBvuITjuVwt4xm1th`Xx zdHZ~A$a}wk=iI-(d%|w_%Dm-XP1rL2U=>X>l@&XydYK-m^XyZskuthkb18qX|Jrlw ztAotSX6)5TnW=Rn`K#EpO%%})gqz1aP9+o2D{E>Kb*^5 zF82+q+=%f{as?q zY2R)4&5jnEfBSS*r;zI@-!h=CT0ip>212iw>)TPi}m8%!$+3NE{yBWc4o0H7>f>u zyVcC5H#bPH<7WFh*Y-mu*ZrIYk2YrUPgySN%z5;SV)~o4@0f%BF{kf|$yzbz#_P%d zK6Hm%s=e73;J-@uc))$TC(pe5|MhilDR*6do8zrWu(X!d{i)mDYZkL` zy2F1Scl557SrK#a!QLtH)ywxC|8o7_O84(|&+o3f|Ek;hcp}ID4Ogvqz2e*X?(Mnb zud0u)SYQ2h?codNe}c*v{>ZP(y|&}=49TneBOX{yV%V`sgMop8Ey>&6g`tumiec)T z^Ivlq7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv|W9D^k>?qRy@xGVNBoQYm&yCR)4AL7z_!Tml!kWwl4l>_}>YmEJVWWVK&RU&Zr>fbp zIxRO=aCcqYI%Ca-?v&=s!ZP@YYrFg}U3TA8ey^Hp&{wh{bRU_`WZ<@&z z$L(8VP96wb``B*6|5tC#UhLUto)R#r{?}^NjV7E=4&SU4F`DTYci`l)1q;Jhh<7FS z?%6B%ZEvB(j&FVdQ&MBb@0KwWQGXMYp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_2_3.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_2_3.png new file mode 100644 index 0000000000000000000000000000000000000000..1d8e5c96f3e270f886c4b8b5491328432d151b2a GIT binary patch literal 1564 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-HdTd0lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNT567CmjX1<#-BT4|goJ{4Qm%_}Z1m~Nk%!&6ymb@#JzA(NY6 z&`vM0fWN<&U$pnAtr(Gy7iu=Ok-2^RlRVjTtQIlGC^O z{pZ+inO{(K>+;&UG4l%l@RYdBV_cdZHp9o>p1D)1Y~FQ|XSIRx(~RpMeG@qS^Iw$p zgg~C2MINDvHw(7db~7}xbXru)M8=dKdQsfHSgi7#?An*ImDy#-?}{yt&0D$PtRH*z z@rzqFSDw3j?!w$G_h+;1H>hoowHJRErM+*fRhalz*5GN+7WFNCV{D-oV0mMM1fPBL z&fD$>K13w3y=2W&>+z9^XncEY7Pos|%=hAFJRMP?tQlS_*Q9K(ydWQP&-G$$K``GZ zktQoIqY&X4R}USkzPI7|={FO18rX;`OT4$b$6J;5=VU}<)a#|E_xwC6TCg&%q2c1x z*X|XL0(p~zH-FyEzw64`GQqF~3vOn9i%7V0iDM$q{H?0H&oS9=&b;NebF;QFgN9Qc zvw==P!e*T|-NkZKlG*y@ez_=wFA8m9%IVSa;l0%n(eXI+d~dbP`+cWYB)Vlc3a~{V zag@qY=vcbd@vp_(KI_@6?O4?7ocDnjJ1?KJcs=K{-i{YXv-9_S zJy$JX!=uF!HG|X4g3GQ&KzWi|OWzLbL(0dNOj4Qav+1Pje5WqSr;|&~Zl+DI<+BtE zU6SxyJX%IH-l=n{w%5v6S*zBr`z4i?vtp~7ulePi;SvH}s zyI$TsKX=u^H+KY^s;v!UjWw2;I2T?Qb#Pq0?&h<|?5k5>&&qX743=QMdZVO}tNiGK z1?$%MJYITt<(=ufCSH_(xhzi8J$BcBC(Bote4omdRxgU`{4MNS*7!^B&78bT7jDc7 z4XmuW*nd27!v?#z{3{F3@#|$oo2xag-SY6hjkocp8t=K^Hoctow@WHgx`wrXo3YN( z+IcR!a@u#+^-Yv>{Kung+f>t3Se@{K(b#j_x5#h)=T(+oVP3cY&{|{1n;Xs@zERWn zdyCb|IQ`;JBJVwNWR6|Z%FwV{z59Rs+?V$*%#m)K6?W;0r}qrbEl+mz6uy{ZwlHXV z=-lj+>Ian9rDU4zTheu}K;xtg!`21rI=dxTeh@O)bm?5SWW=gzv(8PjzCP*N-E}3TzGu%pg{9#E_O4#*7t}Rvx$oca z@ilPz*EjN!E1gSoWXi9tp1bM6RsVp^>Q4ge0?n(fyl3w|pRYTwBiYU?G+YY@s1mL zv*c+6~aLhiYy%k}w}nXmWwvX^zwaaZOW?+Y)gA9=)U zbYcI~`8KEIF9nq_FfgzsdAqwXR5C;{Onr0yYYqbg180FpWHAE+w=f7ZGR&GI!N9=4 zUgGKN%Kn%`P*gy>!pX>%fq~(*r;B5V#p$h=ZM}{p2pszupQ0Paeb7y3(xFREEE~VD zByC<>{^2pxJxAN-CayBEYqvV?-aBx_?Vua)jvW%+=8+x&vyZI2m)`d9=lRnT)&NY14F(vr&?)HgkHFcGT6qXl+PjIeV; literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_2_4.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_2_4.png new file mode 100644 index 0000000000000000000000000000000000000000..2aaa59bd1e4cdaa006ef07cbf883545d72e35d60 GIT binary patch literal 1633 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-zE*`qlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNT569(l=Fou}rxh$WL#$5V?np*tP>=BLd(`Y*TM`>ED0GZ(Dfyli7*Gn-3loeJ*Ke#W{=st3vg(lEa^2_d8dJ)m z585Vfd8)F0<7^Jwjb#;e6%Q7F`}J>U;`M6Yz1vN9r^rqy%JP3ToDwXI@=Q_;%elud-77RPOGgq#kDvt&Prq0Zn#Wh-X?}0i!~>USWA^Y zcJvQTI9|Y*&9l)mdErZQzxq}toA9P(iV}-YJ`N6E-?Be*`NDhduY_I}B(?51gv(BR^udi5ahW@gKSJohV(U%q0RG)-bDs|&}p z4tCQB2Zhs7j{hp8CpddXtPv7ak85)A?3-KqXwK)nD=VJdjMl$b`M$Z|j+M{Mqu^k> zK$6Er7dOtyFBXLx9+3!cy3BH!GhaPp$rRsbIh#|a*Ya6D3z=YdR7`W-4m^GrZ?YOd>>*4oIC;Sbiyihv$}? zo7LPqv1e+Z_;&sk%zq|ZoE7jr-e5Uf>Fk~MmDLBMe2d*5dR~ZVWez?o+q%|zvd;nW zuN7Z=I(r}9SQ5ssoPC42P~6V6JI{Mv(c`>RKNsw)T)0hl{jG08e*B$l9-LltX60>- zvx#YPB663$?X9@_ykWom`d>01#6RAv`dY?xbZ7Xz`(Iz(WnQ;c_F`N0mR#!ci|$P?GK-AyDI9v`OYWHlba463i)(& zQop+Tjnbv>hlK9D`1Cnz zk)86-V&|&mnTJ;{PWk)4^Mz~c%IwF1-#=;Wwn@sK`Z{*|>+H4PH?5w}qxEK6y-e^v zpHJe2D}Nn-_^`Ziu*pj^6T^K4Eq8O&WIsY|> zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_%poW$pz};^`8);&hPR$Bjv*GOw_e__ z#}X)V{Nwqlp*pQD%3U)LF?YC3`OUIu;TOJtdm73=2xu?7pm}AnU~dJpwUkq{XGd@7 zotd3;Z)6?Md}sUp-=zEB=gbjiYi9JA#BzgEnd3QA&$h?Kb>BGUx|woxbebfC-B#$C zo^-r*rKc|Yy}$Cwr`7FV9m3;r*x3zxt8C$^$r^+ZF4cWKU4O#zopr E01Yh|rvLx| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_2_5.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_2_5.png new file mode 100644 index 0000000000000000000000000000000000000000..25185d969cf1c9cf78de293c9304d5b99454baf1 GIT binary patch literal 1605 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 A@Bjb+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_3_0.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_3_0.png new file mode 100644 index 0000000000000000000000000000000000000000..7be866f0b2fc3d8864f408b10a2f1a759ed49cad GIT binary patch literal 1683 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-rK>_BN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}i=OmagXeF$=w_Cd3cdE}tKRXY{VcAy;b-kxo_Br5k%UN& z!akKXzxLO={B1rhVRUMjK<%fv$D2;7O*ZVPie0Uq`@GivMe+yNb?3y{l-$n0zW9CZ ze8uwXEeYHA)J$C+uzl_hUfF5e9p$v8dA7yfX}h6g`8Iv(w>>%X+cy7~S=Jf+^Is10 zfebz;vr{E%*LM8g$aR?6Z_Y*cJDrCEoTQWccgt3--w^!#1KT~zU5U#-Px~CMG38tI z!TSccii*~6oXv4J!aD5VC#5pkFOR=A%=PG2s(q^$&A(*Nt=U%FjNAis8YVqA=@Fz1HRm0Y*?4fxX`?`y*o{Xgr?<_!9QIQ5oyaXShK>!} znvIVnI8-OO&nq!d6JR{fQDzaL$)@!Dy`S%~+h>LF$>bCqY!^uKP;~Dz+w~&3 z!*JP*$(}tz&nEdhE}ao{O0qj`#<>}D7fviTZ0*)v_e01_XXTTw4=cCrdX>Fm zJ@)1bw|KTdd%=tafqr)$@bpM}C)n_?30z1kSf(7A%~srOJeOzEA;}GHc@r*Y7_hPB zsy}Y=d#Cqo-&0@9-{E^^mY-Sac=!LoIZ{`0pUtbRJ{WcSv&%!z3nvaWu1s@G6wcq& z`D3Bn`gt2S8p^a^dG&fS*Qsmb6PwnYyfocIr_cZHwe5Q{wN2-R8ArCuKhD^FW|htH z*2)WI9l!7YUNLX(pSk_7Zk`mkd!^nouO`f`O|!_dRAj}@>Rx6A9|UgRr;cwg^!mwua)^E!A{)rLeKuu@!Gh1QdgO{FSrPquFmdv3PIMd&u`gK65*KSZ8wS+Gv==jA5-Y*pt+j}*UtJ7j-}iF)M*l|Gg5|gR`1kj#5j1acgakOYvL2=4R>@dxfKO&Hrs&q?Pg2 zx9+O%DcitL+oGkf8#9P3mz6x*@O!(phWj6dg)Z~0O%wTw)`p%)eb~`7`P|UB zS*l%IySGaAB(^(mj#8?Bb;)`CyqZ5tyI-9=9=~hFy{R+J-JhI3BY$QUztR488zx+e z^r>CD+)m-A^7|{_8^7-?e|6mX?@wo!6S?6VmhIi=*7r%5@#%`Xf0b>z0|UcPPZ!4!i_>c-Z}dA9Akwy9N<2ZK z&`|c)L3RUyq!~3#ms_uv3(WM4k?dT|&%ivpSwDf3o4ceqA@gxUklJOIEkW(Y`OKlq z?rok^{lEI$&;NhSk8>RsU^rgL(6NYv;d&|K2`dh}n@k@jsxZV{JhEml8hawlGN3^YK>J4;Mc1R8P3fKecJMH)9<0N$#r` ztlwz9KPZ3XI*;SBckWkbeO$1kSHFKd!<`cM|9Q&`S@(PI^zxUvQ!|Z$fq}u()z4*} HQ$iB}Qi&{G literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_3_1.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_3_1.png new file mode 100644 index 0000000000000000000000000000000000000000..ae440af708e4907a580675392dc4ccd9c0034675 GIT binary patch literal 1730 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/flame_3_3.png b/src/main/resources/assets/ebwizardry/textures/particle/flame_3_3.png new file mode 100644 index 0000000000000000000000000000000000000000..ce76fcc23c83736c6d98570d14b439974dfb8087 GIT binary patch literal 1593 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_0.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_0.png index 531b56b52021c306c017a547365e2f140b1d819b..d8e719bab58e70bcfb8fe2b81236e624fc59814f 100644 GIT binary patch literal 1649 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 delta 198 zcmcc2b(7J!Gr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VWz4uU*E zFWyeBWs$3Y#KO-l&HFI(UnK(rLz<_HV~E7%?$NrstN2I(JdOeqcfq|33)78&qol`;+0Cz@F Ae*gdg diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_3.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_3.png index b12745e939ce781a0af09df2ee45a53061b1dcf9..85a339fd4f1930d6c25d0898cfdce6029f96e623 100644 GIT binary patch literal 1213 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to&s2p(lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(yJ-6ts8c*B*&0TtoiY-Tqe$08vx9iWogg*bGN%v-|{k;6r z_K4fGRK+hGZ+3jVKL7IH#`q6*J2kR2mp}Q~ZTT!fVaEQtaDTgZpLc%Xe>nHvU2~?8 zo_Xs}oAlK-#?9l;u=({X?)?^7`!X3@8~OG-MCqJlZ6Y#x8jB;7~$Re{s}e1EmLNSoc2kS#z2r_atX};xC)>cVh9A%Dwe>et!Dm zXRX#8|KkdKpS*bCX?OnaxeMG|kDqv-ccqg5qhfh++3ez&&Dw^F!6)Z>+AiCqDiOA1 z()VOe-$IU*ySj@dm))4~g>RPVTFX-+6W)4Gv=W_VQg(lZ;t>fqhh5Gbx*x7dUYhTG zJK#~4Ni&mw`2yh`jZ)6C?;#8}eD>qgo#&^-XKr6?8U9kJa(8j- zjzd}wEgMg)HD1He^6ccwH-FweyLY9xo_U&MK-nx_VV#B@u^|i7b3Z;ivq4yX?*3DA zx5%@52p$t-apqyN6XaI?B-JFO*w1FiI+49^VG~1Vi(g(7Z!wb$cXp1=;w`z&E#AFr zSru5kT^iZAIW{DTT*R6{_zn4c!W2s7Ea zw*6a2#gdXob8ay76-8-B%bYs=$ocKQ+4CZgi^Xcrc`p#PdvnnIm5X$r_UM})l;5Wu zz0c*%g3_2ppTECd|LxZEq88^Bz3pa8uTB<`y76k;wcySBmZtevTwM3S_WR54SN0v~ zIPOu-_iJhCwz!AltdAF#3$@1`nKi#kcy%Rv-`#({8IOxXI;;O?{oKQO_U^`7W0UgZ z-_Bl$xq7;{sCv~;E++jA=?@=1Epbf?zIFUl$y4`f|8>^QPrd&v`0g*hwMRZKD_9b< zkp11SlRS6%b^qP(`^VlVG2iru`i;N5y?gg%_U5-uW?*1oOY(MiVW?z?Vwn2o{MQ@? z1_sUokH}&M25w;xW@MN(M}mQYfxX1j*OmP-hoGo{akk#7Yz78~B2O2`5R22v2@`g`Ha51l?fP*^ zq3*TfbAJ7K2h!#IySiikPro_o2_W$F`Qpjk-|p;U+$j0#dDVM|J%&e3W=+y$XSmlW WyDB_?a~1;w1B0ilpUXO@geCw&sYBQR delta 171 zcmdnXxu4OvGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VWz4uU*E zFWye(W|7N##KO-l&HFI(UnK(rgO8_+V~E7%-|3B0J{lE5)GbgCt|MUCv z|6}{-^W?|xY3bg0Kw`Pw{@?fi{o`c5-}#wm&7YbXT;J~OI(XpwBUR_UFVdQ&MBb@0Aff)WB>pF diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_4.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_4.png index 389abbd7b66592b6bdfc8712edbc5ffb7c927abc..0bf02ea58c40661c78e17b63a7795485cd6f5cda 100644 GIT binary patch literal 1591 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-u2h9YlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPt{esiLZCeNSaU8anlbDkBrtzpmpr{*45ySMVXi6QG+u}LSU zxb$ZI|9ktY{f`ZNev+@7yU%6T_?S!-7IR#GewOF#pLgQFY^|8I`ZKe$%8b<7(%jeT zC*JNoI9vDp`J$(%w+U}sc>0r>#$n^+jb9I$sqA^OW&i3O-&H>s%=xQcH_PJG`un}? z5?7rx*6iTyJa(B^zllS|>yXR`m5bYe_?*@AJ<_&Xl^>5qzu)uyp!@tL7U7(NgY5!I z9upTYXubJjQMlm|iQuNoESEWV3!4O;nxi^9XY*;hc9~)=kNHVmy6b)jdFiYyn%ebg z{kp19=U!9OERUsWvvSw{6pPAPseFA`$>rSgyWcM)`?qgB`^q@`%b`2h*IZ1?HAq`F zZ+~R-jo+tPddrg7(-V4l8w>3v9GpHs@L@Mwz0Al7$WScwcfA_C1g1UDek-bawTM zZzj`s92U=B{CVH2Gc$uT>asJxT+sBT8^}(VoE#_vuLGiy065)MK zAEy4>C6lVH8f&-G-{8ZxQkexip08rfEVBwI-hM`RV!?J@2Gd>FA{H2`?n}9*zg6PA zq}9=#TU<@=^gKNAcWF_`Wus;}(X*+6VHS&RZd*@4hBS(r09MP(Am?lZrA6Bx=)1@Ez-{kFP^Af{%qRR;FWi7dc5AQ^Yq69 zUf-Tv=4Ax}*S9@ZQ=gF&-V*pdq)yf4tJq`twiWl1{y28{UMdpede`uMQDC|2g>xG< z&dxpXSV{X-?EW3^(mIySTTy&8n|IL$5kIF7Q5QU&H(PA`GNElv_@yb20xz+@;m?$~ zmiOoKrK7TwOZ9xtl*>J9<*^RsyO1mXEp}6({-ee#@m9}6a?@93`7wO%|8=i@TRY#M zGS7!a@mJ%0pFdXKb8O@4czcr_vHNE(ZBq@6|GroMR@~y{FRo5m`srS)-v1hf&!vtv zN$)S}wX2pqt^4`vSHV=92TS+8Joazr!u5}L)Cbjzv&ZfEkiYAf{6?3TmmT9ao@8KP zU`z6LcVVbxh+>%f=KR+j1_lPs0*}aI1_o|n5N2eUHAjMhfq}im)7O>#F^8b2fXP=c z`x6Wd3{N~=978Nl@4am6#T+Pd^y7VQ;Q*%qwFzoR&uHCgni^fiJnh}#Yll>CWTq+` zFA-SuLr_-o@q~24BT7mdlD21SZ7RP1eg81#nnx9Z?C7T3TA zozo7H(;npAblI`)S;8Ju4ujR&8_a!nD{`zp-1Wq6cEgrPH;Z}q8)|k4C;a)qBsbgD zT`uITwZ;1R2d_p)Z=S$1Bcz+7b@{jFH+5II@2-Dx&~yD3z|J=av>$)~xHhchyeV^3e8<{fo8--Cc`*e0dyS_K-Q6GpOL!;j@Aa3=9mO Lu6{1-oD!M<_8tQO literal 289 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Oc=AWzVXw+svn zoCO|{#S9GG!XV7ZFl&wk0|NtliKnkC`y&>9ZfV|!ng1#o7#P-hx;TbNT+Z#c=3@+$ zXx(ou`AASv`J&GgEs?0`jZD8c@ciB&V5N0eKiI?OSh9zN`S);zSwB|=&zV!hzHfz= zE6e@~DxQUoE&-u?zRT>nTsdvko_S|Bi!d-NC@nElD~elwU3ahBnt#u&bv n@rch|t@+{oFc+@)J&Y9%K|#}hxkfWEFfe$!`njxgN@xNAz;kHb diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_5.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_5.png index e1bdc75dbac565c8c5d94de7eebc45df46b89b4f..8749f94dfb3988cdd66e9473c38d136bf67b56a6 100644 GIT binary patch literal 1498 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-rdEYSlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(S7P(19o#)SU5j!VOC!OPoy&rgMYSg_io_;-ZJGQ-r}u`+$CSJ~blgqa(vjo(uQfCEtmpqeUdpXsRs1hu11O=L%SR3C z{^!~rSi!Y)!$UO{@p*Y~lsX(1shnZ-7qag$XnXS^mM<}Xvu?}RPh71# z@0bFW-E`UAFi7h3e>=s;?WS7+bHjo~n7!fZ1#2X_>a; z;flX4mE0VylkD}rYiFKiOfHD|kXCMIH;9>c#Asgsh9FE}Un zC4{*wf-6FJ#m^&7#rG|~Ym00sR*f(^DCsMAzwPIeKQjwuzS?$z(AnlG9j8yuUt?OFt! zyJT41XSj*)?NmHAL&(gxVD1L1gGx)!L~c4eEB2e^lNrH|KSiRq?0Dp@v2n?%P_0}0 zcfIoEHNAFa#lk7Ga&N_a*4=U=$bD_;%Wc`^cfVgq_HW;M_LX+_mt%LnM=m~lE8&cv z_5TFktoQliCVj%Pa~ch|u^juGz`%O8d9(I}tu`~H=fqCDC~_*Hw`4+arU4sUuJSd% z_TB8o_n)3!@i%(U$L%wWn|H+@oFjQ9_u0Nr-x{~hde*BndBMe2=F8qzd}b0`CRi*f zRR8-W=ikca`rV7?-4>dBq)6La)_D1aFJ3uqV%%Dhsv$Q_)4HcK$LGvf;xhWY_V2fx zx|9ufukCYLdMR&dadq{SeX~{`W!mn1e6CIMeirkKBF3J*+rQOLyLLy!cU#b_z}qH& z7tTJEt|2D0rEG%`U(d07Y42vF&J{d<G z^f$U@zMB&AB%!Tk`ex=RkNCN6->)vceekyIZb^&067SDDZMD?(1=amE?&}A~E6>z? zymV9d?ynZs>L)_@E5i0$ZT)%k>AIYoYmfAQ<0@6Xx#!Bi75jz4cva^lzYXz;pSrfk z_|LM;>raY%A1ruI({#^39Fn`as`IAF~L=Sv@{biQ@-olET zUsqJb?_SJXwYc2ti`W@u_5C&v^mg@bnY-?+`gxc4wbqxNWmDUwpEWM~yWyAqnP+bU z4s12MyJAX#g(r8fhwl6zyFYlpp0)6DtwY+L$u_^{?!EUn?r?iu{oJ$9?H|mU{#j&p zZOMmsQ!jiixRX4G{kHxtmw)A7?iaRPUzzcbMeoI_lil13oeT^NY)RhkE)10nQ4CYx zod24`z`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||<`5JWF!}0be}aL5;h3k3V~EA+ zx0h_am=i@>A3o<6bUewSWmcwlAV?sGP5i;EI}OnjMZR5|rm5PZXw=!FV4>#IbMbtV zh)JuM@P>~e+jq?Qd{6#g)WhvcGVRh2VLTBE=zmptmn|Aj{-acG6)j*rM zXV+eilQnFg)@GR>*Y9PBoVK=O!3p-OvHpJbe9ZfV|!ng1#o7#Jpax;TbNTwdDe$kh}e z!tlIXkVW!}Z4_JMY=8C_KCuf{ABo?R|8`TEqT(@g!NP?eX*aVcvv;If8}R(``d8-} zAev;P&A{gnAbP3WIl5Sicfo6h0^hXAp5|Cw0 zr{lWWjn3nrUarvSD)64Y;am9MCZ-#2%7xS{qq6@!Xa2I=rC=M2r5XbR1B0ilpUXO@ GgeCx)zFGhP diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_6.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_6.png index c597f4151ffab8cc5bb129c233b3b641eab0c5f8..881ed9a89e133b763477b862fb553ca6b775a995 100644 GIT binary patch literal 1177 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!tomsEvBlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(yJ-XR;Q?fsi)`wkj# zR^6PwQ2sy9?s^-6yBnu}FB5*RH#%yw3~Swfu+UZo^r97r(#S#2uhDWAln^&1{zAOq$!J z77Az4NOgSC)Y$IY)fs|m?yVYwR`h{^U>*V^vb*5vNX8N zxUDQHB(S0JNU(zROl856kPjzM%sE=f$oOfV^h`!GCB}j&&+k;IUHX)I{&vq=Rt1~5 zi5w;sjSQzP`+s%%1v=mCE?Rz?BtoDMSbc!Po7ab=KWCe$_amqUNu93lDRkd zcipr-@psbfkMH6OAJ3m?EPPk{#LUij6Mj#;&3+{+E?y+E;aRkW=~kl+8xJnbPCNT~ z_LrykYRnJ3cliI`VeyhZIcNED7CirULEzekYY)H3H_Z%B+049GVfOlL6R-P+bymI; zytmb_`dwK2+U?n!Zr^JD@}*PKr!LS-ZNG-<=a(WG?@jk|P1<>8@0-AWx2k=Cp)+l# z_tdP4P2Spcwm6d0`eE)7zKZDXv(d`ccmL(+?>#2FY=Pe=quH6~OJ@hmTHd|)ZH?>F z$w{$w`Sx17B{JNbB*^%|Yo3=9lxN#5=*43!K~ z3{&5n|C+0dKYu_){bL+^{uRJIGj`uVEkKeFo-odq*4o2PwtM>CooE2}*6Zd&v pdf?dx=Fq9ZfU-Xg!P9R7#KV}T^vIsE+;1}u(J62 z^KN~Lov_jKv-|D;m)qB#Xb5%uc$=Lk{@=gU2LV&kGpsj>=W%iODE|F={r}bH-wbPh je{F8;?rrYsV`F$IBXu?4vh+p<1_lOCS3j3^P6;G8Zk>8<_{=P}A+tRIH`^kiz3ljhBIX9~&;``qR>yJ&odpF*| zrzz^(@f+Lg8)M~VgKm6#eDht<-NGF9T}tm8jNH>qw#|R*aA^75Z<|l=j_1r@w%LAC zSjX+3UoBNSE{eD%9*^~~c~{t{bi!ei$dxv0&slyNn`H~bC-!eGF8}PhXZP1dbM!(;>kSKmBRJnVrQ=E;s z!lfBcp2@~BI3;JV^1dH>XLjl1`wgN3S5!AAHXW5u?{I#(aa&5E*pHR`=jNZD8+4md zLGW0ZiZc_F-6RdyPo0*6j_%C!o6bZs$tyUlx^seegJ5SvvdwX~`7WoYPxUwM6Ke>_ znaE;t!=XX6De3Q$ga~I>*XH1>D?EKSPt!1T=`~ztael=lmDVMi%ckf&4e`;L5w#^H z?WWf=9g9OI$LGXsn^UYQu|=W8@jX+25TD%>j&`|^9__L}HAGJ@Z(C)0EoAMpC@J&I z8~=2-J(;!jj@RR+R;Hx}b8-ixjpb8IB{DRT@~&PM&Gb)u_Jn{`o`0upjo&V@qz56-el6c2+z9qBoROiVDWT);8Okte0yCCaT>Vt%4=k15Wo>{+~ zp8b6{<38rU@0oj*r(eyfdr))d+OZX~*NR^pot}DBI>)r@YSqrtr>ph9-7#x>TE?>S z_`6qoN;Y23DV3>e{j)r(s=s{8v+GxuS-J z+tubjAL?yT9HTW?MO`D44(-fQpnc9dqv zA3AZoTd4g?U3F2+HYv9)mRpO%f}fp^`M;Uf(#y_0Kk>uiuFXGW?zHXt#d4nJa0`PlBg3pY5)2Fs>?NMQuI!IF1Vsf*n|%4>7#J9eJzX3_EKa|@w2|{r07J_| z{q+JW6V$jpo^2>zT_Wia?wLHTps`_rlSh_}lBfS6s delta 163 zcmeC;+|Fp+8Q|y6%O%Cdz`(%k>ERN@z`(!(!W?W23=Bv3_jNNcFt8HQ#KO-l%~z4I{xAargNvt&V~E7%FVdQ&MBb@0LU&qXaE2J diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_0.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_0.png index 6c1dabf2c8c5534f2ed11fe1485825402b5fb788..0260459d7b778fb7399a76734eb52b1fa101beda 100644 GIT binary patch literal 1274 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!tozgC4rlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNT5dJ$lk-4W8Efkw>*)i1DP8NAd&`0sa&Jw3I-Nhtc6!C-b>F3`^MAkF^f}U$&z4?}Ss!rZ)YJzjTM|qx<7VwN{^x1U{MF8D`iWz~+E0!y zUN-TVg894;OaiaGgXjJ_mp1R!F}p@lfh(HDN7y#s{U$K`(&B9?MPffzmL7ZO-s}|1 zs33SPOvRar>DpwC%1w=y0*=Qy>?CJywz%ie5VCX9%LL^|jOw2vq>Gt+ot3O+O?OTBZD<;G zh0W0X@1bU?Gm0{b88PZsGa4nVnLZkDELc!!uzBK~$Buahn>!0N3Vtek%NA(yCMmp- z+E`|F)Aq#Q39|#gN8kCOU6i)qH(ycOg6JprcHRwGU0JvI1dEB^!wXlujvr-f7c)L? zvv2ah9p>}deynGIwT_oN|0s7>PT%6AriQYMZG2cC9N)oy`{UC+XI`8&{ITUev**-3 z`Ys!z%Tr>?-D^J1S$1yA^SJIUU$&Tko@v4Fd*-~0q^P}3^MW<~FK@m-yl&m^+DVe% zc0B!&nf5Ha@UM<>@se+uY2I(vxu+?eo$qb7-+djc{k6V3Q6IVIc=@*9^jPE_=rM8X z23^}+`}Id{FNB+_nLgQFustew%30CJHzs@z*VuOF?Vp`iXT2-yE}XZzbuVa#XIF{p z)TKX)mwyzvXQTb!Grw%nSKhn4KCxFU9_7s6dHLLtJ+J=Uc7Ggl)Fx-;=d+=o%tHBs zez4w>n{7OQYhDwGghN*APf6ZZFVBjq9h%9Dc z;5!Jyj5{V~zhz)xU@!6Xb!C6dAt)+fChZdUgn@yf&C|s(#Nu>vf<(rF4n2i zK=0H!5LK}H7hfFn42@DoZoS#@@fBymf*&6p{m;Y0!}IIcubwTXjJwXh53Bug{=k6) z1urkDvVp+XFwr%MPPXC;X7g;8bUPg5w%eeAF=EB&#zkXkBf9V)2&y64@9bWbP0l+XkKt=nLY literal 196 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=eE{Yo_Ugifq@~=)5S4F;&O6=g4hZ1 z6Gkhxu1e@IKB#ij^`>N8e8t&Dju!7*9-wC2;Jzd)vYy85}Sb4q9e0OjaIJOBUy diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_1.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_1.png index 990fba4b9a20f30668c5755e564f7cc141052754..52f737ab721eeda14986f3f57fd65603a3e1e46b 100644 GIT binary patch literal 1155 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 Cqyzx~ delta 164 zcmX@iv4hdLGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uMk0kd5CBX)LfYa@sGOK&nTFt~cUIEF}EUV7#r=K%&DCWp5UX)kif52Cj#Z||I_GT{juJHr_smBh3OPkwIPJy~VjX2JI_UQG%JJ@S4|&ye%LNAH#j|?Tg~sN->zLje~r?u z<`_kYP1+%Ep?Ue=&zooYYcy6#sXNwwsXKh!RXq2Q!}h?>zX3URdAcFaueUcpyo?!`=fb1rDFJCbOz@a)Ge`!Af6IXt=I_=_cXr%jtH zztmuMJm0@17dK6|xt^z0vZ(CzpAQOGm5;jazPI|@y>C}lpD&zZo*lS-=@~&8<0Vfl z&n{;D!+9)mTgS49B*u+gvn1C_bfqjTQ+J;#RGPI}KO|t$=Ce+D*|{5Sa=Csk))nrO z?%lgx-Q<2DcZB&8mESCfsAa8yqxJqws zTpoB#!F=5ZCV^Mp!83oIOS5}3`z><>o8wF)ZLt~K_OzdH`o8z*WaGpBX6f7hW(2Iz zW>9g;b2L1nu%R+Z(LZ{FnSi4^>-?5ey4JHD8(eZ!FCT2X$=r8qqI5BnZ@hMy`Qxih z0*B<E(m({N7E!)3ZaraP#^TGaKLePcUY_t5p8 z^~<;SYRnJ(*9$m*Zhpbx)?;usMH6Py5}Eji$$cEZp?{&XPO6&mP`<|Lsnd{Y;+z?GF}*XQg{z++1VZ zc6{qB{qB!W+@Dhoi22tCz;<`{v~3^r@byWL*I1noHAW0 zcG@+qTCJ0t@7eeS&Rl%w(6v}gF`v4bTTA}cWZr-MpY2ya`yqd^Kh4?ySaqd$J?Yob z@L*tIU`z6LcVVbxh+>%f=KR+j1_lPs0*}aI1_r)^Ak4U9V)k1G1_t&LPhVH|#~gy9 zf(&P${<2|UU`X+FaSX9I{dVF;-Ub66mh&BzlR7tX$R=N?77;7R+QpN!N@OA9LKl;o z%$vV1OYZC2V{2l}KBG-|$8P2)b7oie1nv?z<3HP(gJDJ1=Ii$l#uj^d9uv5-KQ8zB klv>e-RO??>KbX}wX{hJk;W;>qfq{X+)78&qol`;+0O2SPT>t<8 delta 171 zcmaFBv7gbnGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uMk53^j}BX)LfYa@sGOK&nTF!*@7IEF}EUfa8ox50sjS(eS~+u~%NS8G0TTbRl= z&(IRu^WwnMxw_2pPC;hQo~yJN99(XEQoAb~Tjeon(vmYF#jn@@ek3z{?eE6=BE~&8 Xb*%SaJ?+H6z`)??>gTe~DWM4ffK)ut diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_13.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_13.png index 85124935f27096f74edcb5c5cc4186127f47e40d..ea5d76f241e6761baa0e7c8464931a0d250aa47d 100644 GIT binary patch literal 1074 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!toqpCt8N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsH`<9=qwb0#EDxNZ08JoGeL}f6kS#$JX)BurT+V^-b;j!pkdX zO6Z(+vYW5anQ6bT{4+26(FZ+~7uZ$pe^_wQ)lcHZHu-A**|VRQZj5C!FDt&2Fhi$m zcl@tye}vx@)hg^rJ-@w7_*BX+i`i__f>nh|9v~@bHJ(DUxTKH&s4TZ^T>Rj zET{WGS)%=>(yT|K+#R78&SV@7P-(k0S0>c!%F46*0vx;gq@DB9^m3N_D%L+STDarl zieiR&Sq|;FjHcYi@;figF+cZ{OEYa9i@zGn;*%e*oKb$P{g&g(Z;jYRzWi$^i1*KO zlWM+WahTg-g}!gIxvl}b(u)-jCQq=8J}$}P(V{(*&+J;&fk3(9$1@!+Pj4+Z-X_){ z@Oq<1iH^d7BEJCpgPK_youcV3N4y25YMhLIzo+7TvwU?3m)Q=5gY5z)M>*i|52AnywgP??^Q9m zM?bCK#}>Tx*eog2DM7`)v+@^acI%d2iQ0a*^yR+xb++G10-{6mS6=MAQ=GMB1#eQ` zuU2i-8O}Re7Hph*B7rUG4abqg3Jp!q4(0?G^|9|fnA6?ks>qY2!tA%yk%uK#d72;l zZtb1R@AT~OFMJ$7(U|#e_yl9-yGrHf-!g8U^~}6$Zo@GxnOS+;l9QXAFCUq8to+jH zy_Mz%;>A{^KfiuK#_a6NxqHr3SH@g6c>lEU?b+}b#y)90w_>B-I(|A|{9maz%Iy8~ zPhPTLm%P=RUMp6dUnS&TZ#%Wpe){q&c9T!fzjm=XX4e#x<3AL4d^eM_nt5*T(Yo)_ z({IjRZn)w5JRj2!kE;y*TYnyLGSPSbz4pd;j{h3QpYzndOYWU_FD!9 z2KEw9Usv|W9D<^PjJqD4TE)P?5b5dS7-Dhy?Zkte2Ml zV5$xAZ=U$zfw4=AlGEz?-0&QKRfczb4rxpms<$h%Ua!$e4pg1Ql8{!mEy3)(>+^7p jV-i)`t3##iZ{LyLF8%ZBgZPUK3=9mOu6{1-oD!Mt~c6VX;4}uH! zE}uMkCbL}fBX)LfYa@sGOK&nTFgSX;IEF}EUV7>v=K%vAmV?$Fwm}zHdE{k$7P6?6 z+@s$q{c_2>XB>=wJ{lj7@}49j$h6@t|BS*1PyVjdDw{L&TB&};4w;yhoTZfv3=9mO Lu6{1-oD!M<7z{V5 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_14.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_14.png index 50a9fc7007a62c3b58da8b13bd85d7ecf9a1e544..c9812cb6c1456a203d6778e326e8818a032a4f19 100644 GIT binary patch literal 1084 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 Z?R7J{*JH20l7WGN!PC{xWt~$(697gPQjq`v diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_2.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_2.png index f9804dc0e507f82f055dd65a0faeb2335b3b8a26..94dca3bc6c752ffe4c4cca6b614c1f218e783681 100644 GIT binary patch literal 1165 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!toXH|tnlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(yJ-Xb^y7nh=cIWi zFPQfD()YLX6R-bfKA2lwxn*`h`J5fhca`2Z7*(g4Y>U6s*uro9Hhc27;+uOV&;9$l z>F~D4*S_9j?YJoNv4yu>aihiWo81b`o|6LI=Xf3}ahjRizqxDQwR3aMc2}goUNraY zZN2^=iPzhk_h)Q*yJY>=Xs*~5cdP1l1b%t*$aA-0l+0rJ#i!3XYvzAjkmnq!Ya!;L z`P#5w=tJ<9!&;oGNgbj`q%y>&WN8RGzjf@BN|m}29=lS>_4r&xbK~%7sofLo3u6QB z=$KeA_!}=c9OUSm@XS~|>hH3v@k=}ANgtfdc`&1JkI3g!Kc*J3NhSNmDoOjVogjYR zve!gyXJwms!-X5OUR^2|{hW61hIs-jOX*1&!vi^|1s7@DeLhX+9FzUlb2pMR12U`` zRGjX2rFb|Ts1j23H#1;YdLeO8UAb87I4g_CROy+FW=e7eO6T`|^jYxq^r?2qXl@6M zX&wwxItmAh{0!@xx@R~`zCI=y`c=v#>(ZN}*6Z*6e(+pwYBP(t$qxZ19?d5j7hQYp z+9Z;@EDMEl5@*$LsU4jXbnb=pFl5&>fdO}nSW{M>h%kc&C1HV zvn27S`TeHMjZ3Flm-;Myx2x>FbHD9Z8-wd@Jmw`o1l?pZpG>~B?3YKc-V?iJZnJNx zJewB3Be>bJC7NT_?M}Zmg=2jVHa<)2dC(iuuf&MJMeq-ogcPEX^Vby7Nsq^{bb(Gy$h~=s#<)4$t3*Yl`E$X9Aj&jGd^x} z-!p#Q*>dJT@-O=NO}ajZ2kTUtojw2L^G*l(CxzxS=bwDO*g^UD>r*eUo7{^yv%B!o zchg^IWB9s%*6FQ(7Wkfh-oe5E8|B|N(lN8V4$n@w`F5#USkeAFLOF%&_u8*GtLo+-EnohK~JtN6a|#(6Kh^V{REJqzbspSt_njX(VpIsOUG;d&VS_k!5`w!fPX z&Ggs!8MPxltLjNy_Fm@m-)2mjP}cH8^5vQHIyav?9R6y{qyNKc2k*MD|4N6qZ~eJ& z?l;2=(=Y$bH``{ff8l^S&%Y0|>KVW9IJnp@;CUhg0|Q%EYH&dP?C}E!4jkB^S$MiWWqN?USi*z9uliTiuyNe)KiIx2 e(cl9E!&zmi(w2R8+ZY%a7(8A5T-G@yGywpgfF}h2 delta 174 zcmeC>Jj7_+8Q|y6%O%Cdz`(%k>ERN@z`(!(!W?W23=Bv3_jNNcFt8cWU%p6u`TAATut%8ZX}SQ<)AR}Y6OLx8%A62CA@sb0 X;cc=s7bm-dG01FBS3j3^P6LK|bX~-)_IvTw~zUp)~}sq@1*v1l=sGMvHrB} z^k$KF9JdwsWNdl6WPbK`k*bB?%syZ46KbWvv>4;uoN!wSn&@?~lbEwgoI~?x5AQ6tvmM>W z?4WdJtw$RROP|9ckry3jCURIw{YXhU_h@GW!^$FM^8;=w41FKxNS}9!+P9`=*2gSH zj-z6o4$ZtQ5%;uTsaHAkroNGWA7Yvja(RiR#|KAe4#P9$A$>x%S0s{p#DdSLJ@eI# zFxi}9StzvUkV&gZ?4~I}=Vq8FmmIq+DQ79J7gTdm$V(?I=%nb=;M%KFS!=?A&-TtX z$@wo9RdO~eYiF>#X6gN{?Q*-nUis{>mRGXw1&1=9bmo)pTg!g=^v0d2_3bs=>UlV?0@zG1aW228!q&7;`1OMB zyUll|-rbI z{+EBTp3mfi;N&~?TY2~0k~<%`hk=2CEy>&6g`tumiec)T^Ivlq7#KJUJR*x382Ao? zFyoGi*>4#b7}!fZeO=ifa|ntGnCCd>6)`X{Bzd|xhFF|VPLMEq@aSmwfBm>UKjdTQ zbOtp`7JB~q|Np-|Gc)tyrQXveK;X;QuNzk_y}_!}B61)`LE_Z;0|yQq_)z!N-D)R8 znz5q8--w2zre|0yXBSCq{5dyEPlA<)hvCXf`KPs+>y;T87#KWV{an^LB{Ts5R)6>g delta 147 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 BY(@Y8 delta 210 zcmZqWddg_r8Q|y6%O%Cdz`(%k>ERN@z`(!(!W?W23=Bv3_jNNcFt8Yby977~7&+XmK+2SDL+MlE+Ez#8}aW2RBTOzko znbAbE$JMGcxPGsEAlYl6lk=dL?~eSPi5(G7Y@E!un>hE*oVhCQq0*s^vU{faC#i8W ztm-P}YjBTW*7*Gwt3u0xE&Vsow|30gwhg7ekl@6vX9yH0R2-~D#}-sNY{O7G@OKREZUjJ<)6 z*xtMOwbB1L%Xa#4bI?Gs7+eEOjMm5iI7^RDNGy=c6Z`gFJaEx}hYyYH?3cJJGA?{kZT?yYIxWphgA zpyA>vWqzMC7~>CGoDsVy(jVclrYX%$yG_Y()!mbUOI_yPdc!Tcgn9}H|N~^ zw$^dsItC5FYho(SVk~C$vATQL8Dh?G~-QAxp%LN2OapRQT!-~0XGxa8C(UOkTwiY&Z_ zDqCNLT*(f&x2SU+j5^Z2ML zqPua)sjFc*|6gSrgl4Z<8Q45!R`#VDZr|vfmCo6B%dRi|Ew}62jmwU?fqR#`@jtO! z?$&)v;n}kI9YM{OE#4eb$2)n_6pr;d*zhn3nDD2~o>Xjef;TNXC5J09Kv}Xti#JK( zh1A9ps~fQ=Yfqi+_$_4quVaqni+?PZ#us#p()0XRTs66`QN|>-yWmR6W?6P=nOSPr zOzwH!e|OfO`Ok5ttfLDN>3+rEgO5?G!azq=xN0`ghjuL4MFY?ZYv(MKMMG+kU)0 z^QgR7H2QI(-23UfE1s$ByyB;H<=d`=XHWN?$)8ZM^Y?v$3#WVToqh7TXWxXA6E9Z( z-m>=&!|qLw--S*1%e>JjZtD^yfX6UxHq$*x6}5TzM@m|DDPfzxo$%-R^E-iOlJi zpML7kAKBma{8v7n*O*n$_*?PT1doP=%NQ6K*pj^6T^K4Eq8O&WIsY|>fq{Xuz$3Dl zfr0NJ2s7@OnEjT4fq}im)7O>#F^8b2fMxe@=TZg+hIUUE#}JFt$q5n}2RM>B+CCW@ z7#J9Q@ce8DqHX4Un4!TuW5qM3pG=W!xGuyNeSCEEKMxNN&#zybCYUY0y=3`vcWH5hMcfCRB=4$8boBP7F7cIE pa9m#}^-#l#MvdH{M+cZ0gcfUU4(vO!kb!}L!PC{xWt~$(695v;LoxsW literal 223 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4*pj^6T^Rm@;DWu&Co?cG za29w(7BevL9Ry*<9TT(PGB7Z(mw5WRvOi*H=e9OjH}S|<1_p*4PZ!4!iOaobH}W1b zU~svZ?lM=yRjcKOLfXtJ_Zod~H0QpN%@91rw5*6h({?X3Gp;|rdsnbmpw~|+shosa%dU#lP0eN1T)H9d$(-ySL!M&(W3MyH?LxfO Wq)jKxxy``9z~JfX=d#Wzp$P!TUr{~) diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_7.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_7.png index e0a4a7962ed6d8055cdbec20dda86f05ce4e7ed8..2a444fe13b95484dd8708f739d2017ac32ff80e9 100644 GIT binary patch literal 1269 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!toZ&rmwlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(xJ-X<#8Bgo|on3m43>Qr$mjR-_j&&gwVR(lwu)cRYWu_F#l3SbaNhoR^Zk~am9hM{*M2^l*QYO` zb};sv`}Jw{O|kZD6}#X3Tz&V)rbjKJFT^TYrx+S9-u&kfm&%^onYOcc98>+BY598n zQ_*ej;^)p^+b$6*=zpU?coJ{8d75B~LZHw)#&99~ITzgSKU^jBE<3&No#&p#<(Klj zPwT}mHJBaE_io9>O_T3k&(kVdR5ttPX>s2^O}$%RZ~r^RnD5RvLZk%|SzF zubGEsW*wiu=zV&32BWu*LYSlRVo~Rb5?SS&LNo)Ho4s%43fgij`5I0mQM%vHhnZ=PAc>!w|!sK6D?;sZ>Vr+pWQe7SgAN|D%)muY9W<@0_j zWo>Yo5j~NIlOw0k<>bX@Gi?P+cpgliVA=hYhiS>FsXpw|g6tNJ$L~ly&iu9MQ{J(Q zOafiHj~dyeIX0{bz0$v((R5146{*nDSEde$Mj!G0CZWDqdf;eqa0H;&O$9 zY`l6u1e|y@i$r7+rDDIRwMis<%`j0cIrM_1e~MB1Nwe&-o6jdC`>{R^&bj!gOMl^! zNm}76Z~VI&nxC~|<1#nirB`w;Kbw`m@aQzFthL_TV|Tya*DhCWwL*7Q{K|`+cfMcA z2$VkZ=F4aKD+%BJi8UQ7T+}Stu~Ajvdou&qEcVU16Smr%;7yB8$>B;3P?jyw;!RS> zklt8kb)$B|?`g9Gf4krLA!uoQ;V+w|@de$Y@VxRBS559~7%}$7TA18j@;IT{nY+_j z>iv@G@1Nae_`lWR?zW2$W9BS)mL{Lye>v8xu-Kt|o3wnL;@pWB*Dq<#In$l_CFicC z@|BDC-iuh(RqqwM^`O^u^3m?k9T#VQJ9=`rl;n^O-TmRfdz*B}@0touqWOcFL05%GWP_S}Aj8r<~r?fR{;+ z%D$SFx7TYeoS&!g`S96V%f;t~{=JX8$v^ebd*wgox&K%tI3L+AzS(e)fq{W7$=lt9 zp^_nrVd|UnUvn537&r?&B8wRq_zr?Fvf<(rF4sWM@4q~nU3l1f(c{O9jv!-rw{eS5R2?-x&zdzjJ&%9g1nwgoI z`S99T)>jG{xqAvUTq f=qM{QKZDJ2jm2gEw}~?_Ffe$!`njxgN@xNAPxMck delta 213 zcmey$`GV27Gr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uMEf<>y*5`t6nn(`xr`pFJU5CbqHfg!Y2B+Qw|B{lgVbU-o-_?}(}XPJ6lZzgKHp zbw96uy_Z{HF~_4wvl!i*yy5r5H=a1)Hv5A1x)kSfr`O5-t0QXH&9!V7|9I}A>uz1$ z-Fv4W%Bi#b(d~BH?^Dd~g%?_HZTxgsJlB4D#f5cS7p=Yev*cu@#?!M^D;@_P&ik6O+z!mfz|YN9DYdj!FuC6mn7Z`gF}&|K9Hhza^(O@#=YeP-NjXRN49} zXt*DZt)ui7~Tb8Ox)E!Ux)(oy!R>>a*T?E~mR^kpP?NB);VV>TFHx zguE9|zT0~zI?wIS^c^3yi$eP!MGwk@p{Q-UUq4jRchC+ z-1ofy?yNuapW}_U{w;92Y-tkDsl1iH;{3I+`TWIsnJH6>E*=is_OMgD#X8;i>`m3% zQt{8z@=pHMF)#Lhw|l4RTK5Hq!@ie9{<>K7cJ=4ui{~!f{>SI^tMoOKKCVu)(5PGW zW9pn6LfbXX&WO62+4`LivEOp%JDc9bb(1&E{i$$LEWh&0p?8%mv-3DF``j=oJiEKQ z=zGhj(z)$Zw<~@V|McESVg1UKO*ikm81t{%E3mdDe9y9@Hm<)Ezbq?t%Usj@Mdz0D z#_EG|Y5RpQ>=Ai9b5TBvY4GIf_vTMKyXWrre67b?i+}ojG%pv~y}d$pp5#fPJG;et z{<$4Jl;k&0Ub%ku^qHN1ZS;$8rprJ7`scyAXE!s0FQtD|x1V#2n7-Dhy>LgpP zLkow~U<($;FrYz;w^?3pUw?mRmkG5^~a;Uj#U~Qj& zU;2lsOQ@)Wi%Ph`{qqbNv&9;UqL>Qq+c9eVGLoo#&&Z*u(NL_X*t~c6VX;4}uH! zE}uNvhDEOa5j#7#wc*WaUy>OZ7&<&%977~7x1QU}%VfyY_V7A~rmoX2UV)|Rj#Ek^ zpDajaJi_MLF2VY8Qr~=Dql2N#io7aT`|HU`{!>XyQ&OtCG0*%=t{P9{^^b>@p8IGX z-E;e0ULwbqm5du$0z$La{-}F(`&xTwxTj|6!YN65We>kdXtNrGx`s0D()brKTWb2> it1-QXUE21)nT}8O+OuZEDisC>1_n=8KbLh*2~7YrRaY7S diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_9.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_9.png index 29c3868df82e4a2dcbcd9235e337ca9ca7694a57..ff4824f14c9150f8df3ac18572c717b480b5c2dd 100644 GIT binary patch literal 1309 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!toe^!M=lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNT5cJ-XSttX znT2sHo>MPqzhz%v{)<~adyo2Z#a~bM9z3o(J;zOb*5A$dZ|Zv|5Rh375%f;_IRxQbX`{KpEj`A;YTZ}7j zK8@rusxOcAIdi2y5*Aw$| zW(M5JxRc8;&uc;Q(uP?Fa{6N`&dq*S)2f`dj>rEr$Fa$ey%%dg_P-^#;(Oq(Giq{C ziu%@BQkgtOkGb?29_}-_y7GO_mjLr;jB6Se_{~%nn{jqq`;95@x2jIwe89g~d2>E5 zUny&Y%Z%uWJlq@-=NG-X$&$@%T+;Jk^2D8@>E;3nq0uv~Zgf-}=qx+aYuLDaedzAl zgu1-&uPro?oq&|6{SZXu^XgHhHHG#a0>B zT`Mjg7fALoRG-b_K0|Fj)6yA1rz9t*wVacf`*7mtH1nHxmd(C@NNoF-r%j(U*JXTE zoe~jr@@m-18~?6ecQCycQvA3rC~IBjXWcC~f=UUSUlF^Sp7qD+ zU2)c)6}(A#zgn$LXE^U@eNZ^(MFLyWHN%c}M+Vkhc4Oh2mewbD)6^n!xVA1hX7wOM z?uf$$(`~nYCX}mx*EA3MuABEwxyafd+Yc`@(K`=Z_YYfbH|?;bnnE~oqUTGFiB!Ch`yH<`aBRK=w=*=~QD zXt%@rk-qMNWlyhWdwXx!IVvCa=1`{Vl;4+{bf&%#RIKxSs$Y_IEt(+$VU6u96nh@iwqASr_w4VU^Y*+t$Q`$>(mrcq zdgRyFvHTy?D=(IRzv5mgc>n9}Gq2B1HVgjq?)1jZac{+U*`(^-7k)3d)%L%Z<*!#9 zd;H$jEdSGf@8ziK2+xC7G@O*jDg@J*AEy>&6g`tumiec)T^Ivlq7#KJU zJR*x382Ao?FyoGi*>4#b7}!fZeO=ifa|ntGSf_qfiezA5SnBEG7-Dhy=%l^8hYSQ- z_d9!N3bvX%Oc86o5LCr{grRYo=N!I^8`yiT>&z0GLflJ(gd_ux1jQ9!ySe=P&zA{V zowC=Si!!`j&bpvTl;QkiYwH!OxD2%2Hr&x=D3E49kXjwe@V+)*Vd<6Ci#eYiKDM|n z^W4Q0m!ljhGhXSt2VXW}Xc1VF!}jct{@2TUr@i}I!Ss7~2ZuvXU@<@c_Pr(Fmq;A^ b@{8%^UJIq1m3t~c6VX;4}uH! zE}uNvf<>OZ7#ciX977~7_xA4OWik|TnSar1-2p`<#}={H04}E^ z0>LNC+dNjZ?3Z+BUzf00ann}GJsC@OK451|D2_C~+BrjM{paPgCv9O^(eLFm@%6i9 zZM#=bIdtLD`ODD^k1d!c6u+Bwt>F8gTe~DWM4fwpv$# diff --git a/src/main/resources/assets/ebwizardry/textures/particle/path.png b/src/main/resources/assets/ebwizardry/textures/particle/path.png index ab02959d3e63be575b4578308088016b0a6d462e..1e6c9d72fe89240a49dd1aecd26bf04954a39397 100644 GIT binary patch literal 1046 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to1*<|LN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsH`<7C7y;0*~weNZ08Jo*bP|6PTZuu*cTPw^XRj+mgQQt-F1a zP_wAwgIGzSTmA2CYYw|w9uv4~^K^drS^J-v{hX?OPIGxH zvKVBiF<)UxvwQATe8=Xv^$Eiw)e0j;3E#fyLh~g5FPYO=CBM>p%g>df&yFf*8}vHn z-Fe8WaAo>3tFLoa_ne;nRyKmsajucISj4u!VoBjur*&t}VXfPBbi>_CbJwh6n81;& zt>(Q|6Z6e7vsuR_=G(_fH*u$$Y$^EL-+tVt>$1ucNQy zgSQ6keHJBUx+JLEH#+Ouo~L0}MQgqLW2;|X+xtAuFRS~Nvgxh~zimyUuCQ&i`1__; z>P*^q0h4XQvS%E6lpA;OGI?akoiST3Q8_{S%(gQXno}HmOAf3w>1a&IIdbb|%6GSS z+wU|T(=U7+KardH?tTSvwq368l((y2$(pI&<>T;JS7uh;rHvcE9%+@8e{+0$)P@Zg zW!kT#zy7e5@2>rO@=z`($kp z%*@Se*60{BvmD4UV+;Af?e#x3At50lCFRfQ0|yQqIO3p~@aO-3`!jBG8oInomtMGH z*L=x;;TQ2$I~rI|o;R31ci|S%S+|k{s`RJqb2b&g41k9cO4sNznO;>RE_v5@>m!GCn#MB-qy63fq{X+)78&qol`;+01-UavH$=8 delta 200 zcmbQnahuV&Gr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VXe#n8>5 z|Fkvf)8qhVx%!8!aw3N6f|E-07#J8bJY5_^Brdm}-^hC?fT!gl|EDjjd>CdgN#&fj z^emT2h<_93ic2!A(-xf8pPMo_cW!Qv;>jsX)Mt9zo@8m)N}E&o>1nI_J>Fnb{fMlD zqrClXakIJC)!i}dE6cc{Rs8q!^-tUGD!<+PlTq@fgWckkqFD^w3=9mOu6{1-oD!M< Dgoa5e diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_0.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_0.png index 53ed7b630ce95cdff80e074c99115bc77c646b83..9ed0fc9295d595d237c45b6b37762b6bd5d7a4b4 100644 GIT binary patch literal 991 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to4XZ*TN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsH`obD)3ym;@DUFI{A0zF;lL_h-{q_{Aov0-%M_{Xa3h$s>@%mwg2(?!MS&O@diGO zwHCI^_Wk94Q&j8tc$@t9vgM`6H_E<{sbuFVPCJ(H`zD{rkCf$q-+ZcDe`NO4H~w$6 zTb9dy`Dm$iB!ekA;kfOAzUo<iS*+6Vc|(lK_}n3&Yix=t-wa% zsb_D?vL77Bc15`v>uhX_U_Q&d*6P%efa-uHZmn!zuZFMkFf2+xarVsA!Bubm)% zp2CPd(L40@#4?R*A#NC z8B`A4X-d&(Xz&+l5voiLQ+ko{Ab5gh`w4cA2^{7{%sEaT4aqjok6C-2p5E%8CZo%s zsF*nU#vO+S(ZvhuOr)|_cuaWVqSD#rIc<_tmuHaItY?y;CK(|Ym#kVA+0ELmHqGa( zPV~t+%zXwYHCLaWR;kbM}`# z^2hyS?`)8-`yTebPPac>>YedV8}2V*a@X(Gs?E<{kpHak?OpHBwH*JwZ|*wZ@^j}6 z{p{yz{tSYWT@K^xN&@C-%4ezy18; z|Hgmbjcos{4*uWt&VRDnmIG2dGy51A7}%1$-CY;_2(k{+L5hRFFC3&FVG=1_pgk7sn8b)5$3g%>V!Y|KEQmJtZY2 zx2@MwJdmdKI;Vst0JZMM A5C8xG delta 120 zcmcc5-ot3z8Q|y6%O%Cdz`(%k>ERN@z`(!)!W?W23=Atj&Z}c!U|>t~c6VX;4}uH! zE}uNPfLYG^5j&eWr^a7i)5Q!743eHMjv*Y^lM@mW5`O&u|G%D1qM>jDR}w43(OLW- V)$V#-XJBAp@O1TaS?83{1OS1TB(MMg diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_1.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_1.png index 6d792d6d11ca3f2695fac0ac7f7baa3356611d33..6fd9ea9c006c079b20c46fd9835803c00b8bd684 100644 GIT binary patch literal 990 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to^{PT5N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsH`<9$0iofv4@hrE7nK3d;Iuv_U^ui!jWbFMY*j?Lq@DIGDK^LzvrpZvITXZW%8TY^`758UN)?_5k`oDG-2 zWr-)pB;y#IYM+Lr*QFQdzdE*`QCne!@!2+3vHh|_voG!4mQp14V=bxLC^PgY%x@m|~(l(jIkTh}yu=hVKa*O#2H%T>R+R;;hS)%EK{Dcgy^=Sb;hHAl>- zd+EpfY)YPx$u?oxGY&n>jTKTX0T*m$R4x{%m>_+oCT)+%sReFU4??7lI2f2Dy)D_a zd-CrovoC)Lzw<-6C~v{;ra96t#CCqa6Bn>LwQlhV7L$92CI;)vN=wh-lK!_rci+3E zwH2>R3fIOfUf#9aZJBs^FVF1VZp$|8c02ZgwX(D4zlM9g!sjcy&p-ZCDe=9$(Ei=s z@6QU~-&Os*bH%3g_xsHI>pA~Vf4MU|MQ-xnwNXXaPsGIC{PcJ3?O5f{tNQlc_%Hrz zdn=25YMXla~K#HI14-?iy0XB4ude` z@%$Aj3=9nHC7!;n?2kDFMFp8d-mGq8U|=xxba4!^IGz0G|NsB>Y$^v%oH)^OMqTCn z5eG$y3TBCmtQERN@z`(!)!W?W23=Atj&Z}c!U|>t~c6VX;4}uH! zE}uL(ms!sG5j&eWr+ERZMHmAEgQTa6V+hCfgQxBP=B~&lRRN*X2W#dSTkkkMU)*Vqn)zFk(s%1; z7GxzxPHT~K47y(T_wL>J9|2t#Sp&Og^)+&6`C}elA*G`ux zfBQu8x=$%H5lrIs!sTD!KccpdbNr_I{y z<@0R8WDC(VrF|`l5lM_2xn^0r6;A00eCyY!mHO(+GM$hKNe_-`m>Y|K3r^Rle`K_< z#c;)DCjZg}hxawiYM<2~lX1+~I8M>|iPwgdCgWK$@@>`2{+zUs`Dzz6J!A9YuoKvjs*)V4Q}^1J#fr3xGj_%%+V}$vLQHAfcfBsj-{6m zzH@u$o#%JR`_2#JqPzvw?3U&ibc^;ES39kJ_Othq`htzz?!M;t3pX5G5Se!RvGvQH zZ+`EewIgr7UA5<~;>tUh3f`Z5K6CN(Pdhxn&#TGntDAA$cUS(=-+cczXYYDeDfHiW zS8?T>BmaGN6<7Y@_<#M<+|!SD*M4!Dy{kN@|GdoKjNN}4lb<}(%qYnA8$>5 zQt$ph(_MDI(+B(2zu9vdR^Q9h-MyQEfq^Z_+uensk|By=>YMXla~K#HI14-?iy0XB z4ude`@%$Aj3=9nHC7!;n?2kDFMFm+-b=avgFfbT-x;TbdoK8-0VE+IA|Ns6o=_x5G zDF>KmNNBJy=QAkpn$MZ#z&-h)0Ndi12_gmt1`G_kM|i~M{J-qVz`(%Z>FVdQ&MBb@ E03qtyo&W#< delta 125 zcmaFNK9SM5Gr-TCmrII^fq{Y7)59f*fq{VqggMw47#LQ5oL9%dz`&N|?e4edQ|9?H3MuN*j10y4&1*;D* aFsL$e|60ktehUKw1B0ilpUXO@geCw!h$Zd- diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_3.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_3.png index 3f6a9c9103abc094a04fe70802c66ac51a0f2892..dd08a3cb42715f8f780a60a1c42db7313ec5423a 100644 GIT binary patch literal 961 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 delta 288 zcmey!y_w0lGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uO4G>csQBX)Lf3u~b~zkLi03ROT zh-iIcJ$)(urT-WCXX09FyVT5*+h;6XCL6vh`Ti`mFDtmk`M!H;wyt|UV_9d^YRl(O z-u>)cf4a4Ob~KAZOTu9TkL~1&*VP6Mf1}99X=X) zCa+`~mrGqp)Lfuu@Hv+IZ0Y5g^%IhwdVNT7GMFX9e>O(4{?fa~D*2_}DPQMlzjzeb zFv0Lduk{{=mS3k<&i^_0tj(3)S_W-}7wNM^rO%YzcFvi%FUwmky>b5bb2s+h(Yz+g zpn2$)T#|>w0X8B3#+;NsmlKPd{M(Aej!Sb)_#ShzWP>1Q!(y9j$L4rko^Ja-%_fTB zkoN(_i-ipgr!D(`b@~N5-|Q|wRxMxi<<;c#j!oQlEdqxt+@5M&bd`7R2~6&abe&tp zD-~**={JX^-(bE|ms+NmX1dNSL967lHurPV`I~m0%}?x}otJr<^=WX-N7X42Tb4}H z4qs{U&-6;hs%s&|i`#;-*8LQV%DEMET6XKTrMur%zu1`VZ+m~G?yB=wUO2p~&f2nq zH!1JeQT;4~;}zVFj|(5M8w(`6E6A}kikR@Hg`KpNd%|WsTcZ7t@rsG^1zNmG3NNHK zzAs7t?)ok|@7V7DM|$HY8Z+NjKQXg0Z=!Ya?ge3=YZjkiG4XqNV&&96c4?VeY1eG- zd0wx*@24lL-(q$B;K=Jnq8Sv)zkI* z;NDr$mjfp+{FAnK+GkIbRc|y-wbcH}4s5>V?lRL`XVGzymd9zgzRAe2-n?^hWs7i} zm0sA7o5vrx`~PTA$a!nrq!V}Zn}zQ7?bC|$`GSuvelvIJ&myB#W%-MneIVNo(D4XFQioc>rpE{b@04NWbvn)Uw9W6&+O+iyMI1Y-E@7` z=WNaEQ~xq+e!rZ*{?u!aApia~$&s_XS?ph&4LlS1Q2xY0pU;Ap(=C6=vkU!UJ5+z> zS^VCs7hT_MdLzofz`&N|?e4-*$q>ab_09ROISdR8oCO|{#S9GG!XV7ZFl&wk0|Ntl ziKnkC`(qA4Q9;(d{d}7l7#LQ0x;TbdoIW~vBj;fQ5tsY?jXo0&F=jJ}Mjeh-+pv7I zxQDv##6$NS1b8ByR*L*-wUVysf4)zbR;zld#~x3;k=9IFs$E|i)2_*i7-y!2AO z!wSb$PV8+LSjDp`IqgEJ?Csb$`HK6W>|Oq1@2=*eiN7W1{1ZQSo!>yh(Pi^)ZD9rm O1_n=8KbLh*2~7aZtUrkW delta 220 zcmaFD`JU0ZGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uO47qeXbBX)Lf3u~b~zkLi03^krEjv*44Tl+V1G8>9G&tHF%MN?)2d%?rNO;6@4 z%w2Br;~ZOC!U-WSVfpKKwN)EcekgMqPgXhCa{c?^+zW?x= ztwPBn4qlyxY%^xwiA}!~o3?E6?ybkTcJ7YKUZWe$!PsD#F8^ZhW;30+tHr1PVVK1e WE|XpJuZ)3#fx*+&&t;ucLK6Ub-%&sS diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_10.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_10.png index 74f32788da2b72f23b01d0955fe02483a98940b2..0aa5da0231bfbf118d76b86f5d71d4bdeed233c7 100644 GIT binary patch literal 904 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to-dBZ0lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(yJ+Mexk*DpxrEC9&NdiL06BB2?6LaC?+fOl3w;rvze!A@KotuY$vL05+ zc=~Bp-_!Vn>$e%YPw%^byZNf<@$d!NPecQbo#{FE>9eTEkEG>aHWW{B}+g_sHJv9bT(w?0%%H{iMe4SIZ&uK1i zMHGYVG_EWrVwWX?Crmzdh5>>uGfzyHbfj# zFwd%BQ?y%?JFqOKkJrHF>KjgHU4L z(IgLt1aB3uPP1e)r57(A1aByscEXxtf|fa#Y>tc21B?EhhQ~5~ZTfVyXEm!rh!9_A zKQl{&q1LD4i?!{d76r*ny+T0RC$Qu#*D0!XYOng74Kg+@6H|D>XUO= z!)H93qMLHwa(a^|x085}-Up4;=ds^*yq;HfyY_tbN{{(ctFMKutvb8aB=1tepXe;H zS=;ZNa%2yB+0icda>L>NnkjuTuP-HEpSP>@{m$u=Z!N0w@0B}I>(?u`)ltXKes^H= z%{Nj_$4VD9OLi2h2yAy`;5^%W^O=Y;e^K+zX_D3SDEo|5~HdORiFcdGOJS8O$^4@_Z_T3(Q`%k%hAw)Vr^)sp)?>+iJf=l#I- zh3gAH+pFKZFJJzQL70(Y)*J~21_t&LPhVH|#~gy9 zf?T==!b%Jb3{svhjv*GOlM^IZn4DfU3<&xrJU|`_&^l%AcU|`??VGcG128JX2`??tz7}%1$-CY>|gW!U_ z%O_9PW0o_0#Lmub$#}MMnJ)tagRrNIV~E7%4W739Te~8eggQ>iym>+#Gewt4$+Ygq}8|0CJOlgrffch^p9 z>WLTr{*0kQXj*w|&0Mzf>+dX3Oin$L`&(+x5m~%BL-SrPilp5+AW?zKwZy zk!fF7;SAk{t}+`PzHrTwj#Bi~3D~{)@u`{C+i!~Naa{BiKB24R`euvkiTO)>H1bT| z2{kMideNb~AT4p4ve>-e%XY>;?3k;ayv$(E$0rq8Urzm)TxRjAc8T8R&i1elZ#O2T z9>=^GLvDv1`o5*Ftfg(A^j0!tI|eL2BglRx?RIR=sqc3-P2POe#4j*g)epME055sx=zRlQmHy!qCmUp~G5PxdW4)_qIi z*|R+b%h`%K%*Aa^b@HVtsP#G8@GyB~NS^UYd7d&s`izf|jfmEQV^$ABI8Fco`S zvtjq--;<79Q0x>@UCc zdSCMN$t$1Ov}-)tte$*z{&dxUlb>h%=eKWCTDaXg(pEP5_~!mHPPKf$n=dP_zT10m z@nX?9p63m-r%ir&dfqcBl?x}&iusG3EIrm}@NHgg9nXwol6t4Uh&-7sX($`}WM_xq zmU+4>w)Bft1?9}up4y%8Zq>ujFPFQCcdl!?vOwLt)4%w|qFWZPT^EW=mU+#XIU#rV zj$IM|t^^l9cYm8z$@p>7fiE*FW-XRKc6puqZx^9PnOc?33zyv|aftnj6pD3SY<~Je zVC##sMkOJNRhxNaLp%0Gw*6a__W$kcN9GbQjw{YF{{1#!TIZQ|r(f~buYSyC|F3wt zK34RItkS1bybKHsY)RhkE)10nQ4CYxod24`z`(#+;1OBOz`!jG!i)^F=14FwFtC?+ z`ns||<`5JWWK(I2=VV}DnCR)^7-Dhy?qo$iW<>#4dEcuQEK>c?IAW6gkE>cRNuB5X z5Rv6|$ZYMRlWM=O?D+qTU&GErlkq~7G(%K2tANu3X@0Z7;toSThWC4!UhL&(5Da9n ze9l-P)BbDy!8!Dsc%zmKd`)Qc5H*1zu4rD`_8T0U)x-nE@-Lx m_mx9-?e6k|pYc29i95TvE}olz#)5%?fx*+&&t;ucLK6UYrZk%X delta 221 zcmX@f`GL{6Gr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uO42eVxLBX)Lf3u~b~zkLi047Hvvjv*44Tl*IZIvesh&$s9K&hl`ca&=Ybnu!7Z z339KRzI~7S!dj|s>-i(&oM+m!Ri`8#Z`;XmXK&T}8IpU;@9h2I>&BA3cGaq=>`)hj z=QZXjX>*HDonbIAK4&>~CTqdURa>s5yyrb|Z}zoWD^}GQzEg-ZS5x|DcH(lk`(B1; Y*}kt&rkwuEz`(%Z>FVdQ&MBb@0I}0qlmGw# diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_3.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_3.png index dcad491026950949fcfa231909b87b177548aa79..ae54b361085eed8234f316170d6a6c6f31f18cc5 100644 GIT binary patch literal 1154 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!totE)mHN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsH`<9zE%`22b1l$fG)po!v)@45qKz+`ReEPsJlIZ@i42w0tF} zXtQYKpBKVAZg1INzw0Nv{I;B4{zZmIGd_MiseVpk#oih{+erKMuaCvCmzQn+f55=< z%ex}!+n>&FXur+;XnO7L?b4dsed`>qpU_?)ZEVbT+CN<3xVZJ&>dDuNZ`Mbg`(-s# zvF!Qdz2Yj1*(7A8^ZMo-HSLR(5!vy?sOsp{IXvoHEa#O~&avLi&wui^d;6W6d)~aW z6Fqk9sQ|xaR2f%)vAJ={g0i_k-?ayQ*Yw-@dT-YIx0`moQ8p4i8+D~rvzX;L@5++T z8#~l~u=S*FYgrbN&jJARtC?mUC7iqPg?oznV1{Cvz7jKo^E;M zzW5xI&D93J-Aq}0Y4^5Xm}7qSCzod0Iu?I5mc=JOUO1!t*f^K}%5RNWrPbBz7IeEa zIvrCmU-yAY;Fb3B#AoGZpBLu6Vc)>Va@c2cQsd3M=>pLUqH}kiym?SRBLB_OJD#t& z8blJ`F&I8^IN(;)s1%tfrt~E6pt`fA^?7NI0FIcGB^wI$nEF1=kUr1h8_!o`_&9^H z_XG_kEzeC>U!_b| zt;o7G$HG!3QSqpXTBes~y3Z^@tH&>S`sbM6yYp=OhNHe_cP~xjKDGRZke5!-mL-$4 z!^1cJ&0dqV>RL$g;$R0?TdQ7?zddkn@d}l&nwUBer0QFHR1OxDc!8* z8T0Fk7PDIjW6gHrRVXlxN37>BacaHcfpe@yZV}W`FxGD<=!tj zUVGn9PgcLh@|dPw)#7WRmbNSAAN#Y${Lii#E06ARJoD!4afuV(&Cg#cx#INm)8wBu zzMZ%9Rc20Ksw4h+$`p1MpYp0X+Q*uMZ-2V@sNZhc5#dvl7qF}N&vHxM?<&k>yIM2b zI;h&<{>e{o#VnV<&3Wm$@1pVaZ+y0AXFvb)C*IxuQpt<6(cA2*KHt(Tv2HnYI;gMx zzi^OW`Zxc0k@$V;XSkK#ojSG0@r-%?#Q1OjUpmOve|}(}@>zd(;Q1;3d(_k!7#P@+ zyxmB=1wJ~3$iX04q5QOV{? zHM>KowS$)@gG17xhGxt&zrMLr<}Z5U7svD`9^K>ruhdl zWg@0BeChCv Qfq{X+)78&qol`;+02L<@mjD0& delta 196 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 bj*4^gSWl};m$}Zsz`)??>gTe~DWM4fZ^e*a delta 224 zcmX@l^_kJQGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uL(l0~lm5j#7#CBv?|X}1{|7#ciX977~7FFj+(b=W|_<>LN*%^a^no}SZe_M4D* ze&bw61;-7nf$1KZX04n{OrBh=XFGSoa`!5x1*@LS`TH@7VFrT}hfs1!`FDxM?E)>e z_Sf!Ts=xF4%-VCu4}adfaMcV+hO}d;>tb$uW%p)AhaHo+SFJ2AIPu=@9>YCToV+^! b*D|cG@Lnm!!~ULufq}u()z4*}Q$iB}&;nTN diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_6.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_6.png index 985abad9b3f3b1f30b61af0c918e354d43ca32eb..357138bacd7f652175cc4cc9ed96ce420c126421 100644 GIT binary patch literal 1183 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to7gmKtlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(yJ$lk>4W739kw6#%I&(>%UoRYx~D^=FJRulGHZt5fu+tdU)7B`~K3>m~Z^cH}6X_ zJ}Oyr_dA>6szaJ@c5t3-%avHop*2B8viQifBW?o6w($SYetRb~?uhl;?y~5(y2@#X zauZowy4_Cu|BBkZ@9pH;Ogg{^DxP*Yia@}tom?dR5yeXjh@h+U*RFKVHl9B+pa z+s=)yA`JoYvtC^(=lg!a{5Eq0qvKp7_c;moz9}DFSMpwW<{Z|-U6tEq-};4xGkLUZ z6+Jqk;eeRO6sFu`IW89roBZ9L>dY$_PzYW3#Og)|%YjatYsU=TjHgZIH_y{$SSVC5 z@kk*fWVn3J2MF6(c0RugFQdccp2jtM|0UF7l>r8HUG1 ziXW-$XwBq08Plb?bk4>Mw^u!jjg^Y-RZhSAepmb5Z#$OTif{4%=<2NzmgK1#zAmWn z=kI8%Vx@qWkF%O~IY zy$jCs`@4O|$M+|8Hoj9ov9mF6;_nl0S+~x5F6^qdpiq?0*Zk#tHr)2wKM&A{ZAzR z>RsZO-1E>W;G~(a&6T2kl_&4^=${L_ocQRz^YnsU&zXyMwC?IR|1Pxn*SYkqnWkZO z)oWM!6sI5jFZlg;+~0eD>KFY_Qaae}Q}mxfW7;m`j6E}#FfcH%C3(BMFjO)`F-(1P z{%Z~c0|RG)M`SSr1Gg{;GcwGYBf-GHz+U3%>&pI^Lr_$Z*7hl++Fe^o%y0K(UqW&SP_iG(yD!ySfathn+X#3Oc(5TmzuA5 ucI0)Pa6?WQ!@d46hFRHr&+_{n5a*Indf^pba*Kh1fx*+&&t;ucLK6Vy9ViU| delta 162 zcmbQwxsB1dGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uO40kd4{BX)LfONL!_({3{`FgSaEiPy4f9{m9`HM~@wJuw`Jd{A*ZuGRRV!fq{X+)78&q Iol`;+04>Nmw*UYD diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_7.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_7.png index 041dccff698923a24832b1cb31102bcee0665f01..f126d0458f9681d3509612f46cdbfb158cff28a6 100644 GIT binary patch literal 1146 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to8>&JgN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsH`<9y{%^22bn#NLPJE&p#bc8ybt#*f;;#m+)xH+*Pk$s_0){ zez@~sm(G#DEbENk-ml;Fvyp#kO7G`DXRd>f9#8U~V;Hcz{@c7Yv#*yX=QmHjD`Riq z(-imZ_JwKnZFld>cjVnXeKYUTwns0xO1k$jotiPzFrsc36X*M~sPAfPpKtoTVb0g7 z7S1x~u2+jIx_vd^lFoBVD&$QTb7Y&OvN$}(^HG7*?8lk@^Rv_Y9=h&HF1dK_S?cu7 zBFEaE3g}7cTK_!1bv9S*io0oce<%DlJlb5gH~j71x2sRVuOl2_}|tvwoiW;bYD8)y`}BiB}6nKRpU; z@JOB@9bUo6@pb9S`M=Jk*P6uXvJ=bn6`^WpO~$=%bfkM3e} zP&)H=A`d6W4TndX6MD}~Wb>+Um6eg+N1sPdOA15?BUp_PI zxb@4I_x4CV_%F61eebDj!GFx=RQlUJckq8w`2OtW$}dH$q>S0lwswbW|IB(=dnF|5 z%IvGXechAKidY}dTH5(8?QYda^Uv$6GWYgN7jNr(Tes~=+13}c^qmiuZJu;<@|tar z*VaVu-L{oyV%Xj3N^@__Sg%sK#fIzW#iY8)pQdk3x;Oc}+>6c{x$aXob6o!~U9roq z#c2KWP0N$w&ZoXVJKO9($CpdX>KD6d^L~z!`+o0jRp*1w02-)1>*XD)+;-t}JLEtRv2 zHJ7S-HWXiN-*o74mwmej7>kfFfodE?l($?w0h*B_A8U!%3sWa4Qr1_lNO MPgg&ebxsLQ0O*h=%m4rY delta 171 zcmeyxv7gbnGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uMkKeJrkBX)LfONL!_({3{`F!*@7IEF}EUfa8yw;_OsIhXBJ(V9bSGc__b5*gDh zq%<7XJ3i7n{mK28Q`)C*%c2>&I2fb0g?`>>KRcAwA=EHRXo0rLz71>NP0Rgzn$sj& XYw~r!Q~wwk7#KWV{an^LB{Ts5Xihs~ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_8.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_8.png index 4da926fee2b7a92ee7c16d2ac6b767a545be1197..e81ac0dbf9f26405678aa6b508b957b2f51dd81d 100644 GIT binary patch literal 1491 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 d`SB0_ZWJG%e? delta 161 zcmdnTxs}nlGr-TCmrII^fq{Y7)59f*fq{VoggMw47#NQ5@9Sn@U|>t~c6VX;4}uH! zE}uM^okcF?5j#7#CBv?|X}1{|7@Ry^977~7CnqSdq}lB~z2W24;5nas`X&Aw+Wh;~ znfUm#JCC@2+@Jo14X-bYxB2_eH`Lfu^*`RKKX`4!VUh zFfecyctjR6Fz_7&Va6R3v)?i>FtC?+`ns||W@cpIF*_j6vW9_yWwob^V@SoVw{vgj zy;0zCeVp;{|Mc&bmaA?B>fN}}qLS@7^_CiAa*o1{!#dmyDB#Va|Mr`wS9Y0le63w? zc51@rJA19Zz1noFXpLi@wQxxDl-FxdPde3EB7~%CkBqJ3xzb6;Ua#_ticb)nwwA&F zKvC7|sJW~!4&BpVnQXh#hn;DKgNLf^>T6bOA}(JP*lBt9-S@B4YMST&zsX>{uIqJn z06Qbp!~^ELHh*}1STsUT;^JN1(%Rj#*YTVFUn|j=s_h`GeP~+Cg&E5?-P|})Z-M8j zEpgld4`y}g9GZ6U;Khz<>;L>%wMyhcFT-uub(>QaeHZ?@su@vQci=V&P@HQTa_S+6B+%>QxYPQLi&r`gpxvJ1XS zZq#9Y@$OW#eqICHZpWWG2A{o3H#ggPMs4ksdVkC8zsT9+k*6+tu%3Q7+bV){+pnJ& zFNJd^x0X%2Jv+I9m0jbu;lVSGSEud!-gkG?wFe#VIA_mxuDtBq{OZNli`>%wF1xc8 zuM|D13CWywlu5)SS5-qXsk2M##+-dR?&rVPlso#@Ie1&zUq8VQ@=k^J;&7+Sxr<%n zoYpM<7&==$(XOvepIu+dds2{*&S}-zmaM^>xKpnzo;%&@^rdI_Y;}J!uKhm8_VM2Z zZpABVbq(xw>zOBR+mgHL&pS)&8{HnNs~EiHb|&$zlR{ra*ZvB{g8XMJMc#5C7S z>Sh0_4Z`#7&+z|H`Q9L^yJgMis+S5gu107V^ap2GJ^sl!EtAoC@pitMZBN+G+`9aP z-R1an51W0eUTYSdbo;9s5D_Aav z2i4k&RsPuT|8POjL$1>-sebz}6!Pwn+-+y|;qJB1%xjVba_2hbPnS(l2{RDqTZN#~1(SnsH8hNaK z*qS;nGUa*u)4{d-bY;~grLXHf7uOtn*Z20vHdd==8GnL~@b207W~G6$!KI-8X_fPZ z&wkU3saj^?Kj#pWSkSgZ(m&TMuL-?ozL|;d^$D*DJDlqdXcw5z`OMsOxo^3+Nrc?> zlGuqVrLGf<=g0?`DuqV|PrGyY8k=$7F&Qq-W}oo#f{D}qG~Bx^yQkfx!mZNOro5^H z{^# z#l>zqlS$+L>2qvu&z3JR+r8p~Xm#qFOWU^dsGeBRQg!MRvr$!n$KidaKi8Q>JNB*i;K3gv-3J^upxK$;fD^>QfDml z3=|0ob)EP8#jd_Z8c!j>U;nD#5`i{K_aY$GRcu*x8I6| zhD!3a>rD3+xxG!$>BHZ@zO$C?*|Wz$uK(rNsyXM=A6Yyrv6}eYa{vDQ8MBU^Jsg=e~PL*8u`qQspr%J4ruFGDe;pF8hz!EX-=+&#DTn)=IdDxgw zZF1po3=Q3}?)3BL>fgVA_t5NoEOFR?LBJ{Dw%J@i_NULEvo{#sQeG5-Y(r#lLm)4<;O_+wbl< zsb$wXL8l4JGz(>vmp=LVbLP#Qwso&FW*s|xn3-Yr*|x(E9YRA_tm>+$ub;jwQ|P$i z?YClw4PJcz-I91BZS%s*FAZe)DyyrL?dAuEie}Dw^xG~q@?Z6%`}gH{t$Vyn?`+y+ zoAZ(Dub+8d{K&$Mqw)2wAN%}6Lw(eQyB7V}e)VUK+hvnQ8jCK!+z_?)L#=#hsD7E* zY~EF?9$E0EMsB+Q{-X`Qrs|`YFFlVH_N-cUrL;Fu!lKVPP(*xd_tB=f_3eu^JTw_C z=AZ9zQ=U?`+jsFrhwG&wp{nPLA6ck*3NhIUeOBYN&}EZ}L60isrloF-TmO?^ ZxnSDr#qw^q85kHCJYD@<);T3K0RV98jdcJ3 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_0.png b/src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_0.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb6fd3b1c4c2d0de9c9326cc71c7b8cd751d5bb GIT binary patch literal 1272 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!topH_uLlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNT5cJ+|z#22b1j$fG)piY!T%Gv*hkv2XrUdGLnkoGo)r?w@Tr zmcZIlA>SB#`QOjov-f`}oYwqN$aIN-j-B1lCq`0P-_OTQ{`z@W-kXaR8)koIXBS@l z?629DtM-TWwliMT|NSk)e4~#2E*aT*)1Bpvtxdx0WBYErEsOfDwzlx*ecklh+uQD3 z`@8)0-hP3_Tz@tiuQS|u)U+p3La^XbPgJ35-(ulYIp?+aUOPAEYqT?Vo<7$f zBq1HvUT`tvre|EXx#+F{>$JKb3$GP-slTmSf2;a-`1IO_po42%WxZ$WmfTTLJ)g*^ z`bazDc%)EQQYY&Xt&BX4qXA0nTdgZsO<5T{yL4fbz}{@WBJ1Z}k28Z$%#WEF@JHiH zEX%wshvS8erfoOpZoDwZ{OnII&9rqb^ZFk2s2%qQtbxC_S{=T*#Vmh-& z%TCsV3f;Ch9dtxaxII@AED8B=vg6Lia%qkU9jjBUZWyp12sD3oY=+0?^}^d{7j9u_ zDL9~ZabqLH>1xM+F6&P$)X}-u;W0r&%d_aggXR{2B#HEpKAGAn5=lK$!Dmjr3N^_H zxw^!1=MjrTDy<^Em!<@rn_+Ue^w^6YIm`UK$7l05wd&^WTB<9)#Q&qKm&V2nPu1}7 zok_p12P|G06@0c=Drn_THQg;Ywk(}yU9`6Ndu-K);u%x(>>mz=9#{Hvz=sCOysec%4R6=rFTw= z)y=ynYEPf-sPCTryK9c*i+?PZ#us#p&fkd(SY2rsSivNq}UKf>@>a9&O?O{zT@<))@`Qc2ZS!Sw?mwMv8T9O9iRFhUwo!kqgZD)RFW!@V`sf zV-7)4LGCDXh3{yN^978NlADwK=<>bi2rmnO{IAT?={oQx1-vquXg;h<|-P?0B zXwO0IBf>|Vg5Ed_TsgYlOW~-2XFzCh=;OmZKa3t7ouJh6K}KNWGL~e0FHMFeQ&!zO z!;?@O!*w9FI`_$e$;EX$1un4S3=E#GelF{r5}E*?3t)Hv literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_1.png b/src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_1.png new file mode 100644 index 0000000000000000000000000000000000000000..e68d7c8007d3d7ae44a054456144028094654503 GIT binary patch literal 1246 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!tok5+|5lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNT577Cr5?2G5`CT4|gdigKq9+ML^IJ>#i=W9Q|Km*>7a_jlF= z2_5d0D}*er{QGHLP*wN3@6_u1akoFb~e&SCor?FBt&#G0RqhbwH{J@>lpQd9li{HG)LZ(F;e zw7z6tIb%wQtIfug*&8Hc{+>{BQ1CSR)uHVz;g?Ztv;NN3@>G_`D<7}CX#6<;mf(u-fxFJA$;B{Emo?>; zaNb$iD$eq7pT*Ua?{mH^%sa!L$jbFo#6J*Irisbl;WUD}O!Af6pv3S@K)@)Wr#Tn&nsDc4nELH}CRkJfy8renFW>7KC6C@*zhF1%ub9cM6xYiAE#FvlY+Zlz+}Zj55VvGp z|J%z=e+-R&O*$^GuvmIa`NWH>Cza+ZerUsa>`t{fR z)}LIN7?|tjfBWv4)l5tbyU%YwAsi4t@5mS3qx%@U8eXk$sQO-7@?=5w+`oJ`f9s!M zZMoS<^SH_ka=k9AqEBpwj^(N7lulPD2AzT&VS8eU|`@Z@Q5sC zVBk9l!i+m6X1`@%U|=ut^mS!_%poW$$Q@;_yoG^*VV0+hV~EA+qm%aX9x@Pcix((u z$xv2Q+ps;6-_0RX!Fq<4Pw_nlfn1?Y4Vo7`6Y97uj;ubnN!7mgyP}e(i;%q0LvJqG zD~BxE57d}y=gChCX@cA<5e@=dYyxH|F+n=oUsZ6iCd}NNmq02dYzHeju|D1`@R;Shdj^Q>21_lOC LS3j3^P6}S&~gEZFs+W{FuB^`c>@`y@`C*VIAG>*A#jV-m!4z zZV8B=ajWya%q#DEFZ7RaNo)~**1+y#m9MsGsq*%ePdXPi-_qDSmF?#)9tNc!+c?@- zcrx6RPEP!GW*&zH+lR>lmfa6|*iJ;PTVl0Cuuwt$!-rnmdCT;o?;Xj|RXEh;Jh3Iv zLE*GS_n(hy3hk3bv!`sm7Mb7NYi3z^Eb{rB^2P3|`u8ec&;4%q<3;dHZF7HU3tZ4^I6mTPTjhtPok#h?RvZJw_Mem%=FxiRp+JV&Zs^srF)GnIqlWY zX48(n`)4k===bIUPtQh0gLmxA9vO0TUOF86kdRlfOnI?}PP6Hz<~d%?h6Wi@8{cjz zE;sl-$vpM!_KL^pXI47i-Jjsc`%0`h{GQx~u*)@zPpD*sJUkHM?Vj8m^r*r9%j4sl zw=CcOEpl&g#p}iSi7W0OEj;ro{G*KB>P4G%wr=08axPWRvnx8O^r|zHkEw2;zhK3y zJ(g#-dRQNcPuu!3^|9agD8KNxyLYy4%Y7wdweo|{`lG&UU!;A@@Q$e7`|hQ{c9ryB zOMi7A?OznSyujVoclxd`Gs-_-T4vI1-K4E;k-m#x`tM;UuD3mny3Y$97x!H)o|GG{ zqAVAl_w4kv6DzOC-qqWpnzF8FO>Tizy74rN%e`ix9P9`glfE?RhQ=XcNK-HWD7{v|M%c~bk?rH`dQCGM=daQVwpmk%F5 zoc_MpFIsM|m)YNa$8$GZsbAYJuzR1v`p#qd(YOAtk*h1^uv_ur{q|qn$Lrs&E}DL6 zBLf2iTavfC3qvJC6vNav=fCDKFfecyctjR6Fz_7&Va6R3v)?i>FtC?+`ns||<`5JW zUXV`A_jY0>zk9ckTtaQ_8 ziI;Xq?y8L*V!i<`lYXq0y^(nT&s_agtELDs2tE|&%~-iG#9z&G5rhANNf~?Ou1YPc zWO3Ma(n_i0aRg(JAw$Lcm07GiWZyFx-1TSBSm%0Nu4eaxz2Oa)AL%fxKD|l3Y5L9k z*BoE!yqk&IYkJ~7sAve72H&3bfbruEOP4+) S3uOid1_n=8KbLh*2~7aOpM`Az literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_3.png b/src/main/resources/assets/ebwizardry/textures/particle/vine_leaf_3.png new file mode 100644 index 0000000000000000000000000000000000000000..2304504f0f26f666b7e0b3045bfa71c1078e99fa GIT binary patch literal 1195 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 a_BFk`r_5Fj3t(ViVDNPHb6Mw<&;$S)#=C|9 delta 2189 zcmZ3jJwtGUayNrZ*TE7&r?&B8wRqxP?KOkzv*x2?hoR_7YED zSN8in(juyYUn~yQFfeeadb&7xXkJ-S~eT(ot6?YWh&*6sUV;(yF|+i|(}1oe%s zE-9LvLQNCYf3SBf@0c&}kM9wqqF^1vo`#kQ2fP-sB)zF`sYt7NzjMd(<-1p}FSVTA zo_D)2t%7&?m7vhACFfR^UW-c4|M`?(`RRWPnFEjiZSQ}W<2;X<;e|{(Lyn1Ty7Zy; z|7I&HjxYeFe|y?jPNrub zGsBL3q91;r=iSD=tbWmp7>7SaiIEK(*fz2~PATkv5X$+QwJ7vY$i$cf%~~B!djlWq ze{bs$ulxA-0qe1|muL4bdwh7d*v17bgH}W~wJC@l(Grr#u{;pU9CP;JEX71!l?)M% zRfr`b6$?W-OIFN#YyopY5IVOPf_~ zuBDb(@D`J>*&Z(p779(#Is8w;@xmEl7sh2N9!VP8xXx5-+MO(%bof*AQ6??@jE9oU z^*d4zzIfCvE5ZG7ujK3eZ5ysmc=n5H+Zzt^FwHGpQ*NnVTes%&oe0Gomlef7?mX~P zTqh!Q#i_}wW3||Xfa$jwg%7;{H+6nJi-MBGZh@Ja4XZiU$rSCdefY~i{_r*L9g`ME zhK&zBYCWF{?)X}S+*$#eiKxd zU#LIf!R&4+)b>63P?kr@J)_s>PNeTDxX8)YlfWaPp1@+*m&5h;{T0qE#_w|SAAVis zUG@Ch2G@-EsN=4T7k7%@ijMvweE!+h(=)1EN|v3x^;EPdaMkP3YjOETmZv76=H@P>XY?y_b~;!gv?A{ox5tOX8T;b zsb5XCp7-LZf1UAb)u7d0H(8VaNs8f6ZNdcUpVly38JmlL;Y`)qi$s<&)+ zYko_N&E}(CxxJMUi{mu~+-A>Ny=`X7{EHdeFRn~Zz43JZ_VSZzoa*0_}JJ!Rn8*~I16KB3xcpTmYcKc)@GbaGzsoYOj{@%L}b9hrcCBk?hD`Vr@$z^?cn*P z=juz2#2CvhtDccGceVJr%O~?beK^PW`QL=UcbPB!n^Q95!hPw<{+ohxGI)CAVVT|YZ~7`d-m%J*FJ^Y+#e`RVFCXyrdQCN7AFCK= zuk`L)N44{@y@FC_XUg^Z-zt#cpU)^bH8q7x!$TlYW3A8)rS)Rl3$i$_76-Sh*gY?{ ze-c=CM&V`Q{~v053;V6-%J#7t8wIOtt}!U)wYn?0_^;;WbDBIIT!k{1HMUN8T3?pI zHbY=>+sVo90&6$j-tU|FR%&w28TC&c`Z@EbvD`Ve%Vy@A4T^%>t><4>NHDWYdhf?> z@8{uWJn699&ohgwx_GB^CESn~@N(IFhh_bX3MVUr8BUYAr#UxJt&v9+@xgA;em`-V$@bF6gLhIiW%WA%Cw_hwK zG`qNd$&Y^>?cb|r*r-b{&5{3_vHt3hSNHU8nkdg-I^nk}gC*~QVu4qV&n#c*+pDRW9vB&mTTVBIo{T`A|j>ACVg7f zmFl9ollp>xEpBnTJK^YQ%VO8RnR)@tb(JB%T2pg4)#hq0dm#2dwaedzy?mF--=K=Hj5Fobg6r`jOCnFLng2-1J7Dvf{!i(}^BF#T+u0&L_s}HP16nsj#Ou$` znw-91@-mSMBCM-?3Subg@V0TgTRpvw|%bEz@9E!irMkc08I#0WS8a4!9O)h^Ua!z&@cJ3guEVb3D(7`=?wn+a diff --git a/src/main/resources/assets/ebwizardry/textures/spells/arcane_lock.png b/src/main/resources/assets/ebwizardry/textures/spells/arcane_lock.png new file mode 100644 index 0000000000000000000000000000000000000000..6df7d7d8e75c4476108400e8807c33c7adf4eb3e GIT binary patch literal 5300 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 M>FVdQ&MBb@0Q9sSE&u=k delta 2386 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 TU)*N~1_lOCS3j3^P6e zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifamoqmDHgCa9b{nONc41Z42d{=bb4k_ zY^vrQhaiN(v;JwdiGB<=9H>`FIZr(-+|%59#Ovi6^;hSN)B!{>j+|a z(c&b1$4N)}=?)IIWS#_rMFC2jiOCKvIU*n1>!%8|L|?aZ*IZ|1e%RJ*e@$TNK|#mY zPgtc478xi>1ZJc*K2BV!{6?c+_G{u&r8Nq@Q%@;4Nx{$FThF{R}`m>8y zxh}0pdL&`6AY>8O$0Sy(`1^a8$X2UNG@R~zBEsxg>A~-w-}yHdUCr88dp(_F+T0G~ zO>?62_f536ua*9HDf9>PVT+k^Ira`W`KG;X(y05jXzvV%=PDDYsNCAb(5I2)`9ws& zmuqvv?mq>;^`_}bK4OpGGq)f`wg1oC(ocVzYaaLc3+hGsO^`p-U-dC4v+6hd23!8r zzx+%J3JER_A(I-C7P=<7H0Cb;)4(e}r=RN*!;~!EFdp85`?=N(ZVvJA{t?^2yUA>gf1@DE3hX>((?b$<%( znVua}`LVUfPxR*BTNcmPTTT@IRTQ%$O>}qM{Dk|jljm$M(p1-zet7nf$-L)@mV9U3 zm|GLyddv-4S}4P$)Da=Uc*JQ+t9+ZramSr<8&i{8CFl4Yd6CoF`}%xp&aM;d{>vo2 zeI*=mYjWye&(l9I-%$B4H$NrklR=_Z%3aCq8S~a($lB(x-NHKFN{%tpeA<#HQ#J|S zUM46#%k4r^vishOz0DSX4_oZCNuDZUF8Z)dako47npn#-1$t+9T~*((KH%Xr{yAqe zK612Pl99ewE|u@+vp|~H&tHB~NT$MUGnTYH88>XRngx5jl61Fmuj{tZyTNygd&41} zygJU=`Fr|`ug!7FpK@?pZW6QcRIB^pi|p>qW4v>R!B4M$^6SHIWuMIdJnQWA zb?KFMNd~eL{C|E~V&fNm>G;2umT_}+KHqEX*z!6-)Ad%lW$8->ecv-ic4lsiV^UPt z2d**^lbZOneMLx11tVMY4m9LHsK&AlZ^g>&oPS(5<0n02b(dkY}i=T zt13C4J$`P==b4AUq&wMt`M3Fo*{@TN!eVC4e6;cH?ZCJh8V@RBJ~wXd>FIe;QMafe zHTkz)t?gc(=hY|M{xvbNJ(JQ^I~Dq`u3*+nWz%cCZf|NNZF{(kBl`H)wSQuMqtS1@rN`aAT-bY&$TqJ7r+d{l zUzO_rm)tYwdC^(P(~=(5clM+StmU2j+5N_+FP}}k+E<>NE-tK)mzd=H@&ZeQSzx@} z)vN`pQGL5DS_twpW6 zyZ?KoE<50P_^;2NnDt-*(A1fp=VGs&e_UVF74*^I zNx!0k(u#LH9x;3p7iR5zlsM&a)9b``$yr{ipBG(y@X2)bji0BaH7*~&ZdWGQoH>7c z`tu*x-hUUGA!dKmu)$R&norV z%y(8z`n>I2+4?#`^Xbp6ug4zqn37hr?aW<%+t$Ui?|eB}JY(LxXAh6dJ%8{oGV5sM zv-IT|a{BB-FNJ@n-kNrP%i0cxB$Fd+RhqXx`(x~v_Iuv*f}+1QpWC!0&!t*e1V8!A zZ_{?kaQ@#DN4LBx-DdYE`pX$bsi%^UPT72YWwX}p?++FimdkP{nNGS)IilKeF~MZn z%_CPwmp+^;E&{cKwGJo~Xp%|D~`i?4fXY%%O)X zJ@@VYn!bh4|B{y9;@6=id;3(|!Zu&rmin!*=)jh@TRbLlU*dCAw~_F<<08ehs%zz$ zkJlOv-`$;5;go4snQ+@|)zmDfqJ2HB{aC~x!^{iRD^}J;+F50^wMsM=j zwA-pDnuKIUJx;ku_GX%1oNAeIMPs^`=L`dlz_)*1HgFxWQe4LCb@I{GHJdl)+!EN3 z>i=_vy~|FSV;5>QnVtp}DmuDut@gMb*X4I$>E&+^%B#`FchV*(tl%C`im;U|?YIboFyt=akR{0LzLooB#j- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/combustion_rune.png b/src/main/resources/assets/ebwizardry/textures/spells/combustion_rune.png new file mode 100644 index 0000000000000000000000000000000000000000..5d883ec8392685b0577b14aba852808af9cd217f GIT binary patch literal 6199 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/conjure_axe.png b/src/main/resources/assets/ebwizardry/textures/spells/conjure_axe.png new file mode 100644 index 0000000000000000000000000000000000000000..1a50b0e488c7e1b8fabff07456b18d1c2fdc2fca GIT binary patch literal 4557 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/conjure_shovel.png b/src/main/resources/assets/ebwizardry/textures/spells/conjure_shovel.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3314933e92cca6108fa60a80804a1e0e8ec960 GIT binary patch literal 4317 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/containment.png b/src/main/resources/assets/ebwizardry/textures/spells/containment.png new file mode 100644 index 0000000000000000000000000000000000000000..029eb68eb854a6450004c4bde0e9e74d5e854538 GIT binary patch literal 4994 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 QU|?YIboFyt=akR{0L){vp8x;= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/curse_of_enfeeblement.png b/src/main/resources/assets/ebwizardry/textures/spells/curse_of_enfeeblement.png new file mode 100644 index 0000000000000000000000000000000000000000..2515ec506127ef198b850afd75ad4753e458b890 GIT binary patch literal 1726 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}3>g>`I}aaX zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifa`Ff$NGY8<_>6&p&D+z(F(l&f(d&2n z@1%;de>h)R_j%LhckfDWdwFZKPMrQjDBIPihpDr}P%+M<=i}2;E!zJX5ARPhdDU9= zRJB~q?T7-`L6M-AhSnf4u~XY}zSlncE~B5e?QZULY2Obj{%OyC`aYZU{P*8^pKI0R z>I)|P>%Z8zeSOUz(>XRG*SQ;xo=z@ETKM?M!Vm4~hu7xbIIu{|xYfZYex_$1*KEOQ zr=OHBVhPeb`jKZT=lXTEFK)-bczg2m)oSsWh^W1B40ryoTzCKP;uAjV**}WjMxDBr zv{LDC4DbEx-zQz$eDPJv3%8A(j;B{@#D%(Q@`d-ML>x}%>oFM zes;v^`1|?UDa+Pma_dV}2Wo3?`q9)keM{VArEcA$M^o0eS#J`QOqpnU=33H>qfyKJ z+IBV<8~wZ*zis`&{q0SY+mpo4#H`Bf@lSuO5jXLk1kW1PwFL%U?~b(vAKDf$x%BGA zs2;BLEQ`rU_y4+j)Fap7&XU$_jz9l)wk-)^n<^YRXQgbri0#7%3D*|z^7kE{o4b&A zdl|n(3H!a^J*!`&B~Li&f4q17RX5kONpp5jnf&M1%a3PS-yCsj%fB+Oee>%{U-IY3 z%Lqi?xofoIVV2nEtv^zDeRb;sc5O3xci~5z*)?U87aaY)UB8bBM?HJiCTBe1Wg3^0 zN6w>|5Z_HXoBFmttgtp(ml}?XBIZZVB&_;~l~*NXd(Y4MTE#b)H|_PZ@Y)xtYnu*t zxyxQjyB^)TZOP-Qn`P~8oU@I3@y1X8<--cIbq{=B8n3dy^`R~IarU0x(k1)sZdyI> za*e(|Pyg|D3yIBD7ccfdlD(=?*0)ohDL5{xrQExsJVuve{ml>0);$UMxNYLP?|YSV zC9}(I-u%K-M*)JhCSa^V)~;MlE#HcF7%|$f5Mx0xwzl?+LvDMie)B7 zmu%QBdsg?po4s3sC%P{0a?i0hJ6^rCSQL?8Rn>aj$R_y(@5|=cSsaOu_hZ|pow1O; zy6aWZl9@h%6;;`1OP$aBbvd!w*SoEER@f5Ot6c_p$K_`Iy4lpX(Rs(CNxGd2_gVAw zex2KyrBW*)GnFr;RPRQ>cUjhIfeDjCm&fmz@=|!Km8y>BF{k*fuXoZi4tGi3Nk6w} zpR(%NwAVAf1gwqvvzGJm*;3mxk1z3B-MHLl>FQ+k@ywO(Ejn|j?wfS=?ICNyUpK#2 zw%7QTdLCzQ?Fdog*(CL#pr~Tc+uc@r+Pe(8{!BNyr<=GrM7;U?Cads6{l{MRS{3NocVQ#_qh=B_eXdGhnc zsG0Y^{*$>{CenZ9)z$|`{W6k^idMN0vA9hCB++3Mr8Z>9!WZ}3uettp6jyz_&w9;#f@^=pX)#uz_@6B+X84%+&@ptLL z>+fZLzW#ZS@9U-wYpOP#d@VQcWz7aF-zc@Kvlyn$`dTX8C2r8-;eGK|PLfk0r>5=4 zxy`@tcZ985H)HFU+hLbeY}uVyWYUbI6dQ(LX|&73_` z`Zqj2dOEq^-r_^|^02bIQHKiZG_v2#j9VRi|Hk87!D;1DIy(f`YD}J8s-mAURjBUU z3r6v2VRNm_s*RcQ<30QBEg1IKWED4^I(2Hw=778zO4qZxUZ0vLV(_yjpI2ISZ%~wf zP5Pt{hc4Zdc6{^4`rgVHkGtkNS()e6-1#Wq7<<54JttI-fq{X+)78&qol`;+00?JY AR{#J2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/curse_of_undeath.png b/src/main/resources/assets/ebwizardry/textures/spells/curse_of_undeath.png new file mode 100644 index 0000000000000000000000000000000000000000..d36d96f3c24e4aea85566cba10421d43d0120e71 GIT binary patch literal 1990 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(~)RTp0duSK0la zfq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_$SuIYuh8|`f{%fLJ=oL5F(l&f)akeT zWx@rI)rT%${(RH+n_t&m|90zR?+uH-w>OHE8XqTcG6o7UKH?P+aHCgX1Hk(^z^F1giNpFqc8>{f5ZDyl{qvM^6UB(+(#nv6Y zz$+jg<8Y-w{0^^Up>YettDfGTf@e~{zB^bm)c_zukwg>x0%lk=8?O`C8!C}|O(M^!)I$Br+^nlJ z@60c({FlFEW#CsuK6$G%C${M=7CyFYuHV*Y3)u2jxR=acob0MrY43WCLC~F5#8GvU zo}yde)dL~5*2e9Fm|A(()8RjU|IRly zH1*S6Iq}ki*YUsj=GT6!eD%`8y=?9R>-~q`z5UI}D{+_8lgW`=WQ)VLo_*`DI6bNr zYU)t3XqwETs1Xw6p>=Lq?P8l<#rFO()(7qF_nbVfzyH)$>+Xtq#-?UR9x_{3zWJz| zla=%6jbS!>$S7JRy0X;Ja1uObQD^lG9hdZuXFGky)~b1 zvFCrhJbC}}t1rLxpWC`SW>;Bz+TzVxj{4YeNw!T29b)&6 z>V_^|3?9~UUrKu&n43D|45kov1skHV?WFPpAB}O_wdb5`v)@3x^Y z*cv6+DIg%&%}zLa zb~n#A&gSq1O&uF<$y0-5L8U1z&DAWp-L3by`1A)oQMuXM>4DXx5#5mdCB%?>+fr$%oDJ z|4fko|3c*b|HncJZ*CZ#yuRUDTdwudGp3mj3KPWc! z+#aWO54`k*CTjFVFEsHu)4U`{!89YV$+n8uqD{1Kg7b5;njh~{{a$-+^L?NC?v=0J z+1P}lD(1@TGxpy}emHI8u0<&`lUg5syHxZf^rA_FYE1&1>&{Xq#rZDqy z?2fvNKQF)izT%{N2Gh*)pB85>zUJCHZ^N!tH?p4e?Y{7;B-yOv$bP2BMuL+TIUGMW zX+@h}Tg98_XOuG1oTfFebNJ4-=7pEe62&9SxgRw>W!gDOS*K(g_cQmyi<&Z?xI|W8 z^UzQ%a^x-44N|o$HjYUuH4)r!pkkl3FxXr`rsBFrCAK&LmCw+5ke>=PFy0)TF`VsN|>kJi7 zzorVLFWh?L{fsF}4NXT<13MSra9F>*)>2!hJg!PnYR=w^k>>VZma_Inwtpt9toRTa zHre#9M8#%(y=>b0PT`M>K^YTj4;Tk!RN-}C>hSMT}r+h{5nF)%PN Nc)I$ztaD0e0sx@{s$~EG literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/disintegration.png b/src/main/resources/assets/ebwizardry/textures/spells/disintegration.png new file mode 100644 index 0000000000000000000000000000000000000000..0039d680a1c768c84cfafc2dcb97e48482da9078 GIT binary patch literal 2076 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)4$}UNao6ombk+ zz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||~ySecODGiQGnwveQL|rfwk#$%T6#donLi;w&giGyeTmL&;UT(Mb zqDk$_%u7o=vnPAyWMudF=B|3Af8dzl*4CzmKQkH~XY90p_Rk`Hz1^E?ePg5At=5(| zpTCy5^Ua{*{Xv^F zwzQ50;Q)u{XZ>1EXfjz`{V-pvV}a6?)1qeU&+8w!S@c>VeYw_kPKG;wTW8#t6+FZ9 zelx=xTP=o0mNMBpoE9o)o)v1jJQ56?Qz78!5_u{9(cZ_RJ}voo=Eg6mn10~Y!H(yB zT4{3cjhU7mzjeTmA)oP%LYDhG0~xn9UMh*PM;^Nfh#qLRX!}+D^V=(~=&-9lO@B&r z_V93|$r-R1ybpZwuPlv+@5|Pc5)&QvMmaWkv~c*VI9>8=WZBe_^yufgTT^VeOYW4d zelVSVH_MjKpY8;5R+>2*h%j@jB=sEJ7k9--$w)@7J$=FUBbW9Gv6_D3V%_@g^5X>y z0!ogBy9dp?aY4y^AN$UF{qr^1zk9hn$~6T9IJ2{kImG9Shp;}{c12LKlWXZdrL$2} zZ*X=>O>}z1a`=YrtWRgZ+PT#IuY2?0@{;9hV(JP)S-b~4qpKPtc)!XS`YSzLEa4H- zanvKEQ|1U)r&Oo#oT|Kd&e?9gceWj$IQRF15AriA|LVusXm2RVNaRY1i*{w2$hEQU zyNkl|3E>@QCQm+>EFw~rr1SFa!Ub-IO>*gXOp|QNW5@t9lum1TQ0oL8=Z#Sg>&T!k4%)hBvU#6z*%@vmUaSh@6TE4+XEjkvK z_rw$*xD;ru_^zU75xuCPNdz)CH;&iQ7ng30*{ogq|&Ep?U6)woQbn#O`j$dYl zqUwqZpC(9kYcF6@a@rcB7Tm$!bw%5kO}M@P;j)D@vcsR9;O<$gd2prnm%5*JH+IVZ zetiBzdjH2;^$+H19&PBE@O>KR%F?t9$!_fjAnZSwb-MN`ve`&g~#6vl)?bmAl5SNZ$TEZna5Y4+wruVNV9 z*ysvxD*Gb))3#~;@&l#nBCLjU9OrXAF4sAzrMtpxXJ*a>-*mmg^RvYA9$ResnYiSa zxkWkG{rwXcyWdkcet5sw>9TWHV%|3E2U$D4gfo|?ByuhK$>njI(R|ID#1#UDMW-2B z8<}opY$#3P%e&ik_oIQ;N2PoImn|wMhTF|a`>gf&hic+BF5Tcg#!)ksO&@0MycVi3 zd4Y%8|Ha%B0xYJ^oN_g}S!efawUna1UmJ~gtnEMacK3$Q?Vk2lU44BQBq9#AYA&58 zKJSKb)b?qPm$gs->Rmlm>fSo{xw9HxJ<@bAnbYxM21nt!gk4UC)0b~~SGMj*_Qw74 zO9JfN_fAdL_kAGWLv^XfPE3GWD7$>^rjayRJEHQl$;K|6Ff@3GuhyI?r`Otbh=X8Rvi w`R1>FI$Ldj%(wV_c1efJ{Ma9Rj@L78_#ApQl}DhAfq{X+)78&qol`;+0Nh%}lmGw# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/divination.png b/src/main/resources/assets/ebwizardry/textures/spells/divination.png new file mode 100644 index 0000000000000000000000000000000000000000..bf5999c6f1f99cb4ac90e164e745542098979653 GIT binary patch literal 5844 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 L`njxgN@xNA61g21 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/dragon_fireball.png b/src/main/resources/assets/ebwizardry/textures/spells/dragon_fireball.png new file mode 100644 index 0000000000000000000000000000000000000000..3baa68e86fe0f774e376b543aeb50bba68e3fd8c GIT binary patch literal 5692 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 HP6(_s0 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

    1bHXwF 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/fire_breath.png b/src/main/resources/assets/ebwizardry/textures/spells/fire_breath.png new file mode 100644 index 0000000000000000000000000000000000000000..0e0ee447f6b111b7989f950fb424d1eaec4fd416 GIT binary patch literal 1938 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 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/forest_of_thorns.png b/src/main/resources/assets/ebwizardry/textures/spells/forest_of_thorns.png new file mode 100644 index 0000000000000000000000000000000000000000..16fbe282c1fdf5c40d22608d4308735e69cd278d GIT binary patch literal 2579 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

    SbXLg+mpIAfwzn`xEs1Bd5N5y{7~cC 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 E0Eu@du>b%7 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/grapple.png b/src/main/resources/assets/ebwizardry/textures/spells/grapple.png new file mode 100644 index 0000000000000000000000000000000000000000..da78b69b20629acaa3e2f4ea385647180a60e011 GIT binary patch literal 6134 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNP+*KhFB|(Yh3I#>^X_+~x z3MG{VsS2qTnQ06R6}Q&T$eecjgka16>zXw!w>C|CeC5}?{0EPJb5D4cmsw@9?YJ+e zisOQ5Jtt0h?D)LCKJGjJzo5*ssjJt139_l*`CN`&epdb8z4w~Wpa1x?`~CbM|1MX4 z|LFWA4w@>HzsbKR^GHla#tk9wb>p<#N@`D4F5 zEN_0_SS&AJ&w20o^7y3Z$A8!SvJ^Qt{X6T^=@NU-v;Vd$^KaR=PNU}BpUeDWf4;^4 z-*@EQy}R#h*Wc}p=?E!&@B8=0sn4C<>I;3&=eCAF-T!f?-THH@Hy(ApV4mR@ce+(h z>Eb@cc3HO_4{hFS>r9*RxO3`viEy9uJEvv6DYRXXviDH0XvH>f-W;(Ns(#1&x3;9; z`*&u$Q}Q#}9Y$C>$d%pvVOP4^M7nv>F&4t zj&rhW&8>MeCD`BkZx8qNyj?$U>2AMQ_FGnd#ooZbl3PD;7wvb~-4iIB^mFIBx<$uc zM%D8Os;H}-anO0j@FMfEc^?pr3g25_qtlnEp$%<%6hJIr1-|HNN0 z^Yowl59$7sEb_bX*M35A)4Sd~@`bIxY&_S|`#y2)A<=8)+X}9E?cLcged*oWWe#Q$E5(ZDp8Wsyul)Ai z`z!w+fBR1V{qwZfw%IbxOjc1{4bfj_JIsB3AA{kGp5*SQwho@J=qUWY%A?O zV%Z&k*s1^6o)3Jh#E!{V8~vSW%y#+Pp=HwqeDhQkLbEIm>(;27B~QP+s^018szcX} z8h0x9SY~-nsJgmwcAxsz17>>_7_?;hGbcpPnfXPc-SC3K>RY$ec6ZzjuvzYQ-+QG% zWA!uB4sR2tY3$L9qHY=Ye)3c4JD%3DeAgtK*Bns{_V+40re0~^R(nK{(WJmXS+ssy zy5WZ85~YY6QioNNyx+{>edyuw_SoJ}?`pN?6>@KsIDhi#6t_Klu3jvEyI|J58w#tI zT~(CdJqQrMaz2ZBe<+(DoTk1*+vrb%RBC+^ zE05!ei6?{e+<&f#t(Lw1C6oOcvyVXR@!8jP;7!?0Pn4eMSPou z4wVP$yh>8`n;^Eq(RcT;(-YJ*8E&QB?y2YsHc$-g^j`cXMB@FGZI}1lacY<{>$Bp+ zWkM0Nqwl|-@#5RrYVU(lEAwQ3dOPoPn0@EtU4;)KKj!FVJa@D7d~ST*YO?<3X)h=4 zedV9BW{c;H(%6S`9~t?!?y}z2c{xMLiz`$jIzUFT`Pu!e+tZi2ExI+cu46)T&+Ut* znL4{Jol~E?c)j&{@rMhz-9t7<_z0{L&{Y24nakhq{QlAT5{@JHM8t#zJg!~kdd2v` zDW+ZMlJXvdNe35l2JI13T_lv%@sCB?VnP&Kq?E4alBptxHnIl=-%1kUFlt_s`yk|U z(?x0H%?=$~vJ@THC_i|5L*Ovi;t1|SrNr;4oPUFsZBsw=(nX?b{**>$y}gay5x9I@e;hDzc-NzQ&D@vEPO*T3zQemS8= zO~C7pnbwSjD!*7(o?tzhrF8hn`_Hob-G#%KTMBis98sLUY1cMCPxZNiszSy}t8V12 zl_;V#&Ky_}x8pGY{+@VwNhFSy~_f)vtU^=2$`>|{9!hIAhYacN6Y*txb!5A3KA?K-->;Gb}UQmU$w^{e1FUsp&$~)&?aZoC-G2*w5a{1>e z=y`F+sgPBI(g7C(IFG+k5boh#`oXF4(BjRrmU{nEP+P@&e5678ae^v*mfzbmbq(v)Pn%h2nx67u3#Sv3}2ey?F8l-d6tO z%(|qS4TLQAMHNk>E)=nc|zA08=EK3!%j5cJ9lVV{si;L1{1~`OH57$ z+I@Mh&90m{f9uru zxtG_@l>4|T!{ujCzKoGi)JeBV2@1Q+Px_Wl&IqdW;Qtb}NBfG>u6f+ASmH_nzGB|7>VOrGG7n-i+bmXnv5WvN>_< zd_~*2z8ENQ%|CaG^TJY>i_0eLNs{X>li%bsxoqXE_&;Cnbbe{tFZDY0#+7+T>TWzy z+QK8FQj>Z1Rm#(jxPWEnJAN%*YkZ>iNXsYIo$J&DXS%Kxj=U!JLcFNet^4QeuZwn_ zE}vQ>U(MgRE!=s7NAb)jij_&3(tj5;PyXxB?AZK|+suhar|r0B@GTilkH}>c_zs@! z*!VETOz#m}luwt`z542-{}(I}n8ajto9SFt;g!~lTE-{?rW!%MKk* z-^KMkWRAjjgQQQFAE&I84&Ud|>vo7GQ10*I^&){UB$O}C7uRonbD+<;TyVBDRn+UrX!peOg)-dHRQliH)7BXQqV8Bm?HN$M}S-C)h@06z!J^aX!KD zecL`4Mm_DA9)$~`f$udIZ%p4ghw+$}i&t1yR+{7xZ+w` zFqPHCt~c2DpkUU<<#P_p&iI=mfA@6d%-Cry!P68My0$d5eBWI5ZrS7Vh2;|86}lS~ z7fU={GHn5e(Uc!Am8%XOx~crK>cR4IRoU9zlg>(sCEVQ?Q!}Npz+A!`Rlk5!?c8Kn`zPeHLhsTze-b|gnwR8QH zmL2EONVzE7#nJ3u?Q`+$MDtlKO{tYSTi-2xl3E(3r2nrW^yDO-3HL|>8bvRA$2<|(lb@{{5N#z~!aSO}sPjh`<^=`#~=}o&Cy?5VWDUVfEj4FBY zW%Uwi_EXF6O?~@fBGdYREiwy!$2+*jrgqqc%CFdI=)L;N%!_ApWPBH0Japgg?{`g; zltBNMCvF~sRx(>X-rAWynDEI$*w#W_LDi5c$3~!3z%ZdJ`2}P1yjusOdTLLYnEFoD zc=eHg*0M?3(i5Jn_K1jD@9h5N3;(HQv#stOS#iU`**N_~Fw>OBX1O=Io)|l^?3|Rt z{54Pf6Fn^Vg>C+Ba9`4DirkIiUfXZqojY^x%(<57&(6#_En}~f6MHJX zX8)WgXDdJdIrq8#-uFN8iEo&6AN{vTX-M8IZ|8hasE?V!=NdCZ+a)7b?*~&?CKlb) znI-1jzj8$sQ>fTWHoa@>HbNluDjpK^?m>Jf{1>T61UnH9%Ar<1OTFPVFrqSWjvSXchYFgXe>Ti={o@~hA z_@mi;ajNB}N^Vt?3)5$>_$V^-kwSF&{qt*|-*HTKZx($X>vwmn=AOTYn2tYZY`bK1 z`O``sK8+Kbdggg3bQvwu5cnZCb*9$Tm4|&=jC<;2ez6@4`1ED%JNFEA52?a0YZ@ie zJku_p*yR+^$bR~}(Y80z71rq|#X^=W4L>MfU#R48P-ufNTU893i<6@gPwgz;*~{Jv ztTa5d=(zhdi7)(;Gu+q=I|Q!=&8TEHp6cGKD)423pRK~HQUMnZuMZXfIM>-G%Qj^@ zo?86tp8(U3ou3U;Iya~bd{L6w?RPtO@e571Y4dt!lu4Xj=W;de!ec8ZZ}(5XHnUwb*SqavmoCdfZ!>m3B5x-Z1Tz&92vSi*~pi&wUgoQ)75Y-b+^=(PV%i@j zi<>?2IWXO>+|b|t!=p~s3!e=)IUhdqNG-~!Pik^TyRgfo-Wx&-)Fz+%GVx4A#xhTx z+s<7pE!-an%Bd6z#caxw{kY0c$+TmV&_rXV==rxhYDE@t=1 zP_Pej*`D-5b7tOdSM4 zX^~4s)aBpg^&z&j~6dlrTDD>>Q;m7G%r10X>>XRzQ zVr{8{#-We?3I_Qvjuw0oGK=NZom)pdFI1(!(@bUhb0Gb7@oa!lQXXAuzT6u9o%!grp6h2UOKf<$}lOd>6XZzKX00M z+-(TUZTptvamQ!EnPnF*YfkD;O1Sl7(c%7icROtPUaybn4hWmjA9Z1aSc(ddi&k*y zw|{qkHpDJ?X2_=W$dgrjvg_3lhOEmUrrYN}d$T$Jh`=O`B^Ngrikv=veYVYq+3(Lr z*ZsY|eyO>nV2FxJy@2^FR)v{uX}l4FMGp=nPV1k;=A&0~AWCO~GwDGi^a@K+JaW3_0M~#C-DE>E$J7%+$^fSE2b{Kxk|~MQ!lnyeW~+>bqBxg z|J!p}--h+*kA}q+3pPjub{x3+!i4G0hC@qVuYWwVz5dK37%VsR@+_cZwd1@u}jTtWoVkd z;Cfi$9Id(QnwLd%Y_-VFzj0=AbiVpz_A`3lZEG+83BOzt^m!c9Nerc=@4C#UWX#3qIPhTLlZ1rO(LRK zY5uaMS6{@-1g_oFEA;qCY(T!RAe$l+S5U&jmduji!xAAAg%rQr*4hTY@5-0i&7Xhi z*!y?=JMRx)~@kMuj^BVfJLxo)Q0`qu*CZW{UL=g(kdoXEkt zF?*pJ&!lO7i!_Sfe-1wz&9~vMGkkm%g}|Lo$6UuD?3-Yq#YO|LLEnpPTD;=mu-lm$=z`%3axAn{{8; zdtP{>_*;l~dE@llqSx1MU+}l)`ygr88Z-4oFV~N~W*hC89lx&dcX6@ZkZx5GELo$f zWU3RGKV|0IH;+H~P2Z|q{OGaj^9oJ|Ch>PWpFOWQ&a!8j`^unYm%o1KKe99Vty`3} z<2&YjDYtVH%jzvzCbm!W7Shap<<44jesSQd2mYy?$xLaE3A=3kwti*1+U&`7E0X(^ z=D+u6Uu@>>-JoN5dsV>7(2gS=>tu~86WZ?T?>RhGJl5y6?}xsF%Ij@AQ!+ijWQDt}(uHC4DI8KkT#>InNG|L3Ks&dIgUE;m<8>dXF@J~usKliZp3(+pv2 zcM5Np3!0nv;oCvxDeB*fKb=xi7EhV*)vQUvy@zGiTA@7GrFU0e&R&+`|7t=*#s2d@ zHrBeFQVD!oVz*Lu-gemq76}G%Mb8-S&HiCGY+u literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/greater_telekinesis.png b/src/main/resources/assets/ebwizardry/textures/spells/greater_telekinesis.png new file mode 100644 index 0000000000000000000000000000000000000000..190a4cc16d190f740fa32775048c6a89de00b5e4 GIT binary patch literal 2461 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE)1Rw1q>7GBfX9? zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL*Kxg^E-*z*)w?=UcMYI(XihD01bIz4+$ zYHH>2`uA1WcVCP9U6(e$*yj10okm7YN<1Ro?k`&UM140-T;VIaY>L||x7!xSye{QS zm}corb9%)ttP;0KW$D`oEUPrqgf<+z#d3vb8YBDpnKNt8%`E;_yMFKWr+a@So@br$ z(`Wt@->|T2r#_$lzjM!d<#+ewE&s`%Ww*Fn{a12UX(1!Sf~!{pPejRk!d7o0!)Sv~$~`u*8y z5s~t-3=9>w^^Pu9-}caoX-WMz51Y_~S-r(#p=&0q8ye{(+jbU+X|g8n^txlo93*%( zO>&N1-v<#Vho$>k7t6Lj*O9-q_m9@m^UOMDfBgA<`u4%e4?J7c3+Ek*>edP=^bwfn zzwjD^;)JC}LDwc&IsTk<^I6!fa}!b}>jWOGWU}B6Q~o>Q*EFWT->mN2-h1-RcDX)V z#x>S2s!m!0Lh3dx>K{WorpQhGsp@sK!z+27&bo&y8A8`AI@2;UtMh1XbY`g1rwvEC z_gC>rif!;yI>X}s>qSb-2N90KLLnxbd%GK7CG~#X(0tCgC4|M%BSb5B-IW^~tIeM} zx$F#D6tjBKxGi9DS9{JZ9zwb%>e3jwlhGyr0=o^k!a*ICCaZB!d_DE;?+dC%@{gH8>U)#C0t||8Bfyn0C ze=NtOzU}?aY@w)d_D8?F{6pFL8s^r^(p&sA&8~-i4Cy#6`!s86#e)L1{Sk~d{Wh|f zGxwhPv(EO4mZ;QMtCbxV`|O?_{hGRN*VDNoQx92qzR;;IJGXJqrKP54B0E^7E{)WZ z-!)nJe&vkl`=!QeGbi+_^RV;1)sbMF*Z;stsOq_#R`>M9r%GEsyjZ(-QBy=%5=B-yBMqt)}b z+_Jw4%N!Y7%+H3bd@;xFXhyQ|Yn}X?w#O6Jd_3InUEb!zaO*SyGG6t9n1DU+p73siT&DY&58Sz zIGooQ_Oxqi=@eYOW@WwY>W}H?x-U6vpBlA z6tx&-$H zP0w?QXm?O(QQ=^!(cE||q1An*fI*M!WRvCX4?g|uSj=BPZT7!c@;~3_*9-FBsQ z@qcvZUe;c+mp4W(K8DqaV~wfATFL(75!nHDQ*64^b&l6(*cbKBF=7J-lkI?G|gPtYURSoQa$>X*Q73Y z2TwCUZjt@6Pi@O?=SOku_F9kKw|X=BD1OpO+$`Z9MfQ8equ1XHf5+cBcI=nb z(d;^S5CHksq*aC>u*6?ZW8_<&;0*0skdyp&+{8L$MvVZ zm>;R?EnG4!p_I){`42-&|Axul@osC^J$oR!y5>1+;{+~$t(NsGLb4m2)%zx1d-Aen zvbMVBl+_X0lE)2qUbDzPC)eHOmGW58qIA&%>?Nj!t4{!P^ zKKSY~?E8JG?115$a>o-dH$3t!XVt8Iq;m9`=CK!>!%v&2SXj&M^sy`LJ1lv2VRrbr w)Bn7LpKp6y?6Q9PT;`AQzaM?wcAq(8$<)e zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifamoqutBd|H5@%rGWc74$42d{=bo$MF z(d)9u?KhvlGjsRt>&K2INXJVvb8@moi8urbnFcMk+v*j(wSVfb`mamhIxk%iwo=Ho zWrBmE&aoS6_rf=PtlNHbyIo9y%bDV;C5tVkUY>bhyzl;J>;1-u=C7C1{C`}H*=F_M zKRkO`AG$L%eErMOFmI7hzT<;upA=TDnRH%kgRHdYq=_t?fs-sQnx8oJON)uA>B7H& zYg;@fwVbPA@0=o_DyW^U{bQp4-nir)#XqN7On2*Aleevog<*%mf`a6g^IK<;ovB+hTn#g9?sCm7MR-Kr2=FKCWRf{H03euSp zkuA|ucw%Z}Yq*F#!wbz*HJeQubi7VXYEsh9*u=&ektP;6AuxqCGOJvBvNMB;>v8_t zuAf3vi&}f<`u3Gg(TGybD&tkXYVd_e^6-)JShezV#mgQaOl-K{*k5fEP(3B-gHa zPBpFjJAHM=tTv5Kc1Z>S7RG(=i{IbkdHjFwv%UR##lL^W_I;Io+5s6t}F{}+Znmk;qPooe;dt1sx>ZGL=(i1wcEFK_qQ%Pfz~50YJH z^s_+7*>pk*Cu5@l7w6&$2PZm;JrkcHG5MkeTy_0TmoB^EqBa2edUHoeq6<5x6O^q zGArU5GG~@d@$%pmyqz1MC(5Ti;i7NROdU(@{+Wh>DXlM$bLY-%-FAJ~vSbOiS*sEy z*xK?Y7#h9U)wk}o#ID9Qr{13ZnG_i7t|jwwrGZIJ(`04mDc!1O+qd&+UkKDmmQZWE zcCI$afM>C<=C<-ZN}6x07HsK%I-N_!(@99ZV^N3BNe+$o2EyvdVP9H+Rb1X@MRJkbAh{xZ!(3Ar9tM~4Y4 zE`d4cMUOVGdRh5STl9-4x5Ck{F#>Tc0uC-JJkBnGDW$1X9~vK4$#fENZAtWyXtU^Z z7GPsZWH_*L^YVz;C|3d2CWQwtHtK1`rna%ONxpcyeEVk(*`0mY=QC%{dUV4qNo%4C zXV|%fpSNTC_E*n2z#S1CnVgW)u)N#f^AgLPZ*vrQZe?2B@;lr!b>V*(``6{U)5PXa zn!#wVb7tf2{l2Gj6L#xr{C8oDy=btNXK74l(Y_Opt%JYxgxt7y`{~F1^8#hpPCA)3 zWA@y|zbnkQR`o_LcH0|yyioR6+pmbY7`55wjf$#T((mt_va2|z=D&%w_xYD^Gy+dN z_qhCRW#x$`70(qnOJ~Ii+kfMnJfYfL{-X62&uzi!Z~Z3!6aFhP?ckw1Otn|-Uahs_ z-R&5^wZC;ItIBw}vWxqrpom-kC1rDe7K+*!G5`D%tU=g$Reh)P&lx@=gp zI7{g1VoA9g^MiH8{b%2%zcDGZxOLZA#x-Zhx5S3F%SXHvlV?;cJpN+iWQ%RbZ~W!- zx%=qQ)Z#aK<~Qm@3~I_|s0;f?L`FI~95@xtGhZt0ZT9T6?C#0?ZI11ge*9+pw@j1Q z6^+fWcc0PAPu{J|74~ieE7Jp3y{YH;s`^We&Hi;-(Q>4fVNebK>EgnMY5({_}YK^&J&YZ8q~yzwz%k-}|~Mp@!e{bsz1L zJN&$_`2TK0nfq?vTxISbOQqOF1^mp&PZT?Q^xZv3^X8SLOrOemM3u@Wz zzi=#Su;}c3^ubi@M!ev0!9p29H$}%6!p8->R4?C*OsXnui@A5GaQ2;Db?vXBkKfFG z6SV&Q<@!zSzs==0h2KuxzRme`?xPCbd2el8#a#XzQ0-t^WTDc-R9Bw&w3N$XZ{Xqy z`V9&So3!RJJGn15sl4eOjdW7>6>iJ|-U*3DimALBGJMXuid;IVUTc@Kot1p{RS zT@~wYe6#6OUi9PWqDeo#hHv`%w}an(-lwZP`gupR^7-aJ{rRqV&jHmg=bjq}zUIE_ zm6AOC#Qyp|hw##0?0p;W-%|CQRQAEbrlL(hrT*uiCx4_?&(`fLjcgaK2=o3~@I;d# z`E`2dV-EdK98Uczp*L>bN~zD651gXl`(d#_>_rWeO*isZ$ErW-Q0eTPJVT|E-y!bQ zzFjw~Tp1rez5mgB(frkWSti#1dh|T+KQqs1A8vyu+mB|(Yh3I#>^X_+~x z3MG{VsS2qTnQ06R6}Q&T%q&yhDcJJ=v4|bhx2F~n_doO2)YLaF(kSbCbsaVatX0)z{P4`#+uc@w?AY%d%&G zKW=}p*Z!}V_3ilQhu1GOFx#(pV*k+>rT3Q3PcB#fVyXQ7@00j_5_j`{|NJbtyEx1? z-G23JL*bP0zsKCE&D(u`_PS3` zp65(&=+z@4JhS zY;5vRe`e=m?{Hx0lj+9nIZh`Ug7?llYkTx=cI~J0nJZWof=*2F3T0#r>*@TXxp9)S zZL5f{m*(^nEg1oi&wn=5L+Bq#Md-dL*Vhc80Dbikc z^;*<>n=QsA&)=OB-OF!(s6)Be=G2PCy>_1SCDUhBPK!*RUHem1?CJhbT4`6WhTYGb z>}CCK%V)ja@3#F`yzXc5ami$V%dcB5-(Rse;IF9Zcj=<~zFE}^)s8&cyRK&Ov6n&n z+6op;RypHv#-06=yS?)- zG}ip*zT;m0$7|NKvS7E~*KcfV8Tko$GD#zUqhS|L8U76P}o+00M>ZkRl`=hEk- zjPmnW@A;prdoED?wzxdrvaC35ok#A`C*S5Q4E?-MaZQ+aL5TAy)twP;8|rKS|1SG% zfA9akyMLbky)!4OTS|Q*QXHm#wtiQPotf$E|&JpEo!21+J49+)pS! zoA@cC`t~+0kB00g+&7w6-wFK4KY5x^(ej+*tBk*zI)waBdv=hor(9n3t=FNc`}il{ zWpBIVx8Cd>$1-a%=bu|9l%>yl_~vHa-ZM*$ym&T$d-y4$jGukS(sMiAogSELhKtNe zQtEy>%gn!NkJtNc{TA#Sy#g}k?fEwEPsWGGK|Th&d%oQ>a}CY6TdHc ztp|^4w;yHLBWC_K@9e9IF-xusKY!!1Mc<%9ecA-Iz7}(Z8yw z;m?dS+hxPEtnT)>magAf)w_J6Q=D_pp3c1cm1obkcqFLZIe%#3M7<*$w=u4kooc)A zi-3Sy)2{P#7ccS@C_nFVa*_1A=cazUKc(mOi#AylX^3+t|IA72=DB@w3iCq2?RSI& zzq8nGojA?^!`r5)!^Pwm3O?qrsBqOUGMcVT^+RxL9NnIF-3AkNGG zJ@4f+zp7rcp6zfJ{S%%j$I+%S&#C2uZnnGYG>L_LN~a7{z~nYzGhG4S1g~9%o-$=b>z0S zz>5uhckF~G1Ozzjm~Q!`M6%fCp=SCeLD8a2W~-fZ6L$B;d|tzrCfRy!;qzGvQ(2mp z|JW%cmB2Px-Fch#qUFCf2=^x>*neQ{VE4#T^S4-3!xqc*O6*pv+>=UWYagkVdI3DA zqW$weY|wqTIJWV&mDJ%~2I{qMUU<*G@Ljbg?2?!3Gk=A-O_H;oc}(GXUDo5z#5RNV zaO3Vp>l6$prS<7aR5jgxE%e-o=jy^GiD4<;M?0?dg>hQa1-@in0K&MP_k93`F91>S|MsInn?%=sXc;@{(ijA`( z(xQtxgWQi?lwi#^3RYpaKl1;pK)W(i%Mte)sZ`?=HAW0^%XoMmt+Hh?+}iwd=C^x4 z71S%VO_OBAKMCJ!@sKWjwDL~0(Ut3}wF@S4&V1N$j zmOhDG?|wABGsN2JN%O0RT>mHbBr-D3DgR}}BGuYfTNXN1sba^U#+hw~ilL$_)y3q( zRE{NQoC;}jm)g;wrQiDQc?h$&-N}h6ogQs7y6649vGBq-)-Ucdt6C1elV|haB*ek{ zX@c>hsT~_u7S+iw~X@%LxsQghP5gj?MZ8h1sIpZYX8`;nckzn=$F@+!y-X2M#XW(mi2)(@y<0tfyX{ z$`QX>DiQEYKoTh~T(v~lvD-@&9=b>!i+ z3Lahm=FJ6#$(uMrydr-r%IA+)&vA3Dcf0;Cp=rLkXwXaE2e$r+$*&~OmFy66J90d> za#_%coaH*vLMt35A6hJK+S7S!71NrwFV^)h&Ff~}oViV-RwfmJ*f}&r}qX7MY z{>A#Kom{&$7j~cJuee{d;gy?T&X&In&)L5o=$Oy3wtC^@M>#!f<>%Z#$J055r8>WU z@wL?AiT8YTlS*t77xIgJed=9X@+rn9vcgqXVYaUOU7q7lZG-}Am+5@45}V;3W{>Q0-gUhzTk64pB&M?3PTnH21Lswr>zxZUT@rcYuz zaZTHqgLR_7i&rC&sK}U9|FA*Rd};(>W)LyL>g0KQz{=_dj-9^W) z#m2QX{*A%jv(MR!b{H!em(O2vr08t=y@uRl-NhY0R`q;eu;1bMi>IMe9?o_!*kzKg zaJ8>9^34L3Lwe#ijT0fk|?C=JGF(ZkfF5oEQJGD*?>%G4od) zbpPLw{`BK1<|O{vR#7Q})<-`n$V@-{deWbScUR^goM6JZ_GJ8*MEU&}3S5`0n>7DH zVPRv_!vAXuCg09lb(JgN^`7L-s}3KV_1H7IYiUweI#a zTQ3c#hu^+@-zm?UcTZ(c>63Rw_cy-J>S6lDcB5&}oah;wmTg^GxNuGA+C^-c>7NbU zOn-mt&#JhxEzdveaPPZW3=OMx9&7PWGJ2PH`G-WRYrg!K66ed2F|&RyOq_aj>RvVb z3^ALX(p%iQ8k6R1@$@XSsQfhV-Ad`)$@yD;f3^719?@%6c<@)Y;I{cE0=@=_SshfB zR-1Q(=iAcc3*U9Eb#+{uAAWdRW-lGg9l-Z<`PYTbiI!n|C2sbzFAY&D>2^PUCLyOP z@S3wL_rlG6i@xeyQ{pSx)z04AXTW=OIls|%tGA~!xpTBy_soA$fAOE7@f*RiySKjb zv=uB8-ukR^w(L%ZJv+8d6ioiU(DH*y+MDBVb#u)ms&;l(WF6nNozuMJEgy@g)Vflh zs=T+Sb>1Fe$&BS(yp6Az*OYCF`E~>E$9Ynh&6QW=>g66g$SttNY*L;`Q(3-}-BsuN zYcnr5EqGvT>{xt7eQiK~o6w}FjHF%%^Dw8llE0D-W=soau+c}HYICDHm$iCVIwLO3ZOM6+o4j{X&3Bj7C(Rl=O@6&D`@U{{@mHRbTa z6^rB^s0inO7d$mbjQ@mfgxTMp3QtX=B+k7qUa)A}j2rjb6z;yY$r8MuvXUq2NQyv? z>sL;V)OCKo)(4(`yK+Ca`=89o!{J;Z(xPkc{@uONb(gMB&rh{`DW(GA2G#w!Z_j@{ zF?IQ_d&d{v{BU^T&(G`s|8@Sn|IVMvjJhAc_UQL70(Y)*J~21_t&LPhVH|$Be>)OhW$`pE$t4z!~7_ z;usQf_~`V^HL;fd&!zj!AwpMl}cYBdI*HzqIM3HVr+X}v3u)m}W&l(ltH zW9lrCTe-*lwJsX&^H?|I;F+=j*&F@W3ncG_s@^t~JNqi-bo76f4w1w)9}YK^+pXx0 zOur^L_l;bM9V5dG%d0Lob5k};Ie9LVG3`9HuC6F@uG76|8(uzsX|tsFn=_Zs?43zI z?tf>mTe5bwNA8KGc9;C^Rx7t0$-6EfYVoXtZ%@FbyBB4QKQc22Tk{I7?p>p~fu}LP zRO7eYWq*sVU+-jl-oJZt;pAhBUtiQ2Bz}EpS842@sjJxH{=KLD#XQDpbKSJhv!y?L zmh_tZ>CMfkV;5NNUS75+-8ZY0-K?&_z@fa|A#;Ku%e0jfPrpuSajX1owoIl}W$xpW zKD)o1tE|^Mxfy1jb!=lZI;mXJe(Rdu87J%Zvk}Ms@mFh>ly1y@oVH1FuIKTyON@-p zTr0nSocGB=HI@#e+#9>vR%VOr_UWqZp0hMqOY~#=FU=IMH}&t2%T%3VW-!?n&n$AW zSLTKAN%?Qw3~XjK?duAKZ|q7GzU*h!oK@M;f3LcGnYv*KZ*aT9e0vFp>#V!@+7vxv zTxY12$lr9$bn4vk>Qd;ehR+xCUd>#p(3Uy>-+>u^O^xx7`EwODe+#6)u=`W-E$61g z;qDDOlNGv7&WK!eJSc4d)bGxu}xj2^3`^PQKm zotw6FhHSj+X0H<$RQ22+i2wYw^E6}c_wX}|FT^=)7XGyBKwcFO?=F_amWA31vfK$$ zY+=WaZ1dSP&GFo}4V%TbO-=l^X#d8_qc%C(hnIBEJNEZM;+H=uC;VJrSWQT}!P;ef zF7?UOqc3t*`}XCSzPGEBbk%m(P@Q&J;r6==mK!~n-a7I(L!RN*afV23XT$l6C!7yF z^IY>u(T%Wa#(5P}d-=aDa@%XX<5%^Q{biD!(auLS+k_;z-elTV%>LIgaWkj3{D!|P zKU;i@)?V@cmSg4VvQxKzt$ZV~aL;D9)c)!X>|H-)WOFO6ZtE0nJNVQ48pDQn|KfaN z6{jX$ay=gqS8e;%eA=bDQ)}6~UNro^f1IP;>{98oy*z7PIzRk;@345mt@#(}gXc1Qto{qG z%D>Z;m}Y3*=W@D4z_e_^Bdep6#WsJR*}YNy+=7x%L1uOq^IbR>g&6*R70RAZ6HE ziz7Frn1&sEH0S8*nODDytiOA=JME>%VTFrDA?5$LCkl$B-*ZX+t6Pz;zxeN!RFHG@iMbDU-#%_^m8Tqsjln{KGDx_Z{K$&zV4>; z-dCUQynX)Z)22#|*n*<_pFL6oq-74}nq|JZZTM<|-;^}Q2`+Y5WAiVW{mnVV;kW0J z<&&De9Gd;YJdLC>uVVsp1*(L=#>$|#BfN#lA+*0 zi@MBbQMDoOG8<9_O7zkhr1os@fOLW@dk$e|`x-5J00ELtC~YJSJtW14uE(|~vG z?saorqZLn!Zr^)qRqEasOy~Z2o<5lUKHlTE;#-CzE1gdFGEWVVmRln2aj~-ar&C(| z<)}APf1g*+V9|;Bq@)Rk=D{A=KN znPnD(KnB~L+P^xVwjKSR|J$0O`hH~RYgZ2A+e|0KqKY&QZ17OYiT8u&8-#P7^IOn zLBn;{mVf?Jm8Nz@cm|z)@G<`E(m?)|=1fw);)@k7e42DD!9zgx$3z>61DuyGZf6nj zSn3hvsiS(T!EEM1ZXqSj&c_o%9Azp!W=`<%m^8&;s>{kHl1D=3HbgD<+$;Ei*Gb2*ImI-ep=U>fglsBTP?HeT+3u57oLj4UUR$|%cD=vm z&bVqZ1K0hvkJ&ZXy?(%^m^b0UFTuX~4}Kcf%@A_ovTs`U-*Wk*;N{2mY&33Wm~?SN zn3J<{kdC?9^P^MT*`n@Rm`-weXsxV!F{tzMnn&z{PaoD=#PvMhDpuYsVm^Uo;UVsW z{UYJ#PRjByT*xqKFnhxx&{Pt_cecYocYdt(_T&{EpFYU_F<2UT`~EFQN1w_H{jY8w zH*X&EIJ*2=&x+lgeX}353+V@h#JEoAFiiLSd*tM^^RpdaAKUbxqPsLYCdNKxhnPZ0 z%d%+Qbd8QfS{x@LDr?F)jDru9X7ljBT^PoH!+b;kzkjwpQ*5=iPG}RpToAmfFKNX} zkEzGbR~5gJE6LDLS+V=#4bCsuMQV$480z+$EqLa5cD2#M6d@P0Kp|ll!NNWB`pRZ& z#IZZ9l?%wvNm}tHNbh$@7US2nBL${PKBi3pg_r+?rM;0WIp*U~Q)4~PWZ{R_I6r$f hL%ZJ(yX*e3Ut>La*Um|@oPmLX!PC{xWt~$(697bzPF?^2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/guardian_beam.png b/src/main/resources/assets/ebwizardry/textures/spells/guardian_beam.png new file mode 100644 index 0000000000000000000000000000000000000000..30eef9ce2fa4f753a86460d29d47aa6ffc8702ec GIT binary patch literal 5882 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 hA_d#A_d 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 N!PC{xWt~$(69Bb1ReJyc delta 2176 zcmbQE-y=9dxt@V7$=lt9!G%GVA&2Eu#4-j32F?PH$YKTtZeb8+WSBKaf`Ng7y~NYk zmHh!HpNI$#cZSI(1_lmEPZ!6Kh{H>#*Z0JPiXOLres1>Mxi{y|ysLZnUxS%~6pyNe zt8n0^5bsQlr8f?_)k!S;(jK|g_3{KRLocVEf6me@F1PBLT6H3FG6FYpoLXI6tzTSTX;l^3O$v7pHaF^K^7x^Z#bb{h;7#Nu6_&a*|cs((1k3M>-GBc#(QJ zcL%ddEW4lV1U`la<@%`%EYEmSXId+~sqy9Tm0&iIJ*>so@Tx&TP{mD4sMTv`M!cfM zw!@Q(iyA(h@8V}WXP-U6+5NR(!;#PD=UqH}KE8X8Pfxp$q%o7mi3qMhE|*0P9WFNn zd@>BIdY%=s^fU(TJaReTLPKz!z5VfrSu^I%nCkP4C+f|g%}jdGO55!%w(b%kuA@ zZ0|iCwsy(YjG*E*Y+MfmHP7a>*Qx=62IC1v{^iR-C{%k%QdULHU}+UdV9y`;yrucx!P^4 zRNN~pm&^mi%u870dHPd^?uH+)%jc(N z)y+N?Gd(`<#=)-L`45i9+j{5k6Q3FwD|3l+`>eEB6)j7ixCbAPKIOhy{9n)OxX!fP z_@kOnC1v(JRsD5t_Q8PqnUTkTNow&J7!*%<7-c_yU%KYzH%iMxenl4E&-!-f2Lt!| z9Ua@=3(mSxeD&z6`i4|L1ye!CcE#SX$(q$&uJOBD(vQ#g`tDx7{&`L*+bf^el;l5* z8s{CfpInr`KYd^I#op=0so@#Be3@ix8rpkHrY4@s(@JvC|FA)tZ)a5F()*IBKej|Z z@veOnReilZ?BI=UzE{$J{KzC?IAG^$G#q(b~ z!L;|h>!MAJE}9{1Yhv2AM(;bz-2XPg@cGBMhZ^ka>J{}xP32j_dnQ^Ru~+N+u=8$s z(US{;@9yrLDjU7ccv~6IY1Y8G_4ogKFa(}$n)Jd=SU6CJL0Imzd~CDbyTtR~GbN^H zEj;HPFSY#QZI}HoFX&Xg+4X99#b%XMkCGB*w<&)d6|@vnk8e|cEGas*ol&-Bhv{_P z`#%)Tb7GGF%08ws*X+dm{Z@X7aWfx2b`^UYd-TCarskiHY1g`Jj=x^BJI!?V^?QBw z(Z!rKyjCtQD=hicS21~8aj_gP)8L=FI7G1Z8`GVt$!Yd{8={q6inS*iD_z`ay{$Q->rn#dmV-Z}?sI=& zp6{RcgK7OIvGw==GF4qV{QcI)kD8lWb>{E9;4S2d~_d4Yt z)y(HFnTV&<7wGy{&)e{R+40QtZ3lRhii|E!u8@~%>8tRR*&d`Qd3qIJB8MCIF4+g6 z(KZ`D#qHZv&C`%>X46!j*SY*!|K^m_S5wrT#B%q}^4_;os9|sTUH{#;RC2O=@>ksS zOEF=*T*|VkN+qA~cANM;v7Q;{)~XYYRF8_Z<@=3kF_QoIIE>2c^P`ur? zuX=~ywqO#Khk91@#rT<0ay&`L{BPFArUAb^Up~{SRUH{C~>D@=^z12rN%Z zE}8!Eh@#IQ^Qi5UI)z#f9x?2Y2oRAFZVGG3J7Mkp?bFBQ)0sBZe7^p0gMUTdyjbb& zMaI#L75^`#Z|Dy#vUYxS?pdGwsgr5_lqD+DCGKz8a$w=& z(r4#i**l6Jw|z8gq7B3M_vMRM-0(ZYJGbnN!i;ThMp{q5tjMy;o#heoz4Q3p#QDn( zOnPVGSaNCJKSAc?<($n<|)I#z`)??>gTe~DWM4f D^X_+~x z3MG{VsS2qTnQ06R6}Q&T%$_8@Q?TX#V-Y*1d#p0-=Q-{lIR1UQZ&sSgrFU)RwmcKx zq%re`q@|{Az4P<@{`J4b>sS7KQ?xOxdhNXZcZ&O)_0R7A7dQXl^XGqmcE6u*@$coH z-#-+Kv_8&^YyY}uz5E>g`OG@|&!3-v-a7hy<*n*P-}&v;e0FVq_if+0z3N^cOYQdb z$JX~t|2$oG@BgH|WuG2DdVl;T$1%M*J{ONpcKWm@{I2T8rYn~{e%Z~7kC0kFG3eBu z=U>=27R$%)XMO+p_Vyb;KibW&<7@r=wbt>k*y8U$1M1{=t2@Pqi`c#YbD4kjuebaE z)pp+9yZdf++-~WeLMvb0oBeC!)aTOTeoiyzB~G3Gas7w8^TMBBz41utg|vzK`ln9( z6KC9;aF|c|PQkqMqGH}>KDsi( zUb$0$&&T)%UxkQy2IgiKe`@zw;Ud3f~_}a$;hPch*|S zmTwrvab#oT`Glv2Pc0l3rU;c6i01^YYPh`U-B}6l^IJC_xt_U%Rl#f3$%Zx-rZsc8 z|7^VT;DW}=lyI+=N4>Q7_RPv!xAa<8sFbNru$Z{wfbyS_TFB(YNtb9 z>+iCZDmmd}i|*tK4ljpGRCse;OJVyY1Gi>^D0utNks%`>gDC zZND&Ih}F+2!Toc~eo2b2yIb;EcYECKx8JPo0;(7PGR}G^T~yx}Rk2v@$fx4DwTq5r zZk7*bIq4~wrXW_#P$cJVI;T2kYf%2XWQSXOBe_zXSB5!loB1cc|G&h$ ze-D53KYXWu+<3>Ad8Yo2OjY`tOnF!HnM&6spWZslX}9Jcz36Sha~DrzoBn-=cAySJ zsPmcALyrAxwq7-)d{MWw@A9rU*<>uElZsf6A`qpUY@<_YW6SkIh&vukQ z{ekmqw##$BHJ7GKnLX55oiDxewo;z-qP(D@s}{QVw(89;_$*@KUUeqfW%`ylx3qZ^ z(|Z~6md;z)HPbn7>JAYllh2(;x;k$#*`%=rrGypmFA(5rtonQ9_?cNc=g*$vTOs;s zaaGG7nH$A<8!W;Tw>ST>F$+9#`J2-5V>jB4lykX$Q!$islM|a=c-_uf{<_qx!zE^A zQrE8wevdlHcUke@k*sW+hdn_X`(`LS-)!=MS*h%Fg4owzTMTA;O3X2EuXl}j|883I zew*k*Rk_^Pf1ho2+h(#dBJz;=_grJ$*K^-5H%#6CYtq7`wMUmfe$y9rJTN4^YKqpA zi~7yS+k6BU_;o#241SaRyG}c-DTdLKX=Z}1b(({MyE?{m&!6QSX!;+Z7p7WvH0+x;>Kcze|JuNJag%% znQK=7PrAL|Tge$x*LVFan9zO7$~q^f$al8QEvB_zdJdUR@76Byo;_Eu->gP`eRFts z!kPB;2`tx_K9RqyA=L5xrOQmQ#SWZv0U>`ul`Ok&|KDlq(n5oh>zQZjD*xvolS$;=*CyiE*+g zTTE86UEAP!=2C=c*Xd2?mK-WxWxmQ-zWuIc<{l9hhbsG38^!Wv=XhwWIoc$1!BuJQ zb%PaAD~{`j2`+Ry=2-Q^pMB>m)|7R#R=nDk^4QU1QDsY;$(tklYkKX)UQW`D`^5YC zYn@f};(L?dd2mm8^Hixz@^GREU&s@ke|uY67)nJ1uFjNWd-*{i^`y?yrxrfG?T*a5 zDpuC~>+}|OKlJMy%hyodc|8sri|qn4LTVTNP$*fvSnP|hWX0d2tWeuWUQhB8ciUX* zTG#gV*P9h}J1=ybR~_#Duc(xhvisys;~kw^l1t~rZJ(jBVcJRkdoMlb-DBDv*SdK@ zDYviKtO*S|bN;1tKi&~A>+~_xB<)?hm{!b4?T$DZ)}@!=#5q-qE9Qn^xW`E*12ear zpJ!X64H{E(Z+SX+#!p?o*e2v?{M9{aojS$B#VejBF7f7IiktG4v2TXy;)ji43jZDY z53TDu!s=t*b|OeAP2^l6-_08;cdVXk+~E#hn03G7;^C!LFO840{;vME^LDbL;{ADl zCowi;^k^CRJz=@DFK-2(w(G)8yjg0~MIX9;KK;&af{gddS@CxHMs<5Rw{agYdthWJ z!rYg{TE*fZFa0*d^i=PLwa@n+h?B~^`_<%Gi`x0=FILai)NNVlZP+Js)^U;G42{m)l)6!#?}Ck=S1+Ep#%rg%b)O{HRSj2%X89K#=07{7wz9-_ zh}_)o8dt(M`@p}lqtPLGuPrUUf6Uvlc$KQ-K0v}^XMX^(#2{Iyi~_D89s&6k!P-Mp5uuvz8P zgvC=?XJ2F6_~+0+#eE)ZtoICCM3U}%sqFAqCi3_a`OqjpN+2{Fq=Rux#5Lj;I3w0?(<%o4~uGi_ev<6vpb-D16SpukR!_qI_%XG>N08{FyB=X za`Rl^DaV=-FyZYkhMPz7!fz&h3hSG^r*)3R=asd09Iwvqu5Oag{3S# z#krLs?-kZwV0xr*N8rgM<0EQ;hV$CQt}0t^zZ4SGR+Y|m+o)1osiW|Se4x8_Q|768 zljko8VwU6GVqw{pr5Y{cB!@?+ds06Mpsai`SdG z29qNqZKifOeQ$iS`_auqKB1Lv>Fa;#N-nlOVy>*p{%*s$O+PDt_@1A(DQMom*}_3h zD?|>+s~Y)pI@okxur5|O*CH3c`I&IvQ^_y3tKLoDFv-SIcV$MQL3pcFLn_5? z2}JLScs0ePZ=rD?8|y)y4R0n2Uvr$c@^jbItF?iFYbJ@VY1k^(b2{)*{x88RcbD+W zDadB;=#0PWdScPXT&0UEk9K)+JpX#-1IHO8Bpj#j0(blusy za^jJhmoK?R%~$1j-p%)H%j!E?NsTXg=ka-&tUFa_B^tFvZi2P;xoJs^-biHExGYL zeDaQIhr9lKd&rf?(Cn4Xn49l>mFIu?7gc-JL?@3ItIas_CvA$BRG8eLv}KFO!pk{A z$5$;^%*qJ$4pnQ?u~ljpwVPqqB0XJ5H8`eub?Svq^I+~9lG~P_osg=O(DUBcIAcpw zsmPYtNrwVvvzV=%njbrBr%cxZ@szbJ+HBMQnzT*!cven9opK8` z7n~QfeEWj^Q*uh084UQNoIkAgdeyyQvfcK#CDX2La1COSSXkasB{b0_jE~KGk$dza zZcW#guz9x(d|!r`x34<%;N2Jb8D9?0J+gG2jk}{y*ZIX~?s!a6w+WhB71?odbKIY} z&u-H_&E0nL3;pj1eXRYn(>-(k%E+1pzV)w;_Jl0^7<1mK=*s5V^2fJmRXzFT^X2Q0 zeED7VMn7IJ{QY{h{kHOtk$3-!@Aqbp_>mE2!@$76mgMd3!Z3&7Kf{wRUdfLb7#KJU zJR*x37`TN&n2}-D90>*n2KEw9Usv|WOk4~~8n^4_1u-yia(KEphD01bIz4+r$WhVb z^>@GDt33ba&Fs6Wg1t6PNj+UhR1~~2uLzu;WR#F3#C;-*B}U`P-Uc0o2u8um6V5dX zQ4+c=rf!`YDsF2-F0d$fD7-rK?oD=CS=l|~@AuBNPi#&6nR9M>^xfF)=l}mX|MK#G zv0%5|qW|45GtSz*znaI?u~3Y`!TSiyf?W~I)iiEYdK}*-dg?X1?SWmXn^)%F=`avZ zNMmR;n8UHMIaled$qh@E1ubnCN(7{wI3C5my<=q&{NVX6#iJ%$k4}8PNUCt-!NzM^ zWp!a~y1W-;6S5arpOkVe_!+n^setuhaMPFY3pz6d`uUYr;TDqFDp4ke$cfG%L8eS#M74PGJa8-Q%u_9K1bxKp7F(@+5zNvl9 zF#T3ai#o?Xt}O}ncMf_rEfo#6SUi6oK_ffrx|7c6kg#YQ@oMWMRV+?sGoTBOLNNfsUIHN+datJ$k6colDCEA zs|WL}^O6r9vlo2br*J9IMT_Sohmo-IwX1zbn>lVjdiYWG`PGKG&K}%vV)k{!xN_u6 zDg|_IU&HnA(?Uy!=^tKv3xDCYWW~x?$Co;PivIHczI^&~T{LIa;GTH0VOq+!RbSW4u@{bhp;ME@e(3G9zS-^@o}c|bAtGZ| z@8JR=9o@&rQky-$xXjqQX^NnpIp6Zh?s9WHj3&C=h+GsKs}uWKMMCdQj!cXs%SCQR zhJ|bX2znpQys<$xnx!)7B~O&q;hZ}krDh#=kkXr@r~lvX;u&6N?dp2{kFR)Si&*vF z|8A(SEt?atVrqy|UvAWu|NqR_-2P~kvZo`2uZ2OVm7!(X!X+$>K@DDMf{eWmg@U}d z?;ZJ2QQ*PPHT%(m*{|wEp9I}isZwItvc2sCI}^{FaG&fG&Q>`KCs`J?o%|*K|ID?g z#R8|E&7Q0tv0=wXeTEYCLk}G-YBk!~9~LOj&8td^)M3?27tEV};QjZ&tNW*|UjI+A z^I38Q^U*!l|GCv{c6YDumrXppS^whYyN+gp2T!TI@Qcvke3&ukXTQDws?Cy1u5IV% zXlI|p_+iQihr22*+6^W#9%mCyFZzAshQ(ZYp8YMW+v1O%IL$usbynh!15&3}uVV0s zF_dY@{O=PX)meCDn4Z{rPB4B>Gh$39i^e>x_;p0VKi z)cYI0=bC@)DtdE{@1EsHR^j}=mbNQplIx5n{g?TtpJsK=p1=0cmH7MT+~w;Id=+2X zp|^fsu&i&@wO9O*nJ-@_dugo55yy~rZ&+iJUdxz(Xx$v?x z8uZIK{{LriX0dyOMXizd^}NLAuh|VuCZq{jPk!|A>uiCrW%*o7Hchy(rZ&x7`?dO} zANxM;DDBB(=zJ{b(Dk=%_9;z{ko@+hdj9Ubf10AIj&ZxbD?GNFckQ)|!q0DZR!)j}F_tsd zme=)}2gICc5b#*p{Lt01StH%>(8KfbMYVp7bDd{oKANjIX`)|=&YnE=G_|8$sohmC zzsvob(igD8Jn8riLxwAFL-w%EO-DH~0KXlzM*FCF9(_xd9ri z+gLT0tefb!T*Cfa)V_>YFPt|gzmeGVoBvDQ`5Te~rMufFz36;!Sy%0TrSRR2BEeGE z5|14gc+av>??8jdg4YQa8%)K!U#o9UK5zZyONsaeo-bDR*JYBAKaj9q*3jwSw|zs_ zZM|K)cW*3;bWm*3IPoWvVV3aOhptx49EY11zCN-jaF*ZPw11n9HF2D8u(%Gg_+06q zAGvj*=FP&#`-L;J)9#)6dS=gaF###B@~5-!{j7R$_gT@D?JN&9Q{P?jTvPcj^w~Av z2Wy+zcc$G)jVV7n)kJSrck&wvGm+e7dEYNIm7JM*zaj8S|Fmy@r@CYI{JJ)K&c9D0 z@#dz9H>EVso<3*FJ@J&%&9bKT-_I>tsaxmA>(Lv^ot9KlWAo*N+L8d9ZFRzq^ZO5b z8U1n(-(2u9D9l7}VV{j~=j;0mm4%l6{Ul$!#P-|@DShks`~KmtHLGsxG${_tb5d0{>9L6y+&X13kAGa3=L9cBRf{=(f0j-S;gvbF)LAdtA=mWq zs=YNgg;XzzF57GDV=+%{(zX@<-&RQd+c7g|$;@}t)}K(V4wyD`e~pRwrGiCgWRzwn z9OOOe#I|IrnhlTOIwSq~zzEc%mA;Gy9F{o^RK`dmKwv*=#16 zdO?aykbC>3%b$3)B+q7Zr`FznX}n^~scb%Nc8OM3i&bWATP|hnR7rU}!Pmj8_tesj zmpqd$8m!ILt*LmSalEho48&9Q(6zOopxFfu+8c6lh)8eZS|dtN@dqr_3KbHo0r;jf@>)E|$3s>r%Yw(iy z&Hd=akUlS!;r9P||H8Do{&1gs>YSk`z?3*MAzkp)x&Eco_9x^B>j*DA^JmtkiAwwL y|0%R%n04zBLo35MpPK1qY#nv~j+E#AXTE)0?0yJuZ4?6o1B0ilpUXO@geCy6zMVW%->crwn>TkR;}I9Jz@Ai>MVuW$QobEin~WA1cCx0JY~m5w#DANi zNmO8>t5~6Ls6s{gL-&&*-Z8E|JyrNQR-|*#=IB(v5z;0ULg==*!ifa-F}bfmi!k z!1WE1iE0PVFfb)r2nMm=cA1sAp_s#glXu}u1(OzmBfD?ys0~=AaPDh!cVs$BI|No|hd^sE%)XNdlw0+9W%kLjw zRG;tuip}+4(v&9k`)9vgh_4T5nzg{8^i|E(JB}I%8Zp@+Fl5I=8RkdiZIfrNi_OAI^!t^jgBf_V-H2*N2-9R+`uT{p zLhntEOpGMU#coE1g=_u@dLLbRe~WN5OJ&YapIO#cH}||&n044eN^g#yeq4P+{rs#) z%M_>D*6Vrgv8v|Zdwjp0rKiRfCoRF_X1cHH{!5#^xy3E1uQZievB5==VPU3*relN1 zf=Q7s4$1*BE`R&38`#LnTxveF%;LqeO`B%CvJ-t0Bq($@k>OU96VHoaAMX>+yDmGa z7C+&c+GA*;oO zVm7~YR`#h)hliK-D4I6scE3+9K3q~~@TNM(_zjm^jOB!w zaO1;lR|4WfSsfm&s!wF_*9x%NFSC5jwKErkb#>OU$N7!_>ywr}{`2{T zyU*XRvNa$6Ro|)b?8;E8j^k`ecxTPO*vm892VXt%FF`PGWGj4yFnXL*Z9 zoArf_A9l^1F;ir9n9jR}_p9F|-*R3!uSYi7jX7XVT|Lme9xF$v{fJ2c>tDdjnnM-lS#B&UXJ|w)b+L$rr*yZ$y z4T}~k9Nw&OZu^`1+wIlYZsk`r@6JvydiBKf&|2R!@p~sme!s)!;_UU_-iU2(UY|Er-&I<&$z$8RN3WSTXXe!R&cDtalzjG3 zq=cM2zugvAO_BbbJ5Cp#Kb|qE=hsF4$SoH`@>s%rIbO(X|{OB|8-Y+*4BUfQ+_Y-=Kd!*$Wom!wOqIB)1Q~77}6)7g`b*FrNyX5?WOIqtK*T^J@ z)SEp#QD?Yhs@rK*Md|h&rcIe4dc9Nqgu2TvUAlGVx4Zv`nUtOZlCoE6aFlH_jI}=m)EnT=HhiQ|i*u64CPqrgUiGS+snLc$zL@w~z zP;}!a&kaK>t6Lr=CeC^%mmM!}2s$!3GU)Ey6(#lROLhtF6p4sz*(7iyA(BJnR9MEW zJv+4W_@2x2`v1`_{b$xVDagR)0pF(se}iv)dSfT_Q167Q;J59cyo?>PG_>2#EIr_( zJf$;)D>d5VQ?t9*$vyKcGje(_@4w`poV`cjz|C~Y1LyWH-#@iW>AzFaPk~w7Ee;WC zHzHd$ef}SG+B)7~8|SpnfV4XQn;sLtZ%#_J4*Y Y&t%j~8CcIVFfcH9y85}Sb4q9e0EbR^J^%m! diff --git a/src/main/resources/assets/ebwizardry/textures/spells/mine.png b/src/main/resources/assets/ebwizardry/textures/spells/mine.png new file mode 100644 index 0000000000000000000000000000000000000000..ff5ae76e7e2e1ca0233b48fc4e721e3b864dcf6a GIT binary patch literal 1575 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 AsQ>@~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/paralysis.png b/src/main/resources/assets/ebwizardry/textures/spells/paralysis.png new file mode 100644 index 0000000000000000000000000000000000000000..d79ef576b4c5262210d4d212c72cd310d7d83e32 GIT binary patch literal 2420 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 delta 1985 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 D0|!Q} literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/remove_curse.png b/src/main/resources/assets/ebwizardry/textures/spells/remove_curse.png new file mode 100644 index 0000000000000000000000000000000000000000..c5b3f15dfce8d5aae8048bc625b3a43e7a8b4e49 GIT binary patch literal 2459 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/resurrection.png b/src/main/resources/assets/ebwizardry/textures/spells/resurrection.png new file mode 100644 index 0000000000000000000000000000000000000000..8d8a9cdbd7e1605911230e1cd9fe07220730f92f GIT binary patch literal 2254 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE({C|D;WMWYei@= zFfecyctjR6FmMZlFeAgPIT8#E4D2PIzOL+#I2gtBtWKF2Uu0n5i1u`G42d{=^!m>H zv~bDeAK%}6zi-d?t+vVMh0-_iEO208)nsDit!L=);F!YX;>s=LyJU+=M_ZT2!bJ-f zH5vspFeSMQw07heJKMKPi45$g^n%b+rDep(Mr4L%Rk4=b+7rnx$wdN z9~lkheRdUx!&L9FGrW=c#*lMu)>^L*yX&oMK4@qfL@_i8Fa^#@n5*h5Q~8kL@V|S4 zxz~+(r~!?6Tx_w}*{Z{`PUjpU=IiWjGLgyY2pamp3{Nry2yg0aIBnhc3H;- zL8g+!4iP#5L6g?5HH_PTBAT7^_SLhW8`gRil=E{eSflnuw(yNaRfd~s2mqX zm(|L9rk{CUJVnMp?b*cF@{hKL$0uIZ`|-H%*{Nfa4V%04cvK2q!lrm!ywsC*%darA zxcTA^w?&?tm=u{}cc;AIJ^Y|^jw7SEx%tc6(>&)YE`9vuh~S^DMN!GWZ!O;QbA5Qn znl#b2&zw^#Pfc*OSSr!0U1OhWqW5yzygfRSy;&*(>8fGbQ#d441sHq8B35V4nw2OK zaVD#2gUdw4AC}?UVGVbqfZ=SzB7gr=?i1%D~+oG<0N$1&f z``@gU4=rx&cHccmLE?g!5KG5}%X-WIJUMQEbeF_ZllZ^C!aI`OKQv0`|Czh!%nC2} z+pZbmhu-zFGydMa{^P`c+q3V^+6P}1t*bnB0bG$X<=)0SG1&xoJuivcu!nx$j zm(y*lR&_jS*&~yv+OkizPsRA*M4>f-9EuyF1P(Ru$R66RA$g+Pkn!kV7iHfrZ|+rx z6l>axG`ly)PEeheXSy)@-NwqFR?gX;muGqCXX@E?ZRT?F7m-{erlD#WrMUEvWG8>) zLiV*x=RA74FWw5AW;*$??WwBCO51Gp?wxWTMI0m%I38tG;J^@^|_opFkr4RnD_NxIVv>yT`t3+hMo96P}-3 zgf&kd?dFYKQ^?lSVlgSDbI}ReQrU^BY-@RgvRz)xkh_;=X`N8~TX;#P+pK5Lg*T`z zlr)c+zIlfH#d2>aiH^rY*}B<}yE-ElOjVHX7B1%|M@yy-^eqm#$2&4>5_@s+G91pyzd_sy*}ga zPf@+Q302RxUlF%Eb@8pe!J2QHv)p%nKbK$e;#2y$`Hfdk^2Od4Zo7QC-CJqOCW+(= zQOyj}Pd%PaI3(oCdG44*ctVcPq^mcUxOw!3i7j#2ZTR-&ZH|{3Zr4}p+cdrpFIj!^ zC(EXqGanD?O7Lww8MB%fF6uuQIV<*gae0B>p{Vw5;U(t;oth?S zOnoGtFTi#oYU7MOec$J47-i_5R~O)jcrCGu@BY1Iv+ufSu{Rife0fMwVX4z5mHc%N z7D*&4_t^S+d+-J&Ju*y;c(C_~i=^bAxno}3bpQN@<;ah5= z&~fS277L~pClBX2VN0&E>3LnamKfXO;P63!iKlppUw{>piI@A4%HEJ!HxJq=wtQxI z&(1Ng%urctosmwya?67J=`%E(IXVSinFwkMR;=mXsF(QoRdUR)58@2}->qV6aq{ZD z*0>F`0<$%Bc}iCytQXW`=PDbwdK`_5^0Uq#BEPfO{?&zFZz z8LU~x!5Fx)F{Dp`Nx$YjYu>$?bMp`XHh#2y|F=|zeg7Zv3pgqI_VLScynn?k-EYJB zS0vF*L1kgQz&m+|_x{~K<%Gp~?kfJxI>kS~TCU<><0FPg|4M37m47?5U;Zsn`|U9M c-#_fld-XGvz2CoOU|?YIboFyt=akR{0Lk?YjQ{`u literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/reversal.png b/src/main/resources/assets/ebwizardry/textures/spells/reversal.png new file mode 100644 index 0000000000000000000000000000000000000000..71f0cb9559690f04ebc9669be9c303d5b068336f GIT binary patch literal 5726 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 wXmYgU~*gc%bU7#J8lUHx3vIVCg!00rmSvj6}9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/rupture.png b/src/main/resources/assets/ebwizardry/textures/spells/rupture.png new file mode 100644 index 0000000000000000000000000000000000000000..a976e1e9410a3bf3094914be896354e8b5c53d92 GIT binary patch literal 1846 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(~Ds(|LD20|NtR zfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h*M5XoX1YUwVQ!~?XahdV@Sl|qtl~1=7x(N zum8Vy|NA*Ji=Wkb&UO*@O%B%lrKGr}OSg%CX+$^YMlT0Wua+*a=B5?;LS6g1zBWmG zJ?ee7Ilya5Q_{pHlZj!!6->B#eLd2Qru&>bGw1a7>z@+mpGisUTmP}zvbsL~{oa4s zYybaR|Mz9Fyj=br9Fn`d72m8JPz45 z=RR1ou$OtZgYU5}N6i z3*Wm9e&32XmNy2Lr%zY^#(i%k3*YIkFCHchYDpGd-$mV~%;+=_P6)a%<;9HP9mbiq zPxei2VR)|pi%sb`XUC=9-zi&EzPUdCs#3)lDj=BbqvRoCk$j-SK&`2QztbyeozQ8q zP03F_yRUh~FMi~?{Czfu2If|2(>Y=nls0h0s1{i|DynN5^e8WApCKZ{;TL;uq0p>@ zmB$52w4QriuUz~34BJO}adVE4XE$U6HOz`1s$hB$l-$F6BLIcIJN5c56Plo$6An^={qpV>mpoGgPZOib{l?Q(P!;!;?m~a~*R86GAswOBA_VY_|9=>c;%sf%7tJkNHAF=0x!$tTQqXFBJVz z&2N{`8Lkt=v4~&c;o5Z%-|29_a=3Xu+j{~FuchqisUL68WI1rsbs|sPYql+Fbz8I# z?rnO^t~qc2kvI3}EDl$SZD0CCXK7bdhsP~W2Zz>XOU~slFK8$&m2^Gv)I{&%l+Rz7 zuCS&ruQ9HxZfM`S^vJv)+bb%=*{UCK@o-NIUL^R~k0IAs%Y2q2#|qB4{pPtkHX9X= zrTj_AioS2L$M;FU{FBY{m6J=`AAERWno;?T=Wp?Dvxb&f^H;U986G|2jqdB8*BOW& zU7z-*UaIz;f1~u&i$%-7PxkhRRIT5x{r~@ktvM@rc|5;JOlVT$%%>tc!F5+!WiV@dg}PVbf_*YLvWxgF=~TlGCvi5%pQooI5O7g8zP8Dfsxz**h1` z`C0p)JGkrctmpT+cN@3M?FqZ^l~F~fp}Y2)y`j1rlMjob+=H2c_q`7Mm8v-X^I1jQ z_nEDCmh5`BW*76Lf7*TR9Xo?BGpP0)V1Le~_GHhE^>@?5kGu@Lo%zy0r|y$N@cx}! zIA2}0si_KF;Gmj*cFqEar3b23tyty4p3%l=rQpb0QD|0JWN0Kk_kAC~#@>D3rH|de z)pKrpxYBuFRfUf?YFxN>Fnzw;756`^)zYk^W&70+FPskg6r8foDn0ze@StV;_HC|D zLVuiFdt%n%l}k?qHO+HA-D6sAHBa`K6K}*mMmX>KcCg=z{`neztp5! zUSh1X*jakNaeJ}Kp8L6uB0`2O2N`ZX`}1^O%x`~P7B|+j)90`~y2<%CT6^ND&9`a` zH7~ur-&JQe^LtIw!UdQ0cZV`-UMyZ-v|`HdgHc{Bjtt-K%J2MhUXDLbG}zT)+KkS| zr7X|Wdj0PU?0>WU;qttcer@K-pMUf+6EcH?wo0ovF%D6GcU8f zDzDi8`1A{Bcdvhcu6Ip3uuJmbW~XbaO_s7n$y^;*_CH^?uWFhj%hMS3_H`~R9l9>~ zvI(_X$6H&SefnDW+g;;L#!TVU=DPPi3Ey9@`tZpmNgfFV^EoY- zuT3NQ%w&f1GIQA;eENEA8pn%o*FWaEl)v7|yX3~dM|t-DSxXKI+4YKlFaXtmp00i_ I>zopr0HTXj+W-In literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/satiety.png b/src/main/resources/assets/ebwizardry/textures/spells/satiety.png new file mode 100644 index 0000000000000000000000000000000000000000..2e794f38d1092b241f8ad627a064b9350fb04d31 GIT binary patch literal 2450 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/shapeshift.png b/src/main/resources/assets/ebwizardry/textures/spells/shapeshift.png new file mode 100644 index 0000000000000000000000000000000000000000..8d15146739313e408c37896758fc409af629e53d GIT binary patch literal 5336 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 FngH5iBI^JE literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/shocking_weapon.png b/src/main/resources/assets/ebwizardry/textures/spells/shocking_weapon.png new file mode 100644 index 0000000000000000000000000000000000000000..8eef6c871689a565f8e5edf428dab2a46ccbe5d0 GIT binary patch literal 5691 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANO4*Q-JzN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHWvkv-}52Ems9k3}q*?)5)@5II%)$&a5>SG-#Enn`Q_W$+#PgrDXICWO^xoP`vBz>OCf7P!3{O-*k<=)S)uRZ!x|N7bA z+~=1bsIKt)T-W>mBJzuu> z-RqCH%i{h!SC)M;{qej~hb386k1hWXpI$^?q(A2xg)0{Oy1&V(kLBOrcId_*sR{K*UXW;Vt#zZ_qtyN>#qjXeE!@d^tI^t^b3cK5*{9A*?J)Le_Z$O^SR$EFNeGhno?;|$q=`(HOQCzOPnBmCWaG%S)?`vn~@7Z|2fmdNh z-VAN&H)S@#Jx}cJaEU)Zup?#hM*h38k?T1*1kd~F9Ag#OAX&BhP0q)C7Va|IKT5*h zIe%ehiSeqlEIy#t!eepu_02oMcVu5ruGdr6Wtiy1$C?rKqCqsd$zCs+dT8hU2c>b3jsws~2<+wxg& z_q%Ps8?)8tR9rf_d`{J^m-$!XR{ZOl^}F%T{lH@VD=iUw9-m@2)tmmwv~}_vl|;5A zJ1YTwCkChL#I)7j7r8AH(`Kt{PGUEm&T_8EiHGHJnVszSWAB>p#1|TC{tMsn^MA`6 z!IJ;{PkI(qD}J}mt9Qu#8Xb6u)gyAnj9Uc)+j1-I&c91OW;Ju^^P^YZ#jV~uf6m`? ziqCF6f46U5Oj%j+^Jy_zQH8fY&p2sS{%qfsFqw}!Z$(xrX$R@01ZpYIc~Ell<)xzg zY=x>ft#^8se=F$-@YS1kuMHlW!NFk-QZX=6#3d`?)g`lcuq@TU6gUYw$Jk z%4R_az14HydlzYL_~4my|Mj&eKDFib%}lm!iYA8I4jZ3y2zbYTx)XTIM)#bI3?tXf z_wKrPt_7B+OsG2g;LYDCv1z8v(QF&U=Bqv5Dt<-vn5prOS5p-t62p5VroZ|8jm5!G z-fS=X&YZI=bk)pQ*{04av_G`?&PBs5yh*%5I!goQzPD6W-2Oo7<%T;iEayK7{&>#d z_c!(l(b1XfjbBUMa(MHmh}p~T^t-4>^H>>ItMe{@>|-Xt!>T*c_Usyyup2gtH})C# z>-)SpZm})z=!{USX&-N0ka&`DSo*Grhl|;wbrX)vR_F1x7TNwOPq&9{p7v8d7vYRs zTzlUyeY({|{mXo>clXMyHP6m#ys~6b=f%b&es3f8nk=z5Ey`7Rw^PkS_{4OVLxqhe ze+7yi$~mS|e`4cZqkkDLlXQFcC7gPf{8Vwaw&nbZ}-ztqdqYging$g$?Q}#Ftvl zir{ced*Wlc#_0MMjhpQo-9O6iow&at>gGoEeT<(hI@I^RTJ_`f1j94CX2|bistMBS zT%_{PEA*rAX3y|PDX#WO4}Qs6e1BWDc#F>Lm4CbZlzW8OQmq`;)K+}xu~bM}5}>{0 z;ysl&2P^wx)#N*-&fd)at!KvjEUu@=D>?sVrk1}`o#Glf=h4TC-tt*stm*?iKI4$t!-o-r@OXS*fnfMdlI2AbGTE0a1n-EjB5{nKK)1e%{h{pk} zC(gPDA1YaW?(%Cl3x`y7p_&x?oo>4}<#!8NPkI|9ryA+g+p(t5^8cYDDw|%q{wj*B z%lxun)BBYwTfIKm2$Y?wPvhMkt@+?nN}Pi*yPNiAcGW}cN`vHY&uMVCI~_lAv3Y5}$$QZ8lMrz0<%Ieu89WbQ1DpYK%!0v%^vHv7>zb!Ci^ z){Z{mcIzo_O}o3aj(xG6)^l!hSjwX5sg6miJ5R5@v+fSl@=BFA2Zecq3*GrFCT*P8 zbENNK$PyQ3i_B=L&aaIIDV`!ht!o)|PMP&TjP&tVvszeka@m>WQzum?ab~b1+zhhHGMl2Hl2o$l;{xy4Wls{jR)ke1&MDzo z_*gMo_`~cqmlQSEYw&D1(X%iEKJAxFkNlKdX(YC&y1Ml1Bu>dasrB%_i!M%?8OZ3K=JB(u&^=${o|W9q1+__2 zMbk7Hl2^E`Uv>1_H>F5Vmhk!~>(#NxzS^MlxY6@7(^h%?RiCV(vFQq*y2{R{ zt>-S>UGBJY)+h0v%b#v8{i5n9;l6<}_i~T=8U4x$YN1RMbRHF*>@D>wS#m|?&Y`7w z(j~Rm@3wp`}DdR9h;`t`(@l7`FUzx3;O{wq3iDq4Soc1LXR z#KN4uxD!q)D{R+Z30L`^c0#+|G5F<*PdQOslM~H(9gZrVY+AIjVpE~@+|z-cb05vM z`)GE3QEmVC<;yuFveHh*mo>QToMpVuc=4Wsy2d9p5+<1!UkEF%-*!$}yX1Fb+aVK? z?qy~xCdl7jRlGzf{b8Ts{fk1Sft}wt&bGCD^-j6X$$aG6v?baP*V~43hD4Md<4s`r z@ti45=JNShYL#}k%tZH3zR5AC#Cw()x25l_m7G(Jn%q*8r@2O6;|Y^{TK4XkZKwKL zUdwt`#rr?LM!a-iFYvtPZ0PT6{s$zqSLfc|p0V#~jf7h0YuAHZJG8g2D-3fJKAj(P zF0j|Wsof{s^yKDO;S&~|%GDIOy~A~JM8PS(nH{gqe#I`jH+%N0gw(aWUvQZ#+ooUR z*L(G~-0k*XUhmGcOBl+l*BVWQ8hi3|?S$})VIwr%?V^5g@myH+mgdA2F~`^NHUPPGf`;_b3d^S3|o zexbMKPfXa?(kE`Asy25{n07x}ed{Ir#FptBoe!`&&y|Z2Hk5EX&#^zBeSyw1!41As zw_k0K`}Od}3wBv4rBhp%^4!)|dlopkOo!=9=J$2e9HMvaa5-`?Hg?-B%TKd~dYa7t z&U0BE78uSo!?Hhr*%cnn#2qgt8%;dco#$?EKXJNV(9w3O4=arN_yg8Ryi8Q(JysN~(k^wIP^L6cwowkzMftNPW_UWpQciuuc{ z<)muucem7rdNPz=Xq;XAqIvt`tD*7n?P7=H{d&`W&rvph=yz@2=WnK#&+pxTzttk< zSnO){j7{YmRExz|s~k|vnBLh`l+g9l{8DQI18cjB3IhWJTavfC3&T`~P6kb%&#P+~ z7#KJUJR*x37`TN&n2}-D90>*n2KEw9Usv`=Jp4k!3?*&1KQS<{KlOBR42d|rcY1bD zOseGZ`tzUX?R-~Ow)+d4Zr=9k2`tJJ7^X$31WxK=`@$^H+s5H*q9EGa*-&%ALBwvx z3@1}JJvUdUo?Z!IA!awSbDtk_=#_)Z9Lt@TPy?DL;9zu}-Yw4mreVg z_U{iku!Mh>K!A_PWtJ;~D&?(O3LV8W)Hb*oJ;AQ|!r?6q5&He2Z`+H%ynI}L{@{_P4V;eL5kUuH8l$#)6}UQO zvcyXs?)TY{mL!~gZGLy|ownRNeYrCZndKai4=)-MO zWx~^BE4d^>FJEOsgV-XbS1UqK%~1QXgy(7CioV3Fg-#orLXNMvcJ1;dr;ueKso&o1 z-Ez67d;j-nlUzl+!)GLz2fj{@3U64<7bvb< zbdfb|rQ_B%`P&{5`=?HS_tR$Y=5nEPx11)ay!mm`aG6}qwDWb((*tB4v;SV_61{ve z<5a1zHOEA*?Ys5YO5t?elS)0k@B^X~mNbZH@A#w>7h2MUeo~f%9pV^*} zuvAd5{<~#e?ftbr`#*|3e?RBYB%v_rs>ZnOCkrI+8izqW`sIC}q?;^TeA4=X3vypm?O-1RQVB=_SJ zas9`a@BcHrmgjKk#OkyVJIP%M9C?dYST(ub57bd^HJakSAjGjNwMIdx)K%~Qap9a@ zANk^HDyO}j{JiLFEdS>R;p>-&m72`bExZ4lMbBG#LzbVyOZLQh{aP#+Wnz+DgWGqq zcy~o?lsPGKYQmHcY+-9Y%;tW!!ExdbLj?mss{^&vANw zuWc#ok#fbB)UDygC4nv~*S^?@g@_hj?+|1=Sf1a9rQCEWdtlaefp9RF@N(}Y= z&ljDW=9#zSyP?{(TnCqf)hR3adM|qv%e~yD;H~(@LFL=Dr?sUF^Hwt&DX4Np^!LXW zO5Wy|cd3re+xfeWul9eoO!Zp}`KtdrC!G7ddiOfzx>Yi}zS$gc;=9upC;l-qCcD&{ zZN>IoSKPQQM46hnW;{6?`rz!^@Xu$A_ox5QjemGR`TNH!50_Vdyb&GqtI>1azQ>7u zIeVEr(OS}bbzN}a-xij;>w*!k*=COz%Cqo_%u>kG_#cRc{ z6(uHZoiT4-+VO3&XU@-kbYdF6a(A&ux?mLVy1y?CmlR4x+Vqx)P0W-2c=MIszB8<1 z6K6)|no^DB#e z-mUp?;Gq1*|JR}`US5q{xBIJK%5AwNdpnkRXQUh6+y45aWv=2r_q~^U4I9@=Je>5e zcZPf6jMfvEn8a+p7>QZuemgaP=ch%Sa<#8=FPLVZ`6CWrs(EZU?Y>LD zxxatD{l2Kwsy|*^F1uL!E-7V;o%8tXNB&R0jvRe)iRsd+#c!=jqBFL){*vqUQ(q@s z#Vp=&GoeUs7lZSM8JsMgsg^D?`D82vl(*e(TGG(MbNV^Epn$TF8NZ!#Z8^s~V-+6W zpwAqPIR^X{2Le7PIKB9-u|6VSPjq9=4S}~x2bf7{;f{ zlVkbLKY5sV*tc(n>w|xqT#ldX6i@$4HZ1-9F}ZH(n}ds8Qs3W+KE=pp_~77zix~l{ zuYQ{7$sm7n#?xT;oaL9~6P$Ebe>GvwiJbK`-TuS0M(x_yhhEJMJhks`s+`rGj>R*z zn=FoHDMuK%{7G0H_Wn!QyPgR%qS7vYs!NSktY-QD?4FXby7Zp>$1l8?3j1#)-+#yS zpyG!In^1<1-chBsv-ovRCYWD&ZlJ(0(ZT+z&XZ~Fjc<(ArM0UXzmy-Zb<-~2|F>|h z{n1k!YS(0~J}e~7=9(tqlX&%=WSXB@xYmXGkN@w@`!D`1_30#6cD@q~3=9mOu6{1- HoD!M<6JoSa literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/shulker_bullet.png b/src/main/resources/assets/ebwizardry/textures/spells/shulker_bullet.png new file mode 100644 index 0000000000000000000000000000000000000000..9800214a49167cf63952706fb88448f10c1cc2fb GIT binary patch literal 4963 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 Wm0z(6GCT{aE+*pMG literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/slow_time.png b/src/main/resources/assets/ebwizardry/textures/spells/slow_time.png new file mode 100644 index 0000000000000000000000000000000000000000..3534adcd2ad58e288c602cb5c50f419bd95e0468 GIT binary patch literal 2411 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/speed_time.png b/src/main/resources/assets/ebwizardry/textures/spells/speed_time.png new file mode 100644 index 0000000000000000000000000000000000000000..bb95bfad59dc5f4984e3767b6a387decc52f25cd GIT binary patch literal 2530 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Y)RhkE(~`Vlo{@p>(_s0 zU|`@Z@Q5sCVBi)8VMc~ob0ioT7}!fZeO=ifadC(#u`JN2ox{MuneXZ17!q;#==A8G zxlc>m=D+_i|J(lmwKHs!tJ5|dH)}DJ=s0+zA;2kformMv1(xP4N()3ZR;*q1jcHbg znPTRmj!R1BJ5&}!zjN88HTr~N;EiDCJ!eEY*C-ha3l67sgPB&=FHGmq0R{s)Uu+_AU~ zaUyzi_ZjJn^e28~<;qiM1E%$IaZ7RHz ztb1-^zLvq&YiBI`4Q+~fX0v~p)~Ec}%uHKx`;4uot5go^&0nacqo%KMxo69CqllN6 zqu*_=DiWP)vFGEf*E)0cA|rY_9ye&cZuZqU-Nj$~XlDE={y$s^yHr1{Q4O#=`YLft z>51okiENU;o|<>?%eu^FQWcHj($IRh<8}XvYivurnc32>Nvz?qsCmM1cdKG^oR5{x z&adBQd$dW0if(#*NxS05!{ctg90IHLi{2dJ_9;!{xFhiTO2mtOEq%JeX|qb_HEZdb z>1#Z0ihjSRS>67xrqsNJT1CGi8$$R_ah*Cf>B%JN{5{j$ohTvis=g`?uPsNv&TM zArltycvAP2I~-aub{}uP-ueDpy;FsqpTNdFChTiBGgu|I2uNFQs_A(8gN2EC(E?{# zTaz73PPvjA8rr9~Xj;6NjgGLY>DZ>tai>L8X_899gzA)SjHjL+bia4H`FjnovUAU* z7p11NT+2&X*u~-=FBLw2*;l+kR{TDwR{0 zG_pC&KmV^?_g-h2xAIS)xvzU%@ZTWH)ncpe0;XN+{r`5E`b>ygw6!@*YNhPIHwS?W~ps}UgxPFtx->=$Q1qT)2?{?K*?0;+!N70UX7loAsgMyV;fRB`~Q68z4P}V zd&gG~XJ+0k-v-n!sB@C(uBpQ>M)Aa8i z)3&!e7GUAB)Z5!6lXJ$J2O6G)PA^fhFeWJMYQ| z{_?4&aZ9W%npYnVY}o(*lCjD0Wh<^)xg0cEdn;_#*0U~KIeF~ZR?O}we&UvPCCq5* zy}ti{ZqfBemUf4VU%a{3SQ4|R>d2FC-7n|a`5M@{?*5v6Eg(W% zStf>g-{fT5?oi7^+ha;j?)>xGeE#8lw-t9(&kJ*@FZSZ?)VNvnRf2tAb&Kly(+xAU zf+a+LX7z8ldnl?=U{>k#+{IDdfnohx3cj6FCmmwZxb9kJ^QFS!Mwf-$4x6#}GUt zu%R{l-Gj&9-z>Ydz@~qJoX{4hKN?H!tq?AaYI(~xJ;v;G@cB2+S7VmES7K&=s3mq- zZlmm^Fi|(pC96H^H#*e*Hu<>ma>oL{{K|=m`K|Z&B%Ie^I1v8rpZKn{z|!`ph{tWx zdW-Gusm#d;$ajy~QERMze$AsRHFIY5^T>RV6^g#(&z9oac%SRyy6(8=0Y@Z{e&X7? zk}svH^P{ZKpZUgruD!3=+A?|jLzDmJJ9B2veDL${@{HV97iP#Q=eV6IWnXdOa8_sF zhl~6%{TGGQKNM!0{?SmHkr{aZhRfMqEYGhRg!+XZbMe-D{<=X{TK>_GLkU+}_Mhpn z-`yIz!1U+)oE<5$4uLrD1_n=8 KKbLh*2~7aZoV#iO literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/summon_creeper.png b/src/main/resources/assets/ebwizardry/textures/spells/summon_creeper.png new file mode 100644 index 0000000000000000000000000000000000000000..2a678b7507b6af0a364858fab420fe4c39e9b9fb GIT binary patch literal 5393 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

    acy2Z0*jZm@8j#-!a zQl^=4zFsA?C?~J-(Fc!kF0Q?EXSLYK7IH+Jh43Fa(s4T>Q1DUi&znW>)cTnU1Agwh za&Xb>E8?~jFF5y$G@RA_`Xy&dwc^hmY%v^HJ0hl}@mjY^&S75>KIet?)~LCU+D%tp zu;7mWzPEBpU1I#ivc%3To?nHNB)fb?8?@J2oby~3Z|^eCR#nYBgE_uGBCp*ie=U1g zxq5fow+CXM&U|4A-N*B5(V^nkD^EBb$~Y2sjNR3?5h}j98C^m8T8A~ym&YvLarb$GgcFnK zlie#`v}By?|98zcgJ+(QVr5=pleo#z8|@t8`)rmp&Q2D7+imF{C3k*1 z-1X#t{mK5{%YW0m_x~%Y|NZFv+quojW&c?p#dP}C#;jh?z`($kY!0F)*+{_H=O!i8y?8 zdUQ{0s_60h*Sp`;t}A|aW{O|N#%-OCnpK1*W$ui0>``5z|I5uoOoLPDh_}kGB!@=7%;m+F-)n#GdwN)o?eIc|35BdNH@2yY1{kx6C=ZcQ*NvW=Iu*I@pB&D}-3RtwUmHK^ zV{U_O?eWX`TNFZ*LOg`8SRJvxVtK?eBwIjAcFDzqB~=|;C6WzY`#M#Hlpfi95nFh7 zwQ=aPFUOqQ9;^B9+Xyn`Jtm1 zXjo~q5HvzS(P9;oI$X4bwiXKQ7m@gz?zoeT+9nq!px2ufO+4qhD`r zELVg71UKPHA}`M<7Tfxy^SwNG*+=+@O95Yx!ZD?5jT<|@nm9i>V7|XQ?8Cc_=?eqw zz8y%;(A@L&^ZUi?T#jBmYS1-NLa9Kqp@M&J?1>opmtPI<%5A&sw&$p&BhLff8&(<` zNix6p7urW1x|v?re@<(OAHVkgpQa&g%-{b`h&WI$SKlF_ye!b6$J*N=-+bBrmXcjJ zjwA^;e@(E`joE$n-|zixhN4a45& z-=+G=m&7^}7*`dkH)Nhy+;}9TF<1A|E?c{QbJ-6zSERoE!kwTSsPnu39

    wXbqRt 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 I&MBb@0MCRgJ^%m! diff --git a/src/main/resources/assets/ebwizardry/textures/spells/vex_swarm.png b/src/main/resources/assets/ebwizardry/textures/spells/vex_swarm.png new file mode 100644 index 0000000000000000000000000000000000000000..7bdb9189a06d1a6631e8ab3face73bb1bdc8b0d4 GIT binary patch literal 5544 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 QFfcH9y85}Sb4q9e0A}X6y8r+H literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/textures/spells/ward.png b/src/main/resources/assets/ebwizardry/textures/spells/ward.png new file mode 100644 index 0000000000000000000000000000000000000000..1b8284f64b6f27cfd42e00a8ddfc5da18db5aca2 GIT binary patch literal 2304 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 bKf~tO-7|k>Jt$*fU|{fc^>bP0l+XkKWyLTM literal 0 HcmV?d00001 diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index a2b20f24..4aa7d470 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -3,16 +3,13 @@ "modid" : "ebwizardry", "name" : "Electroblob's Wizardry", "version" : "4.2.0", + "mcversion" : "1.12.2", "url" : "https://minecraft.curseforge.com/projects/electroblobs-wizardry", - "credits" : "Designed, coded and textured by Electroblob. Code contributed by: Corail31, 12foo, Shadows-of-Fire. Translators: MadWrist (Spanish, Mexican Spanish), VilagVil (Russian).", - "authors" : [ + "credits" : "\nDesigned, coded and textured by Electroblob.\nCode contributed by: Corail31, 12foo, Shadows-of-Fire, Tora-B, Avatair, Aeronica.\nTranslators: MadWrist (Spanish, Mexican Spanish), VilagVil & kellixon (Russian), Hahdrim (French), lorrampi (Brazilian Portuguese), ZHENGLOC & dragon-evol (Chinese), shejery & rewi_wire (Korean).", + "authorList" : [ "Electroblob" ], "description" : "Electroblob's Wizardry adds an rpg-style system of magic spells to Minecraft with the aim of being as playable as possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master the arcane!", - "logoFile" : "assets/ebwizardry/textures/gui/logo.png", - "updateUrl" : "", - "parent" : "", - "screenshots": [ - ] + "logoFile" : "assets/ebwizardry/textures/gui/logo.png" } ]

    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 OU$vDVvFfv#F#-VKJ7By3 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/flames_start.ogg b/src/main/resources/assets/ebwizardry/sounds/flames_start.ogg new file mode 100644 index 0000000000000000000000000000000000000000..40108d2cab9f186070ee3e0a9626b778518085ea GIT binary patch literal 30379 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/electricityb.ogg b/src/main/resources/assets/ebwizardry/sounds/lightning_ray_end.ogg similarity index 100% rename from src/main/resources/assets/ebwizardry/sounds/electricityb.ogg rename to src/main/resources/assets/ebwizardry/sounds/lightning_ray_end.ogg diff --git a/src/main/resources/assets/ebwizardry/sounds/lightning_ray_loop.ogg b/src/main/resources/assets/ebwizardry/sounds/lightning_ray_loop.ogg new file mode 100644 index 0000000000000000000000000000000000000000..041658ec474cab742a3e6f9948228d6c2378952c GIT binary patch literal 43032 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 X&Q9k4|NT27Bc>HI*Gws9W?%pS`|Cv~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/page3.ogg b/src/main/resources/assets/ebwizardry/sounds/page3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5f3a4e82fc03b9ef61ba7d04222c990e38fde780 GIT binary patch literal 17081 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/pull1.ogg b/src/main/resources/assets/ebwizardry/sounds/pull1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4ce3730cbdbc14153dbb9aa9a982cf9d61defc19 GIT binary patch literal 29901 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/pull2.ogg b/src/main/resources/assets/ebwizardry/sounds/pull2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..737809f4aa5f60d20439f7499f832d093f96fb30 GIT binary patch literal 31418 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/shockwave.ogg b/src/main/resources/assets/ebwizardry/sounds/shockwave.ogg new file mode 100644 index 0000000000000000000000000000000000000000..3af866c071ea1ccc44f690be3b57a8586f4222c8 GIT binary patch literal 44395 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/ebwizardry/sounds/small_aura_end.ogg b/src/main/resources/assets/ebwizardry/sounds/small_aura_end.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9010c3d5f2d4c414dfaeb79f5502a8d15913e951 GIT binary patch literal 59448 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

    * As of wizardry 4.1.2, this method now returns true instead of false if the attacker is null. This * is because in the vast majority of cases, it makes more sense this way: if a construct has no caster, it - * should affect all entities; if a minion has no caster is should target all entities; etc. + * should affect all entities; if a minion has no caster it should target all entities; etc. */ public static boolean isValidTarget(Entity attacker, Entity target){ From 373fd4c8e8dc03903901a4990a035586f8265359 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:30:07 +0100 Subject: [PATCH 17/68] Add chat readout for applying spells to wizards in creative mode --- .../wizardry/entity/living/EntityEvilWizard.java | 9 +++++++-- .../electroblob/wizardry/entity/living/EntityWizard.java | 9 +++++++-- src/main/resources/assets/ebwizardry/lang/en_gb.lang | 2 ++ src/main/resources/assets/ebwizardry/lang/en_us.lang | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java index 44dc43b0..00b4d2e2 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java @@ -48,6 +48,7 @@ import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; +import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; @@ -250,8 +251,12 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // When right-clicked with a spell book in creative, sets one of the spells to that spell if(player.capabilities.isCreativeMode && stack.getItem() instanceof ItemSpellBook){ - if(this.spells.size() >= 4 && Spell.get(stack.getItemDamage()).canBeCastByNPCs()){ - this.spells.set(rand.nextInt(3) + 1, Spell.get(stack.getItemDamage())); + Spell spell = Spell.get(stack.getItemDamage()); + if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){ + // The set(...) method returns the element that was replaced - neat! + player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard", + this.getDisplayName(), this.spells.set(rand.nextInt(3) + 1, spell).getNameForTranslationFormatted(), + spell.getNameForTranslationFormatted())); return true; } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 9c3a474f..9114aeba 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -67,6 +67,7 @@ import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.village.MerchantRecipe; import net.minecraft.village.MerchantRecipeList; import net.minecraft.world.DifficultyInstance; @@ -372,8 +373,12 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // When right-clicked with a spell book in creative, sets one of the spells to that spell if(player.capabilities.isCreativeMode && stack.getItem() instanceof ItemSpellBook){ - if(this.spells.size() >= 4 && Spell.get(stack.getItemDamage()).canBeCastByNPCs()){ - this.spells.set(rand.nextInt(3) + 1, Spell.get(stack.getItemDamage())); + Spell spell = Spell.get(stack.getItemDamage()); + if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){ + // The set(...) method returns the element that was replaced - neat! + player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard", + this.getDisplayName(), this.spells.set(rand.nextInt(3) + 1, spell).getNameForTranslationFormatted(), + spell.getNameForTranslationFormatted())); return true; } } diff --git a/src/main/resources/assets/ebwizardry/lang/en_gb.lang b/src/main/resources/assets/ebwizardry/lang/en_gb.lang index 720a3b1f..17165266 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_gb.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_gb.lang @@ -15,6 +15,8 @@ item.ebwizardry:advanced_wand.name=Advanced Wand item.ebwizardry:master_wand.name=Master Wand item.ebwizardry:spell_book.name=Spell Book +item.ebwizardry:spell_book.apply_to_wizard=Replaced %1$s's spell %2$s with %3$s + item.ebwizardry:arcane_tome.name=Tome of Arcana item.ebwizardry:arcane_tome.desc1=Upgrades any %1$s item.ebwizardry:arcane_tome.desc2=wand to %1$s tier diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang index 7c14a457..fe97b0ae 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_us.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang @@ -15,6 +15,8 @@ item.ebwizardry:advanced_wand.name=Advanced Wand item.ebwizardry:master_wand.name=Master Wand item.ebwizardry:spell_book.name=Spell Book +item.ebwizardry:spell_book.apply_to_wizard=Replaced %1$s's spell %2$s with %3$s + item.ebwizardry:arcane_tome.name=Tome of Arcana item.ebwizardry:arcane_tome.desc1=Upgrades any %1$s item.ebwizardry:arcane_tome.desc2=wand to %1$s tier From a523d3dd2b98564d6107e2122f4b3b9b91c923f9 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:30:52 +0100 Subject: [PATCH 18/68] Fix incorrect default scale for flash particles --- .../electroblob/wizardry/client/particle/ParticleFlash.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java index 82927b46..0e23c95f 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java @@ -16,7 +16,7 @@ public class ParticleFlash extends ParticleWizardry { public ParticleFlash(World world, double x, double y, double z){ super(world, x, y, z); this.setRBGColorF(1, 1, 1); - this.particleScale = 7.1f; // 7.1f is the value used in fireworks + this.particleScale = 0.6f; // 7.1f is the value used in fireworks this.particleMaxAge = 4; } From 24457ebe36991545b8f4f479abda54b90597a9c8 Mon Sep 17 00:00:00 2001 From: Electroblob <35599699+Electroblob77@users.noreply.github.com> Date: Wed, 20 Jun 2018 23:32:14 +0100 Subject: [PATCH 19/68] Add error prevention and console warning for trying to spawn particles on the server side using ParticleBuilder --- .../electroblob/wizardry/util/ParticleBuilder.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index a4ea6725..06f1313b 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -17,7 +17,8 @@ import net.minecraft.world.World; * types in wizardry made the method overloads in the proxies very cumbersome and inevitably resulted in redundant * parameters, which made the code messy and hard to read. Those methods have now been removed. *