diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index 8683ed84..4ad38117 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -817,6 +817,7 @@ public class ClientProxy extends CommonProxy { RenderingRegistry.registerEntityRenderingHandler(EntityRadiantTotem.class, RenderRadiantTotem::new); RenderingRegistry.registerEntityRenderingHandler(EntityBoulder.class, RenderBoulder::new); RenderingRegistry.registerEntityRenderingHandler(EntityWitheringTotem.class, RenderWitheringTotem::new); + RenderingRegistry.registerEntityRenderingHandler(EntityIceBarrier.class, RenderIceBarrier::new); //RenderingRegistry.registerEntityRenderingHandler(EntityContainmentField.class, RenderContainmentField::new); // Stuff that doesn't render diff --git a/src/main/java/electroblob/wizardry/client/model/ModelIceBarrier.java b/src/main/java/electroblob/wizardry/client/model/ModelIceBarrier.java new file mode 100644 index 00000000..0a2137e5 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/model/ModelIceBarrier.java @@ -0,0 +1,35 @@ +package electroblob.wizardry.client.model; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; + +// Made with Blockbench 3.5.4 +public class ModelIceBarrier extends ModelBase { + + private final ModelRenderer mainGroup; + + public ModelIceBarrier(){ + + textureWidth = 64; + textureHeight = 64; + + mainGroup = new ModelRenderer(this); + mainGroup.setRotationPoint(0.0F, 24.0F, 0.0F); + setRotationAngle(mainGroup, 0.0F, 0.0F, 0.7854F); + mainGroup.cubeList.add(new ModelBox(mainGroup, 0, 0, -14.5F, -14.5F, -1.5F, 29, 29, 3, 0.0F, false)); + mainGroup.cubeList.add(new ModelBox(mainGroup, 0, 32, -9.0F, -9.0F, -4.0F, 18, 18, 8, 0.0F, false)); + } + + @Override + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { + mainGroup.render(f5); + } + + public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) { + modelRenderer.rotateAngleX = x; + modelRenderer.rotateAngleY = y; + modelRenderer.rotateAngleZ = z; + } +} \ No newline at end of file diff --git a/src/main/java/electroblob/wizardry/client/renderer/entity/RenderIceBarrier.java b/src/main/java/electroblob/wizardry/client/renderer/entity/RenderIceBarrier.java new file mode 100644 index 00000000..5ee0edac --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/renderer/entity/RenderIceBarrier.java @@ -0,0 +1,50 @@ +package electroblob.wizardry.client.renderer.entity; + +import electroblob.wizardry.Wizardry; +import electroblob.wizardry.client.model.ModelIceBarrier; +import electroblob.wizardry.entity.construct.EntityIceBarrier; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.ResourceLocation; + +public class RenderIceBarrier extends Render { + + private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_barrier.png"); + + private ModelIceBarrier model = new ModelIceBarrier(); + + public RenderIceBarrier(RenderManager manager){ + super(manager); + } + + @Override + public void doRender(EntityIceBarrier entity, double x, double y, double z, float yaw, float partialTicks){ + + GlStateManager.pushMatrix(); + GlStateManager.translate(x, y + entity.height/2, 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); + GlStateManager.translate(0, -entity.height/2 - 0.3, 0); + + // Pass in -1 for the lifetime as the boulder crumbles when the time expires +// float s = DrawingUtils.smoothScaleFactor(-1, entity.ticksExisted, partialTicks, 10, 10); + float s = entity.getSizeMultiplier(); + GlStateManager.scale(s, s, s); + +// GlStateManager.translate(0, 0.875, 0); // No idea why it starts 7/8 of a block too low, but it does + + this.bindTexture(TEXTURE); + + model.render(entity, 0, 0, 0, 0, 0, 0.0625f); + + GlStateManager.popMatrix(); + } + + @Override + protected ResourceLocation getEntityTexture(EntityIceBarrier entity){ + return TEXTURE; + } + +} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityIceBarrier.java b/src/main/java/electroblob/wizardry/entity/construct/EntityIceBarrier.java new file mode 100644 index 00000000..7b8f6757 --- /dev/null +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityIceBarrier.java @@ -0,0 +1,157 @@ +package electroblob.wizardry.entity.construct; + +import electroblob.wizardry.entity.ICustomHitbox; +import electroblob.wizardry.registry.WizardrySounds; +import net.minecraft.entity.Entity; +import net.minecraft.entity.MoverType; +import net.minecraft.nbt.NBTTagCompound; +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; + +public class EntityIceBarrier extends EntityScaledConstruct implements ICustomHitbox { + + private static final double THICKNESS = 0.4; + + private int delay = 0; + + public EntityIceBarrier(World world){ + super(world); + this.setSize(1.8f, 1.05f); + } + + public void setDelay(int delay){ + this.delay = delay; + this.lifetime += delay; + } + + @Override + public void setRotation(float yaw, float pitch){ + super.setRotation(yaw, pitch); + float a = MathHelper.cos((float)Math.toRadians(rotationYaw)); + float b = MathHelper.sin((float)Math.toRadians(rotationYaw)); + double x = width/2 * a + THICKNESS/2 * b; + double z = width/2 * b + THICKNESS/2 * a; + setEntityBoundingBox(new AxisAlignedBB(this.posX - x, this.posY, this.posZ - z, this.posX + x, this.posY + height, this.posZ + z)); + } + + @Override + public boolean canBeCollidedWith(){ + return true; + } + + @Override + public void onUpdate(){ + + // Bit of a cheat but it's easier than trying to sync FrostBarrier#addConstructExtras + if(world.isRemote && firstUpdate){ + setRotation(rotationYaw, rotationPitch); + setSizeMultiplier(sizeMultiplier); + } + + this.prevPosX = posX; + this.prevPosY = posY; + this.prevPosZ = posZ; + + if(!world.isRemote){ + + double extensionSpeed = 0; + + if(lifetime - this.ticksExisted < 20){ + extensionSpeed = -0.01 * (this.ticksExisted - (lifetime - 20)) * sizeMultiplier; + }else if(ticksExisted > 3 + delay){ + extensionSpeed = 0; + }else if(ticksExisted > delay){ + extensionSpeed = 0.5 * sizeMultiplier; + } + + this.move(MoverType.SELF, 0, extensionSpeed, 0); + } + + if(ticksExisted == delay + 1) this.playSound(WizardrySounds.ENTITY_ICE_BARRIER_EXTEND, 1, 1.5f); + + super.onUpdate(); + + Vec3d look = this.getLookVec(); + + for(Entity entity : world.getEntitiesWithinAABBExcludingEntity(this, getEntityBoundingBox().grow(2))){ + + if(entity instanceof EntityMagicConstruct) continue; + + if(!entity.getEntityBoundingBox().intersects(this.getEntityBoundingBox())) continue; + + double perpendicularDist = getSignedPerpendicularDistance(entity.getPositionVector()); + + if(Math.abs(perpendicularDist) < entity.width/2 + THICKNESS/2){ + double velocity = 0.25 * Math.signum(perpendicularDist); + entity.addVelocity(velocity * look.x, 0, velocity * look.z); + } + } + + } + + @Override + public boolean isBurning(){ + return false; + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount){ + this.playSound(WizardrySounds.ENTITY_ICE_BARRIER_DEFLECT, 0.7f, 2.5f); + return super.attackEntityFrom(source, amount); + } + +// @Override +// public int getBrightnessForRender(){ +// return 15728880; +// } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbt){ + super.readEntityFromNBT(nbt); + delay = nbt.getInteger("delay"); + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbt){ + super.writeEntityToNBT(nbt); + nbt.setInteger("delay", delay); + } + + @Override + public Vec3d calculateIntercept(Vec3d origin, Vec3d endpoint, float fuzziness){ + // Calculate the point at which the line intersects the barrier plane + Vec3d vec = endpoint.subtract(origin); + + double perpendicularDist = getPerpendicularDistance(origin); + double perpendicularDist2 = getPerpendicularDistance(endpoint); + + Vec3d intercept = origin.add(vec.scale(perpendicularDist / (perpendicularDist + perpendicularDist2))); + + // This seems to be all over the palce, but the calculation MUST be right because it works for entity collisions! +// world.spawnParticle(EnumParticleTypes.END_ROD, intercept.x, intercept.y, intercept.z, 0, 0, 0); + + // If the point is within the hitbox (expanded by the fuzziness), it was a hit + return getEntityBoundingBox().grow(fuzziness).contains(intercept) ? intercept : null; + } + + @Override + public boolean contains(Vec3d point){ + return this.getEntityBoundingBox().contains(point) && getPerpendicularDistance(point) < THICKNESS/2; + } + + private double getPerpendicularDistance(Vec3d point){ + return Math.abs(getSignedPerpendicularDistance(point)); + } + + private double getSignedPerpendicularDistance(Vec3d point){ + Vec3d look = this.getLookVec(); + Vec3d delta = new Vec3d(point.x - this.posX, 0, point.z - this.posZ); + double dist = delta.length(); + float angle = (float)(delta.dotProduct(look) / dist); + return dist * MathHelper.sin(angle); + } + +} diff --git a/src/main/java/electroblob/wizardry/registry/Spells.java b/src/main/java/electroblob/wizardry/registry/Spells.java index 5dce3c2f..286a9ab2 100644 --- a/src/main/java/electroblob/wizardry/registry/Spells.java +++ b/src/main/java/electroblob/wizardry/registry/Spells.java @@ -240,6 +240,8 @@ public final class Spells { // Wizardry 4.3 spells + public static final Spell frost_barrier = placeholder(); + public static final Spell blinding_flash = placeholder(); public static final Spell mark_sacrifice = placeholder(); @@ -453,6 +455,8 @@ public final class Spells { // Wizardry 4.3 spells + registry.register(new FrostBarrier()); + registry.register(new BlindingFlash()); registry.register(new MarkSacrifice()); diff --git a/src/main/java/electroblob/wizardry/registry/WizardryEntities.java b/src/main/java/electroblob/wizardry/registry/WizardryEntities.java index fe7de88e..12b3df17 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardryEntities.java +++ b/src/main/java/electroblob/wizardry/registry/WizardryEntities.java @@ -162,6 +162,7 @@ public class WizardryEntities { registry.register(createEntry(EntityTornado.class, "tornado") .tracker(160, 3, false).build()); registry.register(createEntry(EntityIceSpike.class, "ice_spike") .tracker(160, 1, true).build()); registry.register(createEntry(EntityBoulder.class, "boulder") .tracker(160, 1, true).build()); // Vertical velocity is not constant + registry.register(createEntry(EntityIceBarrier.class, "ice_barrier") .tracker(160, 1, true).build()); } diff --git a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java index 4842151a..e1610825 100644 --- a/src/main/java/electroblob/wizardry/registry/WizardrySounds.java +++ b/src/main/java/electroblob/wizardry/registry/WizardrySounds.java @@ -66,6 +66,8 @@ public final class WizardrySounds { 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_BARRIER_DEFLECT = createSound("entity.ice_barrier.deflect"); + public static final SoundEvent ENTITY_ICE_BARRIER_EXTEND = createSound("entity.ice_barrier.extend"); 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"); diff --git a/src/main/java/electroblob/wizardry/spell/Boulder.java b/src/main/java/electroblob/wizardry/spell/Boulder.java index b4debe62..700ad4e1 100644 --- a/src/main/java/electroblob/wizardry/spell/Boulder.java +++ b/src/main/java/electroblob/wizardry/spell/Boulder.java @@ -23,8 +23,7 @@ public class Boulder extends SpellConstruct { protected void addConstructExtras(EntityBoulder construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ float speed = getProperty(SPEED).floatValue(); // Unlike tornado, boulder always has the same speed - Vec3d direction = caster == null ? new Vec3d(side.getDirectionVec()) - : GeometryUtils.replaceComponent(caster.getLookVec(), Axis.Y, 0).normalize(); + Vec3d direction = caster == null ? new Vec3d(side.getDirectionVec()) : GeometryUtils.horizontalise(caster.getLookVec()); construct.setHorizontalVelocity(direction.x * speed, direction.z * speed); construct.rotationYaw = caster == null ? side.getHorizontalAngle() : caster.rotationYaw; double yOffset = caster == null ? 0 : 1.6; diff --git a/src/main/java/electroblob/wizardry/spell/Fangs.java b/src/main/java/electroblob/wizardry/spell/Fangs.java index 607ab398..1a6390f5 100644 --- a/src/main/java/electroblob/wizardry/spell/Fangs.java +++ b/src/main/java/electroblob/wizardry/spell/Fangs.java @@ -11,7 +11,6 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntityEvokerFangs; import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumFacing.Axis; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; @@ -42,8 +41,7 @@ public class Fangs extends Spell { @Override public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ - if(!spawnFangs(world, caster.getPositionVector(), - GeometryUtils.replaceComponent(caster.getLookVec(), Axis.Y, 0).normalize(), caster, modifiers)) return false; + if(!spawnFangs(world, caster.getPositionVector(), GeometryUtils.horizontalise(caster.getLookVec()), caster, modifiers)) return false; this.playSound(world, caster, ticksInUse, -1, modifiers); return true; } diff --git a/src/main/java/electroblob/wizardry/spell/FrostBarrier.java b/src/main/java/electroblob/wizardry/spell/FrostBarrier.java new file mode 100644 index 00000000..16c56f91 --- /dev/null +++ b/src/main/java/electroblob/wizardry/spell/FrostBarrier.java @@ -0,0 +1,129 @@ +package electroblob.wizardry.spell; + +import electroblob.wizardry.constants.Constants; +import electroblob.wizardry.entity.construct.EntityIceBarrier; +import electroblob.wizardry.item.SpellActions; +import electroblob.wizardry.registry.WizardryItems; +import electroblob.wizardry.util.BlockUtils; +import electroblob.wizardry.util.GeometryUtils; +import electroblob.wizardry.util.SpellModifiers; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumFacing.Axis; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +public class FrostBarrier extends Spell { + + private static final double BARRIER_DISTANCE = 2; + private static final double BARRIER_ARC_RADIUS = 10; + private static final double BARRIER_SPACING = 1.4; + + public FrostBarrier(){ + super("frost_barrier", SpellActions.SUMMON, false); + this.npcSelector((e, o) -> true); + addProperties(DURATION); + } + + @Override + public boolean requiresPacket(){ + return false; + } + + @Override + public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){ + + if(caster.onGround){ + if(!createBarriers(world, caster.getPositionVector(), caster.getLookVec(), caster, modifiers)) return false; + this.playSound(world, caster, ticksInUse, -1, modifiers); + return true; + } + + return false; + } + + @Override + public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){ + + if(caster.onGround){ + if(!createBarriers(world, caster.getPositionVector(), target.getPositionVector().subtract(caster.getPositionVector()), + caster, modifiers)) return false; + 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){ + if(!createBarriers(world, new Vec3d(x, y, z), new Vec3d(direction.getDirectionVec()), 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; + } + + private boolean createBarriers(World world, Vec3d origin, Vec3d direction, @Nullable EntityLivingBase caster, SpellModifiers modifiers){ + + if(!world.isRemote){ + + direction = GeometryUtils.horizontalise(direction); + Vec3d centre = origin.add(direction.scale(BARRIER_DISTANCE - BARRIER_ARC_RADIUS)); // Arc centred behind caster + + // Don't spawn them yet or the anti-overlap will prevent the rest from spawning + List barriers = new ArrayList<>(); + + int barrierCount = 1 + Math.max(1, (int)((modifiers.get(SpellModifiers.POTENCY) - 1) / Constants.POTENCY_INCREASE_PER_TIER + 0.5f)); + + for(int i = 0; i < barrierCount; i++){ + + EntityIceBarrier barrier = createBarrier(world, centre, direction.rotateYaw((float)(BARRIER_SPACING / BARRIER_ARC_RADIUS) * i), caster, modifiers, barrierCount, i); + if(barrier != null) barriers.add(barrier); + + if(i == 0) continue; // Only one in the middle + barrier = createBarrier(world, centre, direction.rotateYaw(-(float)(BARRIER_SPACING / BARRIER_ARC_RADIUS) * i), caster, modifiers, barrierCount, i); + if(barrier != null) barriers.add(barrier); + } + + if(barriers.isEmpty()) return false; + + barriers.forEach(world::spawnEntity); // Finally spawn them all + } + + return true; + } + + private EntityIceBarrier createBarrier(World world, Vec3d centre, Vec3d direction, @Nullable EntityLivingBase caster, SpellModifiers modifiers, int barrierCount, int index){ + + Vec3d position = centre.add(direction.scale(BARRIER_ARC_RADIUS)); + Integer floor = BlockUtils.getNearestFloor(world, new BlockPos(position), 3); + if(floor == null) return null; + position = GeometryUtils.replaceComponent(position, Axis.Y, floor); + + float scale = 1.5f - (float)index/barrierCount * 0.5f; + double yOffset = 1.5 * scale; + + EntityIceBarrier barrier = new EntityIceBarrier(world); + barrier.setPosition(position.x, position.y - yOffset, position.z); + barrier.setCaster(caster); + barrier.lifetime = (int)(getProperty(DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)); + barrier.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); + barrier.setRotation((float)Math.toDegrees(MathHelper.atan2(-direction.x, direction.z)), barrier.rotationPitch); + barrier.setSizeMultiplier(scale); + barrier.setDelay(1 + 3 * index); // Delay 0 seems to move it down 1 block, no idea why + + if(!world.getEntitiesWithinAABB(barrier.getClass(), barrier.getEntityBoundingBox().offset(0, yOffset, 0)).isEmpty()) return null; + + return barrier; + } + +} diff --git a/src/main/java/electroblob/wizardry/util/GeometryUtils.java b/src/main/java/electroblob/wizardry/util/GeometryUtils.java index d13d2c7b..0b14fb76 100644 --- a/src/main/java/electroblob/wizardry/util/GeometryUtils.java +++ b/src/main/java/electroblob/wizardry/util/GeometryUtils.java @@ -100,6 +100,13 @@ public final class GeometryUtils { return new Vec3i(components[0], components[1], components[2]); } + /** + * Returns a normalised {@link Vec3d} with the same yaw angle as the given vector, but with a y component of zero. + */ + public static Vec3d horizontalise(Vec3d vec){ + return replaceComponent(vec, Axis.Y, 0).normalize(); + } + /** * 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. diff --git a/src/main/java/electroblob/wizardry/util/SpellModifiers.java b/src/main/java/electroblob/wizardry/util/SpellModifiers.java index 53f4a535..a0c30416 100644 --- a/src/main/java/electroblob/wizardry/util/SpellModifiers.java +++ b/src/main/java/electroblob/wizardry/util/SpellModifiers.java @@ -58,20 +58,15 @@ public final class SpellModifiers { 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; -// } + private SpellModifiers(Map multiplierMap, Map syncedMultiplierMap){ + this.multiplierMap = multiplierMap; + this.syncedMultiplierMap = syncedMultiplierMap; + } + + /** Returns a deep copy (with copies of the underlying maps) of this {@code SpellModifiers} object. */ + public SpellModifiers copy(){ + return new SpellModifiers(new HashMap<>(this.multiplierMap), new HashMap<>(this.syncedMultiplierMap)); + } /** * Adds the given multiplier to this SpellModifiers object, using the string identifier that the given wand upgrade diff --git a/src/main/resources/assets/ebwizardry/lang/en_gb.lang b/src/main/resources/assets/ebwizardry/lang/en_gb.lang index 24b20d21..fb498fa7 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_gb.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_gb.lang @@ -829,6 +829,7 @@ 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_barrier=Frost Barrier spell.ebwizardry\:frost_ray=Frost Ray spell.ebwizardry\:frost_sigil=Frost Sigil spell.ebwizardry\:frost_step=Frost Step @@ -1012,6 +1013,7 @@ spell.ebwizardry\:forest_of_thorns.desc=Amidst the wood lies a hidden glade,\nIn 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_barrier.desc=Creates a barricade of ice in front of the caster that shields them from incoming attacks. The barrier lasts for 20 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. diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang index 3980aed6..82e12104 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_us.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang @@ -829,6 +829,7 @@ 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_barrier=Frost Barrier spell.ebwizardry\:frost_ray=Frost Ray spell.ebwizardry\:frost_sigil=Frost Sigil spell.ebwizardry\:frost_step=Frost Step @@ -1012,6 +1013,7 @@ spell.ebwizardry\:forest_of_thorns.desc=Amidst the wood lies a hidden glade,\nIn 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_barrier.desc=Creates a barricade of ice in front of the caster that shields them from incoming attacks. The barrier lasts for 20 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. diff --git a/src/main/resources/assets/ebwizardry/sounds.json b/src/main/resources/assets/ebwizardry/sounds.json index 19ab10ad..f74362cf 100644 --- a/src/main/resources/assets/ebwizardry/sounds.json +++ b/src/main/resources/assets/ebwizardry/sounds.json @@ -37,6 +37,8 @@ "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_barrier.deflect": {"category": "spells", "sounds": ["random/anvil_land"]}, + "entity.ice_barrier.extend": {"category": "spells", "sounds": ["ebwizardry:slice"]}, "entity.ice_spike.extend": {"category": "spells", "sounds": ["ebwizardry:slice"]}, "entity.lightning_sigil.trigger": {"category": "spells", "sounds": ["ebwizardry:arc1", "ebwizardry:arc2", "ebwizardry:arc3"]}, "entity.meteor.falling": {"category": "spells", "sounds": ["ebwizardry:flames_loop"]}, @@ -196,6 +198,7 @@ "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_barrier": {"category": "spells", "sounds": []}, "spell.frost_ray.start": {"category": "spells", "sounds": ["ebwizardry:frost_start"]}, "spell.frost_ray.loop": {"category": "spells", "sounds": ["ebwizardry:frost_loop"]}, "spell.frost_ray.end": {"category": "spells", "sounds": ["ebwizardry:frost_end"]}, diff --git a/src/main/resources/assets/ebwizardry/spells/frost_barrier.json b/src/main/resources/assets/ebwizardry/spells/frost_barrier.json new file mode 100644 index 00000000..6b7fc5b9 --- /dev/null +++ b/src/main/resources/assets/ebwizardry/spells/frost_barrier.json @@ -0,0 +1,22 @@ +{ + "enabled": { + "book": true, + "scroll": true, + "wands": true, + "npcs": true, + "dispensers": true, + "commands": true, + "treasure": true, + "trades": true, + "looting": true + }, + "tier": "apprentice", + "element": "ice", + "type": "defence", + "cost": 20, + "chargeup": 0, + "cooldown": 50, + "base_properties": { + "duration": 400 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ebwizardry/textures/entity/ice_barrier.png b/src/main/resources/assets/ebwizardry/textures/entity/ice_barrier.png new file mode 100644 index 00000000..9b6e1229 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/entity/ice_barrier.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/spells/frost_barrier.png b/src/main/resources/assets/ebwizardry/textures/spells/frost_barrier.png new file mode 100644 index 00000000..b53ac71d Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/spells/frost_barrier.png differ