From 238466390102a3c3fd38e72926ebe9a221bec6cd Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 11 Mar 2019 20:50:06 +0200 Subject: [PATCH] Added the staff of remembrance --- .../unicopia/entity/EntityProjectile.java | 15 +- .../minelittlepony/unicopia/init/UItems.java | 7 +- .../unicopia/item/ItemMagicStaff.java | 160 ++++++++++++++++++ .../unicopia/item/ItemStaff.java | 31 +--- .../unicopia/item/ItemTomato.java | 7 +- .../unicopia/spell/CasterUtils.java | 9 + .../unicopia/spell/ICaster.java | 25 ++- .../unicopia/spell/ITossedEffect.java | 17 +- .../unicopia/spell/SpellAffinity.java | 4 + .../unicopia/spell/SpellAwkward.java | 2 +- .../unicopia/spell/SpellChangelingTrap.java | 8 +- .../unicopia/spell/SpellRegistry.java | 1 + .../unicopia/spell/SpellScorch.java | 82 +++++++++ .../unicopia/tossable/ITossable.java | 5 +- .../com/minelittlepony/util/PosHelper.java | 15 ++ .../resources/assets/unicopia/lang/en_US.lang | 5 + .../models/item/staff_remembrance.json | 6 + .../unicopia/recipes/staff_remembrence.json | 22 +++ .../textures/items/staff_remembrance.png | Bin 0 -> 3244 bytes 19 files changed, 372 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/item/ItemMagicStaff.java create mode 100644 src/main/java/com/minelittlepony/unicopia/spell/SpellScorch.java create mode 100644 src/main/resources/assets/unicopia/models/item/staff_remembrance.json create mode 100644 src/main/resources/assets/unicopia/recipes/staff_remembrence.json create mode 100644 src/main/resources/assets/unicopia/textures/items/staff_remembrance.png diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java index 454b83f2..cf552a0c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java @@ -153,8 +153,19 @@ public class EntityProjectile extends EntitySnowball implements IMagicals, ICast @Override public void onUpdate() { + + if (!world.isRemote) { + if (Math.abs(motionX) < 0.01 && Math.abs(motionZ) < 0.01 && Math.abs(motionY) < 0.01) { + setDead(); + } + } + super.onUpdate(); + if (ticksExisted % 1000 == 0) { + setNoGravity(false); + } + if (hasEffect()) { if (getEffect().getDead()) { setDead(); @@ -211,13 +222,13 @@ public class EntityProjectile extends EntitySnowball implements IMagicals, ICast Item item = getItem().getItem(); if (item instanceof ITossableItem) { - ((ITossableItem)item).onImpact(world, result.getBlockPos(), world.getBlockState(result.getBlockPos())); + ((ITossableItem)item).onImpact(this, result.getBlockPos(), world.getBlockState(result.getBlockPos())); } if (hasEffect()) { IMagicEffect effect = this.getEffect(); if (effect instanceof ITossable) { - ((ITossable)effect).onImpact(world, result.getBlockPos(), world.getBlockState(result.getBlockPos())); + ((ITossable)effect).onImpact(this, result.getBlockPos(), world.getBlockState(result.getBlockPos())); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/init/UItems.java b/src/main/java/com/minelittlepony/unicopia/init/UItems.java index 15e737f9..fbbceeea 100644 --- a/src/main/java/com/minelittlepony/unicopia/init/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/init/UItems.java @@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.item.ItemCereal; import com.minelittlepony.unicopia.item.ItemCloud; import com.minelittlepony.unicopia.item.ItemCurse; import com.minelittlepony.unicopia.item.ItemFruitLeaves; +import com.minelittlepony.unicopia.item.ItemMagicStaff; import com.minelittlepony.unicopia.item.ItemMoss; import com.minelittlepony.unicopia.item.ItemOfHolding; import com.minelittlepony.unicopia.item.ItemRottenApple; @@ -22,6 +23,7 @@ import com.minelittlepony.unicopia.item.UItemDecoration; import com.minelittlepony.unicopia.item.UItemSlab; import com.minelittlepony.unicopia.item.URecord; import com.minelittlepony.unicopia.spell.SpellRegistry; +import com.minelittlepony.unicopia.spell.SpellScorch; import net.minecraft.block.BlockDoublePlant; import net.minecraft.block.BlockFlower; @@ -140,6 +142,7 @@ public class UItems { public static final ItemSpellbook spellbook = new ItemSpellbook(Unicopia.MODID, "spellbook"); public static final Item staff_meadow_brook = new ItemStaff(Unicopia.MODID, "staff_meadow_brook").setMaxDamage(2); + public static final Item staff_remembrance = new ItemMagicStaff(Unicopia.MODID, "staff_remembrance", new SpellScorch()); public static final ItemMoss moss = new ItemMoss(Unicopia.MODID, "moss"); @@ -243,7 +246,7 @@ public class UItems { cloud_farmland, mist_door, library_door, bakery_door, anvil, bag_of_holding, spell, curse, spellbook, mug, enchanted_torch, - staff_meadow_brook, alicorn_amulet, + staff_meadow_brook, staff_remembrance, alicorn_amulet, alfalfa_seeds, alfalfa_leaves, cereal, sugar_cereal, sugar_block, @@ -278,7 +281,7 @@ public class UItems { cloud_farmland, mist_door, library_door, bakery_door, anvil, bag_of_holding, spell, curse, spellbook, mug, enchanted_torch, - staff_meadow_brook, alicorn_amulet, + staff_meadow_brook, staff_remembrance, alicorn_amulet, alfalfa_seeds, alfalfa_leaves, cereal, sugar_cereal, sugar_block, diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemMagicStaff.java b/src/main/java/com/minelittlepony/unicopia/item/ItemMagicStaff.java new file mode 100644 index 00000000..8919f32e --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemMagicStaff.java @@ -0,0 +1,160 @@ +package com.minelittlepony.unicopia.item; + +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.minelittlepony.unicopia.Predicates; +import com.minelittlepony.unicopia.power.IPower; +import com.minelittlepony.unicopia.spell.CasterUtils; +import com.minelittlepony.unicopia.spell.IAligned; +import com.minelittlepony.unicopia.spell.ICaster; +import com.minelittlepony.unicopia.spell.ITossedEffect; +import com.minelittlepony.unicopia.spell.SpellAffinity; +import com.minelittlepony.unicopia.tossable.ITossableItem; +import com.minelittlepony.util.lang.ClientLocale; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; +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.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class ItemMagicStaff extends ItemStaff implements IAligned, ITossableItem { + + @Nonnull + private final ITossedEffect effect; + + public ItemMagicStaff(String domain, String name, @Nonnull ITossedEffect effect) { + super(domain, name); + + this.effect = effect; + setMaxDamage(500); + } + + @Override + public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { + SpellAffinity affinity = getAffinity(); + tooltip.add(affinity.getColourCode() + ClientLocale.format(affinity.getUnlocalizedName())); + } + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { + if (Predicates.MAGI.test(player) && hand == EnumHand.MAIN_HAND) { + ItemStack itemstack = player.getHeldItem(hand); + + player.setActiveHand(hand); + + return new ActionResult(EnumActionResult.SUCCESS, itemstack); + } + + return super.onItemRightClick(world, player, hand); + } + + @Override + public void onPlayerStoppedUsing(ItemStack itemstack, World world, EntityLivingBase entity, int timeLeft) { + if (Predicates.MAGI.test(entity) && entity instanceof EntityPlayer) { + + int i = getMaxItemUseDuration(itemstack) - timeLeft; + + if (i > 10) { + if (canBeThrown(itemstack)) { + toss(world, itemstack, (EntityPlayer)entity); + } + } + } + } + + @Override + protected boolean castContainedEffect(ItemStack stack, EntityLivingBase target, EntityLivingBase attacker) { + if (attacker.isSneaking()) { + stack.damageItem(50, attacker); + + if (attacker instanceof EntityPlayer) { + IPower.takeFromPlayer((EntityPlayer)attacker, 4); + } + + onImpact( + CasterUtils.toCaster(target).orElseGet(() -> CasterUtils.near(target)), + target.getPosition(), + target.getEntityWorld().getBlockState(target.getPosition()) + ); + + return true; + } + + return false; + } + + public void onUpdate(ItemStack stack, World world, Entity entity, int itemSlot, boolean isSelected) { + + if (entity instanceof EntityLivingBase) { + EntityLivingBase living = (EntityLivingBase)entity; + + if (living.getActiveItemStack().getItem() == this) { + Vec3d eyes = entity.getPositionEyes(1); + + float i = getMaxItemUseDuration(stack) - living.getItemInUseCount(); + + world.spawnParticle(i > 150 ? EnumParticleTypes.SMOKE_LARGE : EnumParticleTypes.CLOUD, eyes.x, eyes.y, eyes.z, + (world.rand.nextGaussian() - 0.5) / 10, + (world.rand.nextGaussian() - 0.5) / 10, + (world.rand.nextGaussian() - 0.5) / 10 + ); + world.playSound(null, entity.getPosition(), SoundEvents.ENTITY_GUARDIAN_ATTACK, SoundCategory.PLAYERS, 1, i / 20); + + if (i > 200) { + living.resetActiveHand(); + living.attackEntityFrom(DamageSource.MAGIC, 1200); + onImpact( + CasterUtils.toCaster(entity).orElseGet(() -> CasterUtils.near(entity)), + entity.getPosition(), + entity.getEntityWorld().getBlockState(entity.getPosition()) + ); + } + } + } + + } + + public int getMaxItemUseDuration(ItemStack stack) { + return 72000; + } + + @Override + public boolean canBeThrown(ItemStack stack) { + return true; + } + + @Override + public void toss(World world, ItemStack stack, EntityPlayer player) { + CasterUtils.toCaster(player).ifPresent(effect::toss); + + IPower.takeFromPlayer(player, 4); + + stack.damageItem(1, player); + } + + @Override + public void onImpact(ICaster caster, BlockPos pos, IBlockState state) { + effect.onImpact(caster, pos, state); + } + + @Override + public SpellAffinity getAffinity() { + return effect.getAffinity(); + } + +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemStaff.java b/src/main/java/com/minelittlepony/unicopia/item/ItemStaff.java index a35bd838..ef1091fb 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ItemStaff.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemStaff.java @@ -8,11 +8,9 @@ import javax.annotation.Nullable; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.minelittlepony.unicopia.Predicates; -import com.minelittlepony.unicopia.tossable.ITossableItem; import com.minelittlepony.util.lang.ClientLocale; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -25,15 +23,11 @@ import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemSword; -import net.minecraft.util.ActionResult; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; -public class ItemStaff extends ItemSword implements ITossableItem { +public class ItemStaff extends ItemSword { protected static final UUID ATTACK_REACH_MODIFIER = UUID.fromString("FA235E1C-4280-A865-B01B-CBAE9985ACA3"); @@ -46,19 +40,6 @@ public class ItemStaff extends ItemSword implements ITossableItem { setMaxStackSize(1); } - @Override - public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { - ItemStack itemstack = player.getHeldItem(hand); - - if (canBeThrown(itemstack)) { - toss(world, itemstack, player); - - return new ActionResult(EnumActionResult.SUCCESS, itemstack); - } - - return super.onItemRightClick(world, player, hand); - } - @Override public boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity target) { World w = player.getEntityWorld(); @@ -113,16 +94,6 @@ public class ItemStaff extends ItemSword implements ITossableItem { return EnumAction.BOW; } - @Override - public boolean canBeThrown(ItemStack stack) { - return false; - } - - @Override - public void onImpact(World world, BlockPos pos, IBlockState state) { - - } - @Override public Multimap getItemAttributeModifiers(EntityEquipmentSlot slot) { Multimap multimap = HashMultimap.create(); diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java b/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java index 75e9ab6e..3690aeb5 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.item; import com.minelittlepony.unicopia.forgebullshit.IMultiItem; import com.minelittlepony.unicopia.player.PlayerSpeciesList; +import com.minelittlepony.unicopia.spell.ICaster; import com.minelittlepony.unicopia.tossable.ITossableItem; import net.minecraft.block.material.Material; @@ -96,9 +97,9 @@ public class ItemTomato extends ItemFood implements ITossableItem, IMultiItem { } @Override - public void onImpact(World world, BlockPos pos, IBlockState state) { - if (!world.isRemote && state.getMaterial() == Material.GLASS) { - world.destroyBlock(pos, true); + public void onImpact(ICaster caster, BlockPos pos, IBlockState state) { + if (caster.isLocal() && state.getMaterial() == Material.GLASS) { + caster.getWorld().destroyBlock(pos, true); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/CasterUtils.java b/src/main/java/com/minelittlepony/unicopia/spell/CasterUtils.java index 6060a004..a56c0f34 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/CasterUtils.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/CasterUtils.java @@ -3,10 +3,12 @@ package com.minelittlepony.unicopia.spell; import java.util.Optional; import java.util.stream.Stream; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.common.collect.Streams; import com.minelittlepony.unicopia.Predicates; +import com.minelittlepony.unicopia.entity.EntitySpell; import com.minelittlepony.unicopia.player.PlayerSpeciesList; import net.minecraft.entity.Entity; @@ -71,6 +73,13 @@ public class CasterUtils { .anyMatch(s -> s.equals(effectName)); } + public static ICaster near(@Nonnull Entity entity) { + EntitySpell caster = new EntitySpell(entity.world); + caster.copyLocationAndAnglesFrom(entity); + + return caster; + } + public static Optional> toCaster(@Nullable Entity entity) { if (entity instanceof ICaster) { diff --git a/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java b/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java index 2e1204ba..e662b93a 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java @@ -7,6 +7,7 @@ import java.util.stream.Stream; import javax.annotation.Nullable; +import com.minelittlepony.unicopia.entity.EntitySpell; import com.minelittlepony.unicopia.player.IOwned; import com.minelittlepony.unicopia.power.IPower; import com.minelittlepony.util.shape.IShape; @@ -59,6 +60,20 @@ public interface ICaster extends IOwned, ILevelle return getEntity().getEntityWorld(); } + /** + * Returns true if we're executing on the client. + */ + default boolean isRemote() { + return getWorld().isRemote; + } + + /** + * Returns true if we're executing on the server. + */ + default boolean isLocal() { + return !isRemote(); + } + /** * Gets the center position where this caster is located. */ @@ -66,6 +81,14 @@ public interface ICaster extends IOwned, ILevelle return getEntity().getPosition(); } + default ICaster at(BlockPos newOrigin) { + EntitySpell spell = new EntitySpell(getWorld()); + spell.setPosition(newOrigin.getX(), newOrigin.getY(), newOrigin.getZ()); + spell.setOwner(getOwner()); + + return spell; + } + default Vec3d getOriginVector() { return getEntity().getPositionVector(); } @@ -99,6 +122,4 @@ public interface ICaster extends IOwned, ILevelle default Stream findAllEntitiesInRange(double radius) { return VecHelper.findAllEntitiesInRange(getEntity(), getWorld(), getOrigin(), radius); } - - } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/ITossedEffect.java b/src/main/java/com/minelittlepony/unicopia/spell/ITossedEffect.java index 8f3dc5e9..c39cf7ec 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/ITossedEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/ITossedEffect.java @@ -1,29 +1,38 @@ package com.minelittlepony.unicopia.spell; +import javax.annotation.Nullable; + import com.minelittlepony.unicopia.entity.EntityProjectile; import com.minelittlepony.unicopia.init.UItems; import com.minelittlepony.unicopia.tossable.ITossable; import net.minecraft.entity.Entity; +import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; import net.minecraft.world.World; public interface ITossedEffect extends IMagicEffect, ITossable> { + default SoundEvent getThrowSound(ICaster caster) { + return SoundEvents.ITEM_CHORUS_FRUIT_TELEPORT; + } + default ItemStack getCastAppearance(ICaster caster) { Item item = this.getAffinity() == SpellAffinity.BAD ? UItems.curse : UItems.spell; return SpellRegistry.instance().enchantStack(new ItemStack(item), getName()); } - default void toss(ICaster caster) { + @Nullable + default EntityProjectile toss(ICaster caster) { World world = caster.getWorld(); Entity entity = caster.getOwner(); - world.playSound(null, entity.posX, entity.posY, entity.posZ, getThrowSound(caster), SoundCategory.NEUTRAL, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + world.playSound(null, entity.posX, entity.posY, entity.posZ, getThrowSound(caster), SoundCategory.NEUTRAL, 0.7F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); if (!world.isRemote) { EntityProjectile projectile = new EntityProjectile(world, caster.getOwner()); @@ -36,6 +45,10 @@ public interface ITossedEffect extends IMagicEffect, ITossable> { projectile.shoot(entity, entity.rotationPitch, entity.rotationYaw, 0, 1.5F, 1); world.spawnEntity(projectile); + + return projectile; } + + return null; } } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellAffinity.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellAffinity.java index e8e3dda5..8897cae8 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellAffinity.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellAffinity.java @@ -26,6 +26,10 @@ public enum SpellAffinity { return this == BAD ? "curse" : "spell"; } + public String getUnlocalizedName() { + return "affinity." + getTranslationKey() + ".name"; + } + public int getCorruption() { return corruption; } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellAwkward.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellAwkward.java index 8a54ea5a..ab05017d 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellAwkward.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellAwkward.java @@ -71,7 +71,7 @@ public class SpellAwkward extends AbstractSpell implements ITossedEffect, IUseAc } @Override - public void onImpact(World world, BlockPos pos, IBlockState state) { + public void onImpact(ICaster caster, BlockPos pos, IBlockState state) { // noop } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellChangelingTrap.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellChangelingTrap.java index 787603cb..45f447d5 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellChangelingTrap.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellChangelingTrap.java @@ -5,7 +5,6 @@ import com.minelittlepony.unicopia.init.USounds; import com.minelittlepony.unicopia.player.IPlayer; import com.minelittlepony.unicopia.player.PlayerSpeciesList; import com.minelittlepony.util.WorldEvent; -import com.minelittlepony.util.vector.VecHelper; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; @@ -20,7 +19,6 @@ import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; public class SpellChangelingTrap extends AbstractSpell implements ITossedEffect, IAttachedEffect { @@ -154,9 +152,9 @@ public class SpellChangelingTrap extends AbstractSpell implements ITossedEffect, } @Override - public void onImpact(World world, BlockPos pos, IBlockState state) { - if (!world.isRemote) { - VecHelper.findAllEntitiesInRange(null, world, pos, 5) + public void onImpact(ICaster caster, BlockPos pos, IBlockState state) { + if (caster.isLocal()) { + caster.findAllEntitiesInRange(5) .filter(e -> e instanceof EntityPlayer) .map(e -> PlayerSpeciesList.instance().getPlayer((EntityPlayer)e)) .forEach(this::entrap); diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellRegistry.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellRegistry.java index 3aed186f..7f406941 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellRegistry.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellRegistry.java @@ -48,6 +48,7 @@ public class SpellRegistry { registerSpell(SpellSiphon::new); registerSpell(SpellLight::new); registerSpell(SpellChangelingTrap::new); + registerSpell(SpellScorch::new); } @Nullable diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellScorch.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellScorch.java new file mode 100644 index 00000000..cbf50779 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellScorch.java @@ -0,0 +1,82 @@ +package com.minelittlepony.unicopia.spell; + +import javax.annotation.Nullable; + +import com.minelittlepony.unicopia.entity.EntityProjectile; +import com.minelittlepony.unicopia.init.UParticles; +import com.minelittlepony.util.PosHelper; +import com.minelittlepony.util.shape.Sphere; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; + +public class SpellScorch extends SpellFire implements ITossedEffect { + + @Override + public String getName() { + return "scorch"; + } + + @Override + public boolean isCraftable() { + return false; + } + + @Override + public int getTint() { + return 0; + } + + @Override + public boolean update(ICaster source) { + + BlockPos pos = PosHelper.findSolidGroundAt(source.getWorld(), source.getOrigin()); + + IBlockState state = source.getWorld().getBlockState(pos); + + IBlockState newState = affected.getConverted(state); + + if (!state.equals(newState)) { + source.getWorld().setBlockState(pos, newState, 3); + source.spawnParticles(new Sphere(false, 1), 5, p -> { + p = PosHelper.offset(p, pos); + + source.getWorld().spawnParticle(EnumParticleTypes.SMOKE_NORMAL, + p.x, p.y, p.z, 0, 0, 0); + }); + } + + return true; + } + + @Override + public void render(ICaster source) { + source.spawnParticles(EnumParticleTypes.FLAME.getParticleID(), 3); + source.spawnParticles(UParticles.UNICORN_MAGIC, 3, getTint()); + } + + @Override + public SpellAffinity getAffinity() { + return SpellAffinity.BAD; + } + + @Override + @Nullable + public EntityProjectile toss(ICaster caster) { + EntityProjectile projectile = ITossedEffect.super.toss(caster); + + if (projectile != null) { + projectile.setNoGravity(true); + } + + return projectile; + } + + @Override + public void onImpact(ICaster caster, BlockPos pos, IBlockState state) { + if (caster.isLocal()) { + caster.getWorld().newExplosion(caster.getOwner(), pos.getX(), pos.getY(), pos.getZ(), 2, true, true); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/tossable/ITossable.java b/src/main/java/com/minelittlepony/unicopia/tossable/ITossable.java index b95b0c9a..15b24194 100644 --- a/src/main/java/com/minelittlepony/unicopia/tossable/ITossable.java +++ b/src/main/java/com/minelittlepony/unicopia/tossable/ITossable.java @@ -1,13 +1,14 @@ package com.minelittlepony.unicopia.tossable; +import com.minelittlepony.unicopia.spell.ICaster; + import net.minecraft.block.state.IBlockState; import net.minecraft.init.SoundEvents; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; public interface ITossable { - void onImpact(World world, BlockPos pos, IBlockState state); + void onImpact(ICaster caster, BlockPos pos, IBlockState state); default SoundEvent getThrowSound(T stack) { return SoundEvents.ENTITY_SNOWBALL_THROW; diff --git a/src/main/java/com/minelittlepony/util/PosHelper.java b/src/main/java/com/minelittlepony/util/PosHelper.java index 6e6c1ebd..dcd6a741 100644 --- a/src/main/java/com/minelittlepony/util/PosHelper.java +++ b/src/main/java/com/minelittlepony/util/PosHelper.java @@ -12,10 +12,25 @@ import com.minelittlepony.util.shape.IShape; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; import net.minecraft.util.math.BlockPos.MutableBlockPos; +import net.minecraft.world.World; public class PosHelper { + public static Vec3d offset(Vec3d a, Vec3i b) { + return a.add(b.getX(), b.getY(), b.getZ()); + } + + public static BlockPos findSolidGroundAt(World world, BlockPos pos) { + while ((pos.getY() > 0 || !world.isOutsideBuildHeight(pos)) + && (world.isAirBlock(pos) || world.getBlockState(pos).getBlock().isReplaceable(world, pos))) { + pos = pos.down(); + } + + return pos; + } + public static void all(BlockPos origin, Consumer consumer, EnumFacing... directions) { for (EnumFacing facing : directions) { consumer.accept(origin.offset(facing)); diff --git a/src/main/resources/assets/unicopia/lang/en_US.lang b/src/main/resources/assets/unicopia/lang/en_US.lang index cb61a11c..6fa1b336 100644 --- a/src/main/resources/assets/unicopia/lang/en_US.lang +++ b/src/main/resources/assets/unicopia/lang/en_US.lang @@ -43,6 +43,7 @@ item.chitin_shell.name=Chitinous Shell item.moss.name=Moss item.staff_meadow_brook.name=Meadow Brook's Staff item.staff_meadow_brook.tagline=It's a big stick +item.staff_remembrance.name=Staff of Remembrance item.alicorn_amulet.name=The Alicorn Amulet item.alicorn_amulet.tagline=Time Worn: %s @@ -53,6 +54,10 @@ item.gem.enchanted.name=Gem of %s item.corrupted_gem.name=Fractured Gem item.corrupted_gem.enchanted.name=Fractured Gem of %s +affinity.good.name=Pure +affinity.neutral.name=Neutral +affinity.bad.name=Corrupt + spell.shield.name=Defense spell.shield.tagline=Protection I diff --git a/src/main/resources/assets/unicopia/models/item/staff_remembrance.json b/src/main/resources/assets/unicopia/models/item/staff_remembrance.json new file mode 100644 index 00000000..97844a9d --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/staff_remembrance.json @@ -0,0 +1,6 @@ +{ + "parent": "unicopia:item/handheld_staff", + "textures": { + "layer0": "unicopia:items/staff_remembrance" + } +} diff --git a/src/main/resources/assets/unicopia/recipes/staff_remembrence.json b/src/main/resources/assets/unicopia/recipes/staff_remembrence.json new file mode 100644 index 00000000..f1d1a408 --- /dev/null +++ b/src/main/resources/assets/unicopia/recipes/staff_remembrence.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " /*", + " / ", + "/ " + ], + "key": { + "/": [ + { "item": "minecraft:stick" } + ], + "*": [ + { + "item": "unicopia:gem", + "nbt": { + "spell": "fire" + } + } + ] + }, + "result": { "item": "unicopia:staff_remembrence", "count": 1 } +} diff --git a/src/main/resources/assets/unicopia/textures/items/staff_remembrance.png b/src/main/resources/assets/unicopia/textures/items/staff_remembrance.png new file mode 100644 index 0000000000000000000000000000000000000000..12454c123660abf201e68c81d3c26e7092d15bc5 GIT binary patch literal 3244 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 e7khpKzJkB$_Qvp&!mi%{0000