Added the staff of remembrance

This commit is contained in:
Sollace 2019-03-11 20:50:06 +02:00
parent 6c8cb739cd
commit 2384663901
19 changed files with 372 additions and 49 deletions

View file

@ -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()));
}
}
}

View file

@ -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,

View file

@ -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<String> tooltip, ITooltipFlag flagIn) {
SpellAffinity affinity = getAffinity();
tooltip.add(affinity.getColourCode() + ClientLocale.format(affinity.getUnlocalizedName()));
}
@Override
public ActionResult<ItemStack> 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<ItemStack>(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();
}
}

View file

@ -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<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
ItemStack itemstack = player.getHeldItem(hand);
if (canBeThrown(itemstack)) {
toss(world, itemstack, player);
return new ActionResult<ItemStack>(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<String, AttributeModifier> getItemAttributeModifiers(EntityEquipmentSlot slot) {
Multimap<String, AttributeModifier> multimap = HashMultimap.create();

View file

@ -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);
}
}
}

View file

@ -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<ICaster<?>> toCaster(@Nullable Entity entity) {
if (entity instanceof ICaster<?>) {

View file

@ -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<E extends EntityLivingBase> extends IOwned<E>, 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<E extends EntityLivingBase> extends IOwned<E>, 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<E extends EntityLivingBase> extends IOwned<E>, ILevelle
default Stream<Entity> findAllEntitiesInRange(double radius) {
return VecHelper.findAllEntitiesInRange(getEntity(), getWorld(), getOrigin(), radius);
}
}

View file

@ -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<ICaster<?>> {
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<ICaster<?>> {
projectile.shoot(entity, entity.rotationPitch, entity.rotationYaw, 0, 1.5F, 1);
world.spawnEntity(projectile);
return projectile;
}
return null;
}
}

View file

@ -26,6 +26,10 @@ public enum SpellAffinity {
return this == BAD ? "curse" : "spell";
}
public String getUnlocalizedName() {
return "affinity." + getTranslationKey() + ".name";
}
public int getCorruption() {
return corruption;
}

View file

@ -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
}

View file

@ -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);

View file

@ -48,6 +48,7 @@ public class SpellRegistry {
registerSpell(SpellSiphon::new);
registerSpell(SpellLight::new);
registerSpell(SpellChangelingTrap::new);
registerSpell(SpellScorch::new);
}
@Nullable

View file

@ -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);
}
}
}

View file

@ -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<T> {
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;

View file

@ -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<BlockPos> consumer, EnumFacing... directions) {
for (EnumFacing facing : directions) {
consumer.accept(origin.offset(facing));

View file

@ -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

View file

@ -0,0 +1,6 @@
{
"parent": "unicopia:item/handheld_staff",
"textures": {
"layer0": "unicopia:items/staff_remembrance"
}
}

View file

@ -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 }
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB