diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/Thrown.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/Thrown.java index 132d501b..2491a1dc 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/Thrown.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/Thrown.java @@ -3,11 +3,13 @@ package com.minelittlepony.unicopia.ability.magic; import javax.annotation.Nullable; import com.minelittlepony.unicopia.Affinity; -import com.minelittlepony.unicopia.UEntities; import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; +import com.minelittlepony.unicopia.projectile.ProjectileDelegate; + import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -15,23 +17,25 @@ import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvents; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; /** * Magic effects that can be thrown. */ -public interface Thrown extends Spell { +public interface Thrown extends Spell, ProjectileDelegate { - /** - * Called once the projectile lands either hitting the ground or an entity. - */ - default void onImpact(Caster caster, BlockPos pos, BlockState state) { - if (!caster.isClient()) { - update(caster); + @Override + default void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { + if (!projectile.isClient()) { + update(projectile); } } + @Override + default void onImpact(MagicProjectileEntity projectile, Entity entity) { + + } + /** * The amount of damage to be dealt when the projectile collides with an entity. */ @@ -64,24 +68,18 @@ public interface Thrown extends Spell { default MagicProjectileEntity toss(Caster caster) { World world = caster.getWorld(); - Entity entity = caster.getMaster(); + LivingEntity entity = caster.getMaster(); world.playSound(null, entity.getX(), entity.getY(), entity.getZ(), getThrowSound(caster), SoundCategory.NEUTRAL, 0.7F, 0.4F / (world.random.nextFloat() * 0.4F + 0.8F)); if (!caster.isClient()) { - Vec3d rot = entity.getRotationVec(1); - - MagicProjectileEntity projectile = new MagicProjectileEntity(UEntities.THROWN_ITEM, world, caster.getMaster(), entity.getRotationVec(1)); + MagicProjectileEntity projectile = new MagicProjectileEntity(world, entity); projectile.setItem(getCastAppearance(caster)); projectile.setThrowDamage(getThrowDamage(caster)); projectile.setSpell(this); projectile.setHydrophobic(); - projectile.updatePosition( - entity.getX() + rot.x * 4, - entity.getBodyY(0.5D) + 0.5, - projectile.getZ() + rot.z * 4 - ); + projectile.setProperties(entity, entity.pitch, entity.yaw, 0, 1.5F, 1); world.spawnEntity(projectile); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/FireSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/FireSpell.java index aa1d6632..df223abd 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/FireSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/FireSpell.java @@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Magical; import com.minelittlepony.unicopia.ability.magic.Thrown; import com.minelittlepony.unicopia.block.state.StateMaps; +import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.VecHelper; @@ -55,9 +56,9 @@ public class FireSpell extends AbstractRangedAreaSpell implements Thrown { } @Override - public void onImpact(Caster caster, BlockPos pos, BlockState state) { - if (!caster.isClient()) { - caster.getWorld().createExplosion(caster.getMaster(), pos.getX(), pos.getY(), pos.getZ(), 2, DestructionType.DESTROY); + public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { + if (!projectile.isClient()) { + projectile.getWorld().createExplosion(projectile.getMaster(), pos.getX(), pos.getY(), pos.getZ(), 2, DestructionType.DESTROY); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Equine.java b/src/main/java/com/minelittlepony/unicopia/entity/Equine.java index 14298366..11d865b8 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Equine.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Equine.java @@ -1,11 +1,14 @@ package com.minelittlepony.unicopia.entity; +import java.util.Optional; + import javax.annotation.Nullable; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.util.NbtSerialisable; import net.minecraft.entity.Entity; +import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.projectile.ProjectileEntity; import net.minecraft.util.Tickable; @@ -38,7 +41,6 @@ public interface Equine extends NbtSerialisable, Tickable { return false; } - /** * Event triggered when this entity is hit by a projectile. */ @@ -53,6 +55,13 @@ public interface Equine extends NbtSerialisable, Tickable { } + /** + * Called when an entity is harmed. + */ + default Optional onDamage(DamageSource source, float amount) { + return Optional.empty(); + } + @Nullable static > T of(Entity entity) { return PonyContainer.of(entity) diff --git a/src/main/java/com/minelittlepony/unicopia/item/JarItem.java b/src/main/java/com/minelittlepony/unicopia/item/JarItem.java new file mode 100644 index 00000000..2cbb8252 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/JarItem.java @@ -0,0 +1,148 @@ +package com.minelittlepony.unicopia.item; + +import com.minelittlepony.unicopia.entity.IItemEntity; +import com.minelittlepony.unicopia.entity.ItemImpl; +import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; +import com.minelittlepony.unicopia.projectile.ProjectileDelegate; +import com.minelittlepony.unicopia.util.WorldEvent; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.DispenserBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.LightningEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ArmorItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.stat.Stats; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.level.ServerWorldProperties; + +public class JarItem extends Item implements ProjectileDelegate, ItemImpl.TickableItem { + + private final boolean rain; + private final boolean thunder; + private final boolean lightning; + + public JarItem(Settings settings, boolean rain, boolean thunder, boolean lightning) { + super(settings); + this.rain = rain; + this.thunder = thunder; + this.lightning = lightning; + + DispenserBlock.registerBehavior(this, ArmorItem.DISPENSER_BEHAVIOR); + } + + @Override + public TypedActionResult use(World world, PlayerEntity player, Hand hand) { + ItemStack stack = player.getStackInHand(hand); + + world.playSound(null, player.getX(), player.getY(), player.getZ(), + SoundEvents.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, + 0.5F, + 0.4F / (RANDOM.nextFloat() * 0.4F + 0.8F)); + + if (!world.isClient) { + MagicProjectileEntity projectile = new MagicProjectileEntity(world, player); + projectile.setItem(stack); + projectile.setThrowDamage(0.5F); + projectile.setProperties(player, player.pitch, player.yaw, 0, 1.5F, 1); + + world.spawnEntity(projectile); + } + + player.incrementStat(Stats.USED.getOrCreateStat(this)); + + if (!player.abilities.creativeMode) { + stack.decrement(1); + } + + return TypedActionResult.success(stack, world.isClient()); + } + + + @Override + public ActionResult onGroundTick(IItemEntity item) { + ItemEntity entity = item.get().getMaster(); + + entity.setInvulnerable(true); + + if (!lightning + && !entity.world.isClient + && !entity.removed + && entity.getAge() > 100 + && entity.world.isThundering() + && entity.world.isSkyVisible(entity.getBlockPos()) + && entity.world.random.nextInt(130) == 0) { + LightningEntity lightning = EntityType.LIGHTNING_BOLT.create(entity.world); + lightning.refreshPositionAfterTeleport(entity.getX(), entity.getY(), entity.getZ()); + + entity.remove(); + entity.world.spawnEntity(lightning); + + ItemEntity neu = EntityType.ITEM.create(entity.world); + neu.copyPositionAndRotation(entity); + neu.setStack(new ItemStack(this == UItems.RAIN_CLOUD_JAR ? UItems.STORM_CLOUD_JAR : UItems.LIGHTNING_JAR)); + neu.setInvulnerable(true); + + entity.world.spawnEntity(neu); + + ItemEntity copy = EntityType.ITEM.create(entity.world); + copy.copyPositionAndRotation(entity); + copy.setInvulnerable(true); + copy.setStack(entity.getStack()); + copy.getStack().decrement(1); + + entity.world.spawnEntity(copy); + } + return ActionResult.PASS; + } + + @Override + public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { + onImpact(projectile); + } + + @Override + public void onImpact(MagicProjectileEntity projectile, Entity entity) { + onImpact(projectile); + } + + private void onImpact(MagicProjectileEntity projectile) { + + + if (!projectile.isClient()) { + ServerWorld world = (ServerWorld)projectile.world; + + if (rain || thunder) { + ServerWorldProperties props = ((ServerWorldProperties)world.getLevelProperties()); + + int time = Math.max(Math.max(props.getRainTime(), props.getThunderTime()), 40); + world.setWeather(0, time, rain, thunder); + } + + if (lightning) { + LightningEntity lightning = EntityType.LIGHTNING_BOLT.create(world); + lightning.refreshPositionAfterTeleport(projectile.getX(), projectile.getY(), projectile.getZ()); + + world.spawnEntity(lightning); + } + } + + if (rain || thunder) { + projectile.world.syncWorldEvent(WorldEvent.PROJECTILE_HIT, projectile.getBlockPos(), thunder ? 0x888888 : 0xF8F8F8); + } + + WorldEvent.play(WorldEvent.DESTROY_BLOCK, projectile.world, projectile.getBlockPos(), Blocks.GLASS.getDefaultState()); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 772d6258..4d69dfe7 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -47,6 +47,12 @@ public interface UItems { .equipmentSlot(FriendshipBraceletItem::getPreferredEquipmentSlot) )); + Item EMPTY_JAR = register("empty_jar", new JarItem(new Item.Settings().group(ItemGroup.DECORATIONS).maxCount(16).fireproof(), false, false, false)); + Item RAIN_CLOUD_JAR = register("rain_cloud_jar", new JarItem(new Item.Settings().group(ItemGroup.DECORATIONS).maxCount(1).fireproof(), true, false, false)); + Item STORM_CLOUD_JAR = register("storm_cloud_jar", new JarItem(new Item.Settings().group(ItemGroup.DECORATIONS).maxCount(1).fireproof(), true, true, false)); + Item LIGHTNING_JAR = register("lightning_jar", new JarItem(new Item.Settings().group(ItemGroup.DECORATIONS).maxCount(1).fireproof(), false, false, true)); + Item ZAP_APPLE_JAM_JAR = register("zap_apple_jam_jar", new JarItem(new Item.Settings().group(ItemGroup.DECORATIONS).maxCount(1).fireproof(), false, false, true)); + static T register(String name, T item) { ITEMS.add(item); if (item instanceof BlockItem) { diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java index 1b3211d2..e0af48aa 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java @@ -1,11 +1,11 @@ package com.minelittlepony.unicopia.projectile; import com.minelittlepony.unicopia.Affinity; +import com.minelittlepony.unicopia.UEntities; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Levelled; import com.minelittlepony.unicopia.ability.magic.Magical; import com.minelittlepony.unicopia.ability.magic.Spell; -import com.minelittlepony.unicopia.ability.magic.Thrown; import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.Physics; @@ -59,12 +59,8 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical, super(type, world); } - public MagicProjectileEntity(EntityType type, World world, LivingEntity thrower, Vec3d velocity) { - super(type, world); - refreshPositionAndAngles(thrower.getX(), thrower.getY(), thrower.getZ(), thrower.yaw, thrower.pitch); - refreshPosition(); - setVelocity(velocity); - setOwner(thrower); + public MagicProjectileEntity(World world, LivingEntity thrower) { + super(UEntities.THROWN_ITEM, thrower, world); } @Override @@ -249,10 +245,14 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical, if (hasSpell()) { Spell effect = getSpell(true); - if (effect instanceof Thrown) { - ((Thrown)effect).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos())); + if (effect instanceof ProjectileDelegate) { + ((ProjectileDelegate)effect).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos())); } } + + if (getItem().getItem() instanceof ProjectileDelegate) { + ((ProjectileDelegate)getItem().getItem()).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos())); + } } @Override @@ -266,6 +266,10 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical, if (entity != null) { entity.damage(DamageSource.thrownProjectile(this, getOwner()), getThrowDamage()); } + + if (getItem().getItem() instanceof ProjectileDelegate) { + ((ProjectileDelegate)getItem().getItem()).onImpact(this, entity); + } } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/ProjectileDelegate.java b/src/main/java/com/minelittlepony/unicopia/projectile/ProjectileDelegate.java new file mode 100644 index 00000000..9c4c33d4 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/projectile/ProjectileDelegate.java @@ -0,0 +1,17 @@ +package com.minelittlepony.unicopia.projectile; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; + +public interface ProjectileDelegate { + /** + * Called once the projectile lands either hitting the ground or an entity. + */ + void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state); + + /** + * Called once the projectile lands either hitting the ground or an entity. + */ + void onImpact(MagicProjectileEntity projectile, Entity entity); +} diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 3cf64b0c..6ef61e6a 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -16,6 +16,12 @@ "item.unicopia.cooked_zap_apple": "Cooked Zap Apple", "item.unicopia.zap_apple": "Zap Apple", + "item.unicopia.empty_jar": "Glass Jar", + "item.unicopia.rain_cloud_jar": "Rain Cloud in a Jar", + "item.unicopia.storm_cloud_jar": "Storm Cloud in a Jar", + "item.unicopia.lightning_jar": "Lightning in a Jar", + "item.unicopia.zap_apple_jam_jar": "Zap Apple Jam", + "item.unicopia.music_disc_pet": "Music Disc", "item.unicopia.music_disc_pet.desc": "Danial Ingram - pet", "item.unicopia.music_disc_popular": "Music Disc", diff --git a/src/main/resources/assets/unicopia/models/item/empty_jar.json b/src/main/resources/assets/unicopia/models/item/empty_jar.json new file mode 100644 index 00000000..7df21561 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/empty_jar.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/empty_jar" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/lightning_jar.json b/src/main/resources/assets/unicopia/models/item/lightning_jar.json new file mode 100644 index 00000000..a9255315 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/lightning_jar.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/lightning_jar" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/rain_cloud_jar.json b/src/main/resources/assets/unicopia/models/item/rain_cloud_jar.json new file mode 100644 index 00000000..46f325d2 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/rain_cloud_jar.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/rain_cloud_jar" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/storm_cloud_jar.json b/src/main/resources/assets/unicopia/models/item/storm_cloud_jar.json new file mode 100644 index 00000000..a1af2ea1 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/storm_cloud_jar.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/storm_cloud_jar" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/zap_apple_jam_jar.json b/src/main/resources/assets/unicopia/models/item/zap_apple_jam_jar.json new file mode 100644 index 00000000..394030ba --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/zap_apple_jam_jar.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/zap_apple_jam_jar" + } +} diff --git a/src/main/resources/assets/unicopia/textures/item/empty_jar.png b/src/main/resources/assets/unicopia/textures/item/empty_jar.png new file mode 100644 index 00000000..f8330704 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/empty_jar.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/lightning_jar.png b/src/main/resources/assets/unicopia/textures/item/lightning_jar.png new file mode 100644 index 00000000..0fea7577 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/lightning_jar.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/rain_cloud_jar.png b/src/main/resources/assets/unicopia/textures/item/rain_cloud_jar.png new file mode 100644 index 00000000..ceb51cca Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/rain_cloud_jar.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/storm_cloud_jar.png b/src/main/resources/assets/unicopia/textures/item/storm_cloud_jar.png new file mode 100644 index 00000000..d1d58a51 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/storm_cloud_jar.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/zap_apple_jam_jar.png b/src/main/resources/assets/unicopia/textures/item/zap_apple_jam_jar.png new file mode 100644 index 00000000..5a7cf320 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/zap_apple_jam_jar.png differ diff --git a/src/main/resources/data/unicopia/recipes/empty_jar.json b/src/main/resources/data/unicopia/recipes/empty_jar.json new file mode 100644 index 00000000..e4915306 --- /dev/null +++ b/src/main/resources/data/unicopia/recipes/empty_jar.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "*#*", + "* *", + "***" + ], + "key": { + "#": { + "tag": "minecraft:planks" + }, + "*": { + "item": "minecraft:glass" + } + }, + "result": { + "item": "unicopia:empty_jar", + "count": 7 + } +} \ No newline at end of file