From c996701734564bb8ea284fa2c67c3194bac11607 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 6 Jan 2019 23:31:34 +0200 Subject: [PATCH] Fixed some issues with alpfalfa, added cloud farmland, added tomatos --- .../com/minelittlepony/unicopia/UBlocks.java | 9 +- .../minelittlepony/unicopia/UEntities.java | 45 ++++--- .../com/minelittlepony/unicopia/UItems.java | 14 +- .../com/minelittlepony/unicopia/Unicopia.java | 25 ++++ .../unicopia/block/BlockAlfalfa.java | 17 ++- .../unicopia/block/BlockCloud.java | 19 ++- .../unicopia/block/BlockCloudFarm.java | 125 +++++++++++++++++ .../unicopia/block/ITillable.java | 24 ++++ .../unicopia/block/UFarmland.java | 127 ++++++++++++++++++ .../unicopia/entity/EntityProjectile.java | 121 +++++++++++++++++ .../unicopia/item/ITossable.java | 105 +++++++++++++++ .../unicopia/item/ItemApple.java | 39 +++--- .../unicopia/item/ItemTomato.java | 91 +++++++++++++ .../player/PlayerGravityDelegate.java | 3 +- .../unicopia/render/RenderProjectile.java | 21 +++ .../com/minelittlepony/util/PosHelper.java | 11 ++ .../unicopia/blockstates/cloud_farmland.json | 12 ++ .../resources/assets/unicopia/lang/en_US.lang | 4 + .../unicopia/models/block/farmland/dry.json | 8 ++ .../unicopia/models/block/farmland/wet.json | 8 ++ .../models/item/cloudsdale_tomato.json | 6 + .../models/item/rotten_cloudsdale_tomato.json | 6 + .../unicopia/models/item/rotten_tomato.json | 6 + .../assets/unicopia/models/item/tomato.json | 6 + .../textures/blocks/cloud_farmland_dry.png | Bin 0 -> 3082 bytes .../textures/blocks/cloud_farmland_wet.png | Bin 0 -> 3076 bytes .../unicopia/textures/items/rotten_tomato.png | Bin 0 -> 3184 bytes .../assets/unicopia/textures/items/tomato.png | Bin 0 -> 3119 bytes 28 files changed, 802 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/block/BlockCloudFarm.java create mode 100644 src/main/java/com/minelittlepony/unicopia/block/ITillable.java create mode 100644 src/main/java/com/minelittlepony/unicopia/block/UFarmland.java create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/ITossable.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java create mode 100644 src/main/java/com/minelittlepony/unicopia/render/RenderProjectile.java create mode 100644 src/main/resources/assets/unicopia/blockstates/cloud_farmland.json create mode 100644 src/main/resources/assets/unicopia/models/block/farmland/dry.json create mode 100644 src/main/resources/assets/unicopia/models/block/farmland/wet.json create mode 100644 src/main/resources/assets/unicopia/models/item/cloudsdale_tomato.json create mode 100644 src/main/resources/assets/unicopia/models/item/rotten_cloudsdale_tomato.json create mode 100644 src/main/resources/assets/unicopia/models/item/rotten_tomato.json create mode 100644 src/main/resources/assets/unicopia/models/item/tomato.json create mode 100644 src/main/resources/assets/unicopia/textures/blocks/cloud_farmland_dry.png create mode 100644 src/main/resources/assets/unicopia/textures/blocks/cloud_farmland_wet.png create mode 100644 src/main/resources/assets/unicopia/textures/items/rotten_tomato.png create mode 100644 src/main/resources/assets/unicopia/textures/items/tomato.png diff --git a/src/main/java/com/minelittlepony/unicopia/UBlocks.java b/src/main/java/com/minelittlepony/unicopia/UBlocks.java index 0121dce5..f8c15c5b 100644 --- a/src/main/java/com/minelittlepony/unicopia/UBlocks.java +++ b/src/main/java/com/minelittlepony/unicopia/UBlocks.java @@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.block.BlockCloudAnvil; import com.minelittlepony.unicopia.block.BlockCloudSlab; import com.minelittlepony.unicopia.block.BlockCloudStairs; import com.minelittlepony.unicopia.block.BlockCloudDoor; +import com.minelittlepony.unicopia.block.BlockCloudFarm; import net.minecraft.block.Block; import net.minecraftforge.registries.IForgeRegistry; @@ -13,9 +14,9 @@ import net.minecraftforge.registries.IForgeRegistry; public class UBlocks { public static final BlockCloud cloud = new BlockCloud(UMaterials.cloud, Unicopia.MODID, "cloud_block"); - public static final BlockCloudStairs stairsCloud = new BlockCloudStairs(UBlocks.cloud.getDefaultState(), Unicopia.MODID, "cloud_stairs"); + public static final BlockCloudStairs cloud_stairs = new BlockCloudStairs(UBlocks.cloud.getDefaultState(), Unicopia.MODID, "cloud_stairs"); - public static final BlockCloudSlab cloud_double_slab = new BlockCloudSlab(true, UMaterials.cloud, Unicopia.MODID, "cloud_double_slab"); + public static final BlockCloudSlab double_cloud_slab = new BlockCloudSlab(true, UMaterials.cloud, Unicopia.MODID, "cloud_double_slab"); public static final BlockCloudSlab cloud_slab = new BlockCloudSlab(false, UMaterials.cloud, Unicopia.MODID, "cloud_slab"); public static final BlockCloudDoor mist_door = new BlockCloudDoor(UMaterials.cloud, Unicopia.MODID, "mist_door"); @@ -24,8 +25,10 @@ public class UBlocks { public static final BlockAlfalfa alfalfa = new BlockAlfalfa(Unicopia.MODID, "alfalfa"); + public static final BlockCloudFarm cloud_farmland = new BlockCloudFarm(Unicopia.MODID, "cloud_farmland"); + static void registerBlocks(IForgeRegistry registry) { - registry.registerAll(cloud, stairsCloud, cloud_double_slab, cloud_slab, mist_door, anvil, + registry.registerAll(cloud, cloud_stairs, double_cloud_slab, cloud_slab, mist_door, anvil, cloud_farmland, alfalfa); } } diff --git a/src/main/java/com/minelittlepony/unicopia/UEntities.java b/src/main/java/com/minelittlepony/unicopia/UEntities.java index dcaaae20..b58fd7a7 100644 --- a/src/main/java/com/minelittlepony/unicopia/UEntities.java +++ b/src/main/java/com/minelittlepony/unicopia/UEntities.java @@ -4,15 +4,18 @@ import com.minelittlepony.unicopia.entity.EntityCloud; import com.minelittlepony.unicopia.entity.EntityConstructionCloud; import com.minelittlepony.unicopia.entity.EntityRacingCloud; import com.minelittlepony.unicopia.entity.EntitySpell; +import com.minelittlepony.unicopia.entity.EntityProjectile; import com.minelittlepony.unicopia.entity.EntityWildCloud; import com.minelittlepony.unicopia.render.RenderCloud; import com.minelittlepony.unicopia.render.RenderGem; +import com.minelittlepony.unicopia.render.RenderProjectile; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList.EntityEggInfo; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.registry.EntityEntry; +import net.minecraftforge.fml.common.registry.EntityEntryBuilder; import net.minecraftforge.registries.IForgeRegistry; public class UEntities { @@ -20,25 +23,33 @@ public class UEntities { private static final int BRUSHES_CHARTREUSE = 0x7FFF00; static void init(IForgeRegistry registry) { - addEntity(registry, EntityCloud.class, "cloud", true, BRUSHES_ROYALBLUE, BRUSHES_CHARTREUSE); - addEntity(registry, EntityWildCloud.class, "wild_cloud", false, 0, 0); - addEntity(registry, EntityRacingCloud.class, "racing_cloud", false, 0, 0); - addEntity(registry, EntityConstructionCloud.class, "construction_cloud", false, 0, 0); - addEntity(registry, EntitySpell.class, "magic_spell", false, 0, 0); - } - - static void addEntity(IForgeRegistry registry, Class type, String name, boolean egg, int a, int b) { - EntityEntry entry = new EntityEntry(type, name).setRegistryName(Unicopia.MODID, name); - - if (egg) { - entry.setEgg(new EntityEggInfo(new ResourceLocation("unicopia", "cloud"), a, a)); - } - - registry.register(entry); + registry.registerAll( + new Entry(EntityCloud.class, "cloud").withEgg(BRUSHES_ROYALBLUE, BRUSHES_CHARTREUSE), + new Entry(EntityWildCloud.class, "wild_cloud"), + new Entry(EntityRacingCloud.class, "racing_cloud"), + new Entry(EntityConstructionCloud.class, "construction_cloud"), + new Entry(EntitySpell.class, "magic_spell"), + EntityEntryBuilder.create().entity(EntityProjectile.class).name("thrown_item").id(new ResourceLocation(Unicopia.MODID, "thrown_item"), 0).tracker(10, 5, true).build() + ); } static void preInit() { - RenderingRegistry.registerEntityRenderingHandler(EntityCloud.class, manager -> new RenderCloud(manager)); - RenderingRegistry.registerEntityRenderingHandler(EntitySpell.class, manager -> new RenderGem(manager)); + RenderingRegistry.registerEntityRenderingHandler(EntityCloud.class, RenderCloud::new); + RenderingRegistry.registerEntityRenderingHandler(EntitySpell.class, RenderGem::new); + RenderingRegistry.registerEntityRenderingHandler(EntityProjectile.class, RenderProjectile::new); + } + + static class Entry extends EntityEntry { + + public Entry(Class cls, String name) { + super(cls, name); + setRegistryName(Unicopia.MODID, name); + } + + Entry withEgg(int a, int b) { + setEgg(new EntityEggInfo(getRegistryName(), a, b)); + + return this; + } } } diff --git a/src/main/java/com/minelittlepony/unicopia/UItems.java b/src/main/java/com/minelittlepony/unicopia/UItems.java index f81395c3..c347a04d 100644 --- a/src/main/java/com/minelittlepony/unicopia/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/UItems.java @@ -5,6 +5,7 @@ import com.minelittlepony.unicopia.item.ItemCloud; import com.minelittlepony.unicopia.item.ItemCurse; import com.minelittlepony.unicopia.item.ItemOfHolding; import com.minelittlepony.unicopia.item.ItemSpell; +import com.minelittlepony.unicopia.item.ItemTomato; import com.minelittlepony.unicopia.item.UItemBlock; import com.minelittlepony.unicopia.item.UItemMultiTexture; import com.minelittlepony.unicopia.item.UItemSlab; @@ -57,7 +58,7 @@ public class UItems { }, INTERACT_WITH_CLOUDS) .setRegistryName(Unicopia.MODID, "cloud_block"); - public static final Item cloud_stairs = new UItemBlock(UBlocks.stairsCloud, INTERACT_WITH_CLOUDS) + public static final Item cloud_stairs = new UItemBlock(UBlocks.cloud_stairs, INTERACT_WITH_CLOUDS) .setTranslationKey("cloud_stairs") .setRegistryName(Unicopia.MODID, "cloud_stairs"); @@ -70,7 +71,7 @@ public class UItems { .setTranslationKey("mist_door") .setRegistryName(Unicopia.MODID, "mist_door"); - public static final Item cloud_slab = new UItemSlab(UBlocks.cloud_slab, UBlocks.cloud_slab, UBlocks.cloud_double_slab, INTERACT_WITH_CLOUDS) + public static final Item cloud_slab = new UItemSlab(UBlocks.cloud_slab, UBlocks.cloud_slab, UBlocks.double_cloud_slab, INTERACT_WITH_CLOUDS) .setTranslationKey("cloud_slab") .setRegistryName(Unicopia.MODID, "cloud_slab"); @@ -91,6 +92,9 @@ public class UItems { .setTranslationKey("cereal") .setRegistryName(Unicopia.MODID, "cereal"); + public static final ItemTomato tomato = new ItemTomato(Unicopia.MODID, "tomato", 4, 34); + public static final ItemTomato cloudsdale_tomato = new ItemTomato(Unicopia.MODID, "cloudsdale_tomato", 16, 4); + static void registerItems(IForgeRegistry registry) { RegistryLockSpinner.unlock(Item.REGISTRY); @@ -98,12 +102,10 @@ public class UItems { RegistryLockSpinner.lock(Item.REGISTRY); - - registry.registerAll(cloud_spawner, dew_drop, cloud_matter, cloud_block, cloud_stairs, cloud_slab, mist_door, anvil, bag_of_holding, spell, curse, - alfalfa_seeds, alfalfa_leaves, cereal); + alfalfa_seeds, alfalfa_leaves, cereal, tomato); if (UClient.isClientSide()) { registerAllVariants(apple, apple.getVariants()); @@ -121,6 +123,8 @@ public class UItems { registerAllVariants(alfalfa_seeds, "alfalfa_seeds"); registerAllVariants(alfalfa_leaves, "alfalfa_leaves"); registerAllVariants(cereal, "cereal"); + registerAllVariants(tomato, "tomato", "rotten_tomato"); + registerAllVariants(cloudsdale_tomato, "cloudsdale_tomato", "rotten_cloudsdale_tomato"); } registerFuels(); diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index b3bfd28e..58b0798b 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia; import net.minecraft.block.Block; import net.minecraft.block.BlockCrops; +import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; @@ -10,6 +11,8 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraftforge.client.event.ColorHandlerEvent; import net.minecraftforge.client.event.EntityViewRenderEvent; import net.minecraftforge.client.event.FOVUpdateEvent; @@ -20,6 +23,7 @@ import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.player.PlayerDropsEvent; import net.minecraftforge.event.entity.player.PlayerFlyableFallEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.entity.player.UseHoeEvent; import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @@ -27,6 +31,7 @@ import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.event.FMLServerStartingEvent; +import net.minecraftforge.fml.common.eventhandler.Event.Result; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent.Phase; @@ -38,6 +43,7 @@ import com.minelittlepony.jumpingcastle.api.IChannel; import com.minelittlepony.jumpingcastle.api.JumpingCastle; import com.minelittlepony.jumpingcastle.api.Target; import com.minelittlepony.unicopia.advancements.UAdvancements; +import com.minelittlepony.unicopia.block.ITillable; import com.minelittlepony.unicopia.client.particle.EntityMagicFX; import com.minelittlepony.unicopia.client.particle.EntityRaindropFX; import com.minelittlepony.unicopia.client.particle.Particles; @@ -193,6 +199,25 @@ public class Unicopia { } } + @SubscribeEvent + public static void onBlockTilled(UseHoeEvent event) { + BlockPos pos = event.getPos(); + World world = event.getWorld(); + + IBlockState state = world.getBlockState(pos); + + if (state.getBlock() instanceof ITillable) { + ITillable farm = ((ITillable)state.getBlock()); + + if (farm.canBeTilled(event.getCurrent(), event.getEntityPlayer(), world, state, pos)) { + + world.setBlockState(pos, farm.getFarmlandState(event.getCurrent(), event.getEntityPlayer(), world, state, pos)); + + event.setResult(Result.ALLOW); + } + } + } + @SubscribeEvent public static void onPlayerTick(TickEvent.PlayerTickEvent event) { if (event.phase == Phase.END) { diff --git a/src/main/java/com/minelittlepony/unicopia/block/BlockAlfalfa.java b/src/main/java/com/minelittlepony/unicopia/block/BlockAlfalfa.java index 71e3e4f4..f3d85d16 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/BlockAlfalfa.java +++ b/src/main/java/com/minelittlepony/unicopia/block/BlockAlfalfa.java @@ -19,6 +19,7 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.common.EnumPlantType; import net.minecraftforge.common.ForgeHooks; public class BlockAlfalfa extends BlockCrops { @@ -116,19 +117,20 @@ public class BlockAlfalfa extends BlockCrops { int max = getMaxAge(); if (age > max) { - growUpwards(world, pos.up(), world.getBlockState(pos.up()), age - max); + if (!(hasDown && hasTrunk)) { + growUpwards(world, pos.up(), world.getBlockState(pos.up()), age - max); + } age = max; } - boolean hasUp = world.getBlockState(pos.up()).getBlock() == this; if (hasDown && hasUp) { - world.setBlockState(pos, this.withAge(age).withProperty(HALF, Half.MIDDLE)); + world.setBlockState(pos, withAge(age).withProperty(HALF, Half.MIDDLE)); } else if (hasUp) { - world.setBlockState(pos, this.withAge(age).withProperty(HALF, Half.BOTTOM)); + world.setBlockState(pos, withAge(age).withProperty(HALF, Half.BOTTOM)); } else { - world.setBlockState(pos, this.withAge(age).withProperty(HALF, Half.TOP)); + world.setBlockState(pos, withAge(age).withProperty(HALF, Half.TOP)); } } @@ -269,6 +271,11 @@ public class BlockAlfalfa extends BlockCrops { return (Half)state.getValue(HALF); } + @Override + public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos) { + return EnumPlantType.Crop; + } + public static enum Half implements IStringSerializable { TOP, MIDDLE, diff --git a/src/main/java/com/minelittlepony/unicopia/block/BlockCloud.java b/src/main/java/com/minelittlepony/unicopia/block/BlockCloud.java index 68a5d0ba..756a81e0 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/BlockCloud.java +++ b/src/main/java/com/minelittlepony/unicopia/block/BlockCloud.java @@ -5,6 +5,8 @@ import java.util.List; import javax.annotation.Nullable; import com.minelittlepony.unicopia.CloudType; +import com.minelittlepony.unicopia.UBlocks; +import com.minelittlepony.unicopia.player.PlayerSpeciesList; import net.minecraft.block.Block; import net.minecraft.block.SoundType; @@ -25,7 +27,7 @@ import net.minecraft.util.NonNullList; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; -public class BlockCloud extends Block implements ICloudBlock { +public class BlockCloud extends Block implements ICloudBlock, ITillable { public static final PropertyEnum VARIANT = PropertyEnum.create("variant", CloudType.class); @@ -139,9 +141,9 @@ public class BlockCloud extends Block implements ICloudBlock { @Override public float getPlayerRelativeBlockHardness(IBlockState state, EntityPlayer player, World worldIn, BlockPos pos) { if (!CloudType.NORMAL.canInteract(player)) { - return -1; + return super.getPlayerRelativeBlockHardness(state, player, worldIn, pos); } - return super.getPlayerRelativeBlockHardness(state, player, worldIn, pos); + return -1; } @Override @@ -176,4 +178,15 @@ public class BlockCloud extends Block implements ICloudBlock { return (CloudType)blockState.getValue(VARIANT); } + @Override + public boolean canBeTilled(ItemStack hoe, EntityPlayer player, World world, IBlockState state, BlockPos pos) { + return PlayerSpeciesList.instance().getPlayer(player).getPlayerSpecies().canInteractWithClouds() + && ITillable.super.canBeTilled(hoe, player, world, state, pos); + } + + @Override + public IBlockState getFarmlandState(ItemStack hoe, EntityPlayer player, World world, IBlockState state, BlockPos pos) { + return UBlocks.cloud_farmland.getDefaultState(); + } + } diff --git a/src/main/java/com/minelittlepony/unicopia/block/BlockCloudFarm.java b/src/main/java/com/minelittlepony/unicopia/block/BlockCloudFarm.java new file mode 100644 index 00000000..57b548cf --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/block/BlockCloudFarm.java @@ -0,0 +1,125 @@ +package com.minelittlepony.unicopia.block; + +import java.util.List; + +import javax.annotation.Nullable; + +import com.minelittlepony.unicopia.CloudType; +import com.minelittlepony.unicopia.UBlocks; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public class BlockCloudFarm extends UFarmland implements ICloudBlock { + + public BlockCloudFarm(String domain, String name) { + super(domain, name); + } + + @Override + public boolean isTranslucent(IBlockState state) { + return true; + } + + @Override + public boolean isAir(IBlockState state, IBlockAccess world, BlockPos pos) { + return allowsFallingBlockToPass(state, world, pos); + } + + @Override + public BlockRenderLayer getRenderLayer() { + return BlockRenderLayer.TRANSLUCENT; + } + + @Override + public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing face) { + + IBlockState beside = world.getBlockState(pos.offset(face)); + + if (beside.getBlock() instanceof ICloudBlock) { + ICloudBlock cloud = ((ICloudBlock)beside.getBlock()); + + if ((face == EnumFacing.DOWN || face == EnumFacing.UP || cloud == this)) { + if (cloud.getCloudMaterialType(beside) == getCloudMaterialType(state)) { + return true; + } + } + } + + return super.doesSideBlockRendering(state, world, pos, face); + } + + @Override + public void onFallenUpon(World world, BlockPos pos, Entity entityIn, float fallDistance) { + if (entityIn.isSneaking()) { + super.onFallenUpon(world, pos, entityIn, fallDistance); + } else { + entityIn.fall(fallDistance, 0); + } + } + + @Override + public void onLanded(World worldIn, Entity entity) { + if (entity.isSneaking()) { + super.onLanded(worldIn, entity); + } else if (entity.motionY < 0) { + if (Math.abs(entity.motionY) >= 0.25) { + entity.motionY = -entity.motionY * 1.2; + } else { + entity.motionY = 0; + } + } + } + + @Override + public void onEntityCollision(World w, BlockPos pos, IBlockState state, Entity entity) { + if (getCanInteract(state, entity)) { + if (!entity.isSneaking() && Math.abs(entity.motionY) >= 0.25) { + entity.motionY += 0.0155 * (entity.fallDistance < 1 ? 1 : entity.fallDistance); + } else { + entity.motionY = 0; + } + + super.onEntityCollision(w, pos, state, entity); + } + } + + @Override + public boolean canEntityDestroy(IBlockState state, IBlockAccess world, BlockPos pos, Entity entity) { + return getCanInteract(state, entity) && super.canEntityDestroy(state, world, pos, entity); + } + + @Deprecated + public void addCollisionBoxToList(IBlockState state, World worldIn, BlockPos pos, AxisAlignedBB entityBox, List collidingBoxes, @Nullable Entity entity, boolean p_185477_7_) { + if (getCanInteract(state, entity)) { + super.addCollisionBoxToList(state, worldIn, pos, entityBox, collidingBoxes, entity, p_185477_7_); + } + } + + @Deprecated + @Override + public float getPlayerRelativeBlockHardness(IBlockState state, EntityPlayer player, World worldIn, BlockPos pos) { + if (CloudType.NORMAL.canInteract(player)) { + return super.getPlayerRelativeBlockHardness(state, player, worldIn, pos); + } + return -1; + } + + + @Override + public CloudType getCloudMaterialType(IBlockState blockState) { + return CloudType.NORMAL; + } + + @Override + protected IBlockState getDirtState(World world, BlockPos pos, IBlockState state) { + return UBlocks.cloud.getDefaultState(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/block/ITillable.java b/src/main/java/com/minelittlepony/unicopia/block/ITillable.java new file mode 100644 index 00000000..57d7750f --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/block/ITillable.java @@ -0,0 +1,24 @@ +package com.minelittlepony.unicopia.block; + +import javax.annotation.Nonnull; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +/** + * Blocks that can be turned into farmland when tilled. + */ +public interface ITillable { + /** + * Gets the farmland/tilled state for this block when attacked by a hoe. + */ + @Nonnull + IBlockState getFarmlandState(ItemStack hoe, EntityPlayer player, World world, IBlockState state, BlockPos pos); + + default boolean canBeTilled(ItemStack hoe, EntityPlayer player, World world, IBlockState state, BlockPos pos) { + return world.isAirBlock(pos.up()); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/block/UFarmland.java b/src/main/java/com/minelittlepony/unicopia/block/UFarmland.java new file mode 100644 index 00000000..16d3cbb0 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/block/UFarmland.java @@ -0,0 +1,127 @@ +package com.minelittlepony.unicopia.block; + +import java.util.Random; + +import com.minelittlepony.util.PosHelper; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockFarmland; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.init.Blocks; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.EnumPlantType; +import net.minecraftforge.common.IPlantable; + +public abstract class UFarmland extends BlockFarmland { + + public UFarmland(String domain, String name) { + setTranslationKey(name); + setRegistryName(domain, name); + } + + @Override + public void updateTick(World world, BlockPos pos, IBlockState state, Random rand) { + int i = state.getValue(MOISTURE); + + if (!hasWater(world, pos) && !world.isRainingAt(pos.up())) { + if (i > 0) { + world.setBlockState(pos, state.withProperty(MOISTURE, i - 1), 2); + } else if (!hasCrops(world, pos)) { + turnToDirt(world, pos, state); + } + } else if (i < 7) { + world.setBlockState(pos, state.withProperty(MOISTURE, 7), 2); + } + } + + @Override + public void onFallenUpon(World world, BlockPos pos, Entity entity, float fallDistance) { + if (shouldTrample(world, pos, entity, fallDistance)) { + turnToDirt(world, pos, world.getBlockState(pos)); + } + + entity.fall(fallDistance, 1); + } + + @Override + public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos fromPos) { + if (shouldTurnToDirt(world, pos, state)) { + turnToDirt(world, pos, state); + } + } + + @Override + public void onBlockAdded(World world, BlockPos pos, IBlockState state) { + if (shouldTurnToDirt(world, pos, state)) { + turnToDirt(world, pos, state); + } + } + + public boolean hasCrops(World worldIn, BlockPos pos) { + Block block = worldIn.getBlockState(pos.up()).getBlock(); + return block instanceof IPlantable + && canSustainPlant(worldIn.getBlockState(pos), worldIn, pos, EnumFacing.UP, (IPlantable)block); + } + + public boolean hasWater(World world, BlockPos pos) { + return PosHelper.inRegion(pos.add(-4, 0, -4), pos.add(4, 1, 4)).anyMatch(p -> { + return world.getBlockState(p).getMaterial() == Material.WATER; + }); + } + + @Override + public boolean canSustainPlant(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing direction, IPlantable plantable) { + return super.canSustainPlant(state, world, pos, direction, plantable) + || plantable.getPlantType(world, pos.offset(direction)) == EnumPlantType.Crop; + } + + /** + * Determines if this farmland should be trampled when an entity walks on it. + */ + public boolean shouldTrample(World world, BlockPos pos, Entity entity, float fallDistance) { + return !world.isRemote && entity.canTrample(world, this, pos, fallDistance); + } + + /** + * Determines if this farmland meets all the conditions for turning into dirt. + */ + public boolean shouldTurnToDirt(World world, BlockPos pos, IBlockState state) { + return world.getBlockState(pos.up()).getMaterial().isSolid(); + } + + /** + * Turns this farmland into dirt or its dirt equivalent. + */ + public void turnToDirt(World world, BlockPos pos, IBlockState state) { + world.setBlockState(pos, getDirtState(world, pos, state)); + + AxisAlignedBB bounds = getUpdateCollissionBounds(world, pos, state); + + if (bounds != null) { + // Update entity positions so they don't fall through the block + for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, bounds)) { + + double offset = Math.min(bounds.maxY - bounds.minY, bounds.maxY - entity.getEntityBoundingBox().minY); + + entity.setPositionAndUpdate(entity.posX, entity.posY + offset + 0.001D, entity.posZ); + } + } + } + + protected AxisAlignedBB getUpdateCollissionBounds(World world, BlockPos pos, IBlockState state) { + return field_194405_c.offset(pos); + } + + /** + * Gets the state used to represent this block as a piece of dirt. + */ + protected IBlockState getDirtState(World world, BlockPos pos, IBlockState state) { + return Blocks.DIRT.getDefaultState(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java new file mode 100644 index 00000000..170e8ef3 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java @@ -0,0 +1,121 @@ +package com.minelittlepony.unicopia.entity; + +import com.minelittlepony.unicopia.item.ITossable; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IProjectile; +import net.minecraft.entity.projectile.EntitySnowball; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +public class EntityProjectile extends EntitySnowball { + + private static final DataParameter ITEM = EntityDataManager + .createKey(EntityProjectile.class, DataSerializers.ITEM_STACK); + private static final DataParameter DAMAGE = EntityDataManager + .createKey(EntityProjectile.class, DataSerializers.FLOAT); + + public EntityProjectile(World world) { + super(world); + } + + public EntityProjectile(World world, double x, double y, double z) { + super(world, x, y, z); + } + + public EntityProjectile(World world, EntityLivingBase thrower) { + super(world, thrower); + } + + @Override + protected void entityInit() { + getDataManager().register(ITEM, ItemStack.EMPTY); + getDataManager().register(DAMAGE, (float)0); + } + + public ItemStack getItem() { + ItemStack stack = getDataManager().get(ITEM); + + return stack == null ? ItemStack.EMPTY : stack; + } + + public void setItem(ItemStack stack) { + getDataManager().set(ITEM, stack); + getDataManager().setDirty(ITEM); + } + + public void setThrowDamage(float damage) { + getDataManager().set(DAMAGE, Math.max(0, damage)); + } + + public float getThrowDamage() { + return getDataManager().get(DAMAGE); + } + + @Override + public void readEntityFromNBT(NBTTagCompound compound) { + super.readEntityFromNBT(compound); + + ItemStack itemstack = new ItemStack(compound.getCompoundTag("Item")); + + if (itemstack.isEmpty()) { + setDead(); + } else { + setItem(itemstack); + } + } + + @Override + public void handleStatusUpdate(byte id) { + if (id == 3) { + ItemStack stack = getItem(); + + for (int i = 0; i < 8; i++) { + world.spawnParticle(EnumParticleTypes.ITEM_CRACK, posX, posY, posZ, 0, 0, 0, Item.getIdFromItem(stack.getItem()), stack.getMetadata()); + } + } + } + + @Override + public void writeEntityToNBT(NBTTagCompound compound) { + super.writeEntityToNBT(compound); + + ItemStack itemstack = this.getItem(); + + if (!itemstack.isEmpty()) { + compound.setTag("Item", itemstack.writeToNBT(new NBTTagCompound())); + } + } + + @Override + protected void onImpact(RayTraceResult result) { + if (result.entityHit != this && !(result.entityHit instanceof IProjectile)) { + if (result.typeOfHit == RayTraceResult.Type.BLOCK) { + Item item = getItem().getItem(); + + if (item instanceof ITossable) { + ((ITossable)item).onImpact(world, result.getBlockPos(), world.getBlockState(result.getBlockPos())); + } + } + + if (result.entityHit != null) { + result.entityHit.attackEntityFrom(DamageSource.causeThrownDamage(this, getThrower()), getThrowDamage()); + } + + + + if (!world.isRemote) { + world.setEntityState(this, (byte)3); + setDead(); + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/ITossable.java b/src/main/java/com/minelittlepony/unicopia/item/ITossable.java new file mode 100644 index 00000000..ad32e5e1 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/ITossable.java @@ -0,0 +1,105 @@ +package com.minelittlepony.unicopia.item; + +import com.minelittlepony.unicopia.entity.EntityProjectile; + +import net.minecraft.block.BlockDispenser; +import net.minecraft.block.state.IBlockState; +import net.minecraft.dispenser.BehaviorDefaultDispenseItem; +import net.minecraft.dispenser.IBehaviorDispenseItem; +import net.minecraft.dispenser.IBlockSource; +import net.minecraft.dispenser.IPosition; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.stats.StatList; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface ITossable { + IBehaviorDispenseItem dispenserBehavior = new ITossable.DispenserBehaviour(); + + boolean canBeThrown(ItemStack stack); + + void onImpact(World world, BlockPos pos, IBlockState state); + + default Item setDispenseable() { + BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject((Item)(Object)this, dispenserBehavior); + + return (Item)(Object)this; + } + + default SoundEvent getThrowSound(ItemStack stack) { + return SoundEvents.ENTITY_SNOWBALL_THROW; + } + + default int getThrowDamage(ItemStack stack) { + return 0; + } + + default void toss(World world, ItemStack itemstack, EntityPlayer player) { + if (!player.capabilities.isCreativeMode) { + itemstack.shrink(1); + } + + world.playSound(null, player.posX, player.posY, player.posZ, getThrowSound(itemstack), SoundCategory.NEUTRAL, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + + if (!world.isRemote) { + EntityProjectile projectile = new EntityProjectile(world, player); + + projectile.setItem(itemstack); + projectile.setThrowDamage(getThrowDamage(itemstack)); + projectile.shoot(player, player.rotationPitch, player.rotationYaw, 0, 1.5F, 1); + + world.spawnEntity(projectile); + } + + player.addStat(StatList.getObjectUseStats(itemstack.getItem())); + } + + default ItemStack toss(World world, IPosition pos, EnumFacing facing, ItemStack stack, float velocity, float inaccuracy) { + EntityProjectile iprojectile = new EntityProjectile(world, pos.getX(), pos.getY(), pos.getZ()); + + iprojectile.setItem(stack); + iprojectile.setThrowDamage(getThrowDamage(stack)); + + iprojectile.shoot(facing.getXOffset(), facing.getYOffset() + 0.1F, facing.getZOffset(), velocity, inaccuracy); + + world.spawnEntity(iprojectile); + + stack.shrink(1); + + return stack; + } + + class DispenserBehaviour extends BehaviorDefaultDispenseItem { + @Override + public ItemStack dispenseStack(IBlockSource source, ItemStack stack) { + ITossable tossable = (ITossable)stack.getItem(); + + if (tossable.canBeThrown(stack)) { + return shootStack(source, stack); + } + + return super.dispenseStack(source, stack); + } + + public ItemStack shootStack(IBlockSource source, ItemStack stack) { + return ((ITossable)stack.getItem()).toss(source.getWorld(), + BlockDispenser.getDispensePosition(source), + (EnumFacing)source.getBlockState().getValue(BlockDispenser.FACING), + stack, getProjectileInaccuracy(), getProjectileVelocity()); + } + + protected float getProjectileInaccuracy() { + return 6.0F; + } + + protected float getProjectileVelocity() { + return 1.1F; + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemApple.java b/src/main/java/com/minelittlepony/unicopia/item/ItemApple.java index c7ad6dcf..f90a9559 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ItemApple.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemApple.java @@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.item; import java.util.Random; -import com.minelittlepony.unicopia.UItems; import com.minelittlepony.util.MagicalDamageSource; import com.minelittlepony.util.vector.VecHelper; @@ -63,20 +62,25 @@ public class ItemApple extends ItemFood { @Override public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { RayTraceResult mop = VecHelper.getObjectMouseOver(player, 5, 0); + if (mop != null && mop.typeOfHit == RayTraceResult.Type.ENTITY) { ItemStack stack = player.getHeldItem(hand); + if (canFeedTo(stack, mop.entityHit)) { return onFedTo(stack, player, mop.entityHit); } } + return super.onItemRightClick(world, player, hand); } @Override protected void onFoodEaten(ItemStack stack, World w, EntityPlayer player) { super.onFoodEaten(stack, w, player); + if (isZapApple(stack)) { player.attackEntityFrom(MagicalDamageSource.create("zap"), 120); + w.addWeatherEffect(new EntityLightningBolt(w, player.posX, player.posY, player.posZ, false)); } } @@ -92,7 +96,11 @@ public class ItemApple extends ItemFood { public ActionResult onFedTo(ItemStack stack, EntityPlayer player, Entity e) { e.onStruckByLightning(new EntityLightningBolt(e.world, e.posX, e.posY, e.posZ, false)); - if (!player.capabilities.isCreativeMode) stack.shrink(1); + + if (!player.capabilities.isCreativeMode) { + stack.shrink(1); + } + return new ActionResult(EnumActionResult.SUCCESS, stack); } @@ -103,7 +111,9 @@ public class ItemApple extends ItemFood { public ItemApple setSubTypes(String... types) { subTypes = types; variants = new String[subTypes.length * 2]; + setTranslationKey(variants[0] = types[0]); + for (int i = 1; i < variants.length; i++) { variants[i] = variants[0] + (i % subTypes.length != 0 ? "_" + subTypes[i % subTypes.length] : ""); } @@ -123,7 +133,7 @@ public class ItemApple extends ItemFood { public void getSubItems(CreativeTabs tab, NonNullList items) { if (isInCreativeTab(tab)) { for (int i = 0; i < subTypes.length; i++) { - items.add(new ItemStack(UItems.apple, 1, i)); + items.add(new ItemStack(this, 1, i)); } } } @@ -131,23 +141,22 @@ public class ItemApple extends ItemFood { @Override public EnumRarity getRarity(ItemStack stack) { int meta = stack.getMetadata(); - if (meta == getZapAppleMetadata()) return EnumRarity.EPIC; - if (meta >= subTypes.length) return EnumRarity.RARE; + + if (meta == getZapAppleMetadata()) { + return EnumRarity.EPIC; + } + + if (meta >= subTypes.length) { + return EnumRarity.RARE; + } + return EnumRarity.COMMON; } - /*public String getItemStackDisplayName(ItemStack stack) { - String result = super.getItemStackDisplayName(stack); - if (stack.getMetadata() >= subTypes.length) { - return ChatColor.ITALIC + result; - } - return result; - }*/ - @Override public String getTranslationKey(ItemStack stack) { - int meta = stack.getMetadata() % subTypes.length; - if (meta < 0) meta = 0; + int meta = Math.max(0, stack.getMetadata() % subTypes.length); + return super.getTranslationKey(stack) + (meta > 0 ? "." + subTypes[meta] : ""); } diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java b/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java new file mode 100644 index 00000000..b63eef11 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java @@ -0,0 +1,91 @@ +package com.minelittlepony.unicopia.item; + +import com.minelittlepony.unicopia.player.PlayerSpeciesList; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemFood; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class ItemTomato extends ItemFood implements ITossable { + + public ItemTomato(String domain, String name, int heal, int sat) { + super(heal, sat, false); + + setTranslationKey(name); + setRegistryName(domain, name); + + setDispenseable(); + } + + @Override + public void getSubItems(CreativeTabs tab, NonNullList items) { + if (isInCreativeTab(tab)) { + items.add(new ItemStack(this, 1, 0)); + items.add(new ItemStack(this, 1, 1)); + } + } + + @Override + public String getTranslationKey(ItemStack stack) { + return super.getTranslationKey(stack) + (canBeThrown(stack) ? ".rotten" : ""); + } + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { + ItemStack itemstack = player.getHeldItem(hand); + + if (canBeThrown(itemstack) && !player.canEat(false)) { + toss(world, itemstack, player); + + return new ActionResult(EnumActionResult.SUCCESS, itemstack); + } + + return super.onItemRightClick(world, player, hand); + } + + public boolean canBeThrown(ItemStack stack) { + return stack.getMetadata() > 0; + } + + protected boolean isSickening(ItemStack stack, EntityPlayer player) { + return canBeThrown(stack) + && !PlayerSpeciesList.instance().getPlayer(player).getPlayerSpecies().canUseEarth(); + } + + @Override + protected void onFoodEaten(ItemStack stack, World worldIn, EntityPlayer player) { + + PotionEffect effect = player.getActivePotionEffect(MobEffects.NAUSEA); + + if (isSickening(stack, player)) { + int duration = 7000; + + if (effect != null) { + duration += Math.max(0, effect.getDuration()); + } + + player.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, duration, 4)); + } else if (effect != null) { + player.removePotionEffect(MobEffects.NAUSEA); + } + + super.onFoodEaten(stack, worldIn, player); + } + + @Override + public void onImpact(World world, BlockPos pos, IBlockState state) { + if (!world.isRemote && state.getMaterial() == Material.GLASS) { + world.destroyBlock(pos, true); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/player/PlayerGravityDelegate.java b/src/main/java/com/minelittlepony/unicopia/player/PlayerGravityDelegate.java index c4cccce3..6dd52685 100644 --- a/src/main/java/com/minelittlepony/unicopia/player/PlayerGravityDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/player/PlayerGravityDelegate.java @@ -60,12 +60,11 @@ class PlayerGravityDelegate implements IUpdatable, IGravity, InbtS entity.fallDistance = 0; - float exhaustion = (0.2F * ticksInAir++) / 90; + float exhaustion = (0.5F * ticksInAir++) / 70; if (entity.isSprinting()) { exhaustion *= 3.11F; } - exhaustion *= (1 - flightExperience/MAXIMUM_FLIGHT_EXPERIENCE); entity.addExhaustion(exhaustion); diff --git a/src/main/java/com/minelittlepony/unicopia/render/RenderProjectile.java b/src/main/java/com/minelittlepony/unicopia/render/RenderProjectile.java new file mode 100644 index 00000000..0ef0a90c --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/render/RenderProjectile.java @@ -0,0 +1,21 @@ +package com.minelittlepony.unicopia.render; + +import com.minelittlepony.unicopia.entity.EntityProjectile; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.entity.RenderSnowball; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +public class RenderProjectile extends RenderSnowball { + + public RenderProjectile(RenderManager renderManager) { + super(renderManager, Items.POTIONITEM, Minecraft.getMinecraft().getRenderItem()); + } + + @Override + public ItemStack getStackToRender(EntityProjectile entity) { + return entity.getItem(); + } +} diff --git a/src/main/java/com/minelittlepony/util/PosHelper.java b/src/main/java/com/minelittlepony/util/PosHelper.java index 2d04ce3e..4bbd81c9 100644 --- a/src/main/java/com/minelittlepony/util/PosHelper.java +++ b/src/main/java/com/minelittlepony/util/PosHelper.java @@ -2,9 +2,13 @@ package com.minelittlepony.util; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Stream; + +import com.google.common.collect.Streams; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockPos.MutableBlockPos; public class PosHelper { @@ -22,4 +26,11 @@ public class PosHelper { } return false; } + + /** + * Creates a stream of mutable block positions ranging from the beginning position to end. + */ + public static Stream inRegion(BlockPos from, BlockPos to) { + return Streams.stream(BlockPos.getAllInBoxMutable(from, to)); + } } diff --git a/src/main/resources/assets/unicopia/blockstates/cloud_farmland.json b/src/main/resources/assets/unicopia/blockstates/cloud_farmland.json new file mode 100644 index 00000000..00a1aa0e --- /dev/null +++ b/src/main/resources/assets/unicopia/blockstates/cloud_farmland.json @@ -0,0 +1,12 @@ +{ + "variants": { + "moisture=0": { "model": "unicopia:farmland/dry" }, + "moisture=1": { "model": "unicopia:farmland/dry" }, + "moisture=2": { "model": "unicopia:farmland/dry" }, + "moisture=3": { "model": "unicopia:farmland/dry" }, + "moisture=4": { "model": "unicopia:farmland/dry" }, + "moisture=5": { "model": "unicopia:farmland/dry" }, + "moisture=6": { "model": "unicopia:farmland/dry" }, + "moisture=7": { "model": "unicopia:farmland/wet" } + } +} diff --git a/src/main/resources/assets/unicopia/lang/en_US.lang b/src/main/resources/assets/unicopia/lang/en_US.lang index 89b3445a..eeb09fc5 100644 --- a/src/main/resources/assets/unicopia/lang/en_US.lang +++ b/src/main/resources/assets/unicopia/lang/en_US.lang @@ -45,6 +45,10 @@ item.apple.rotten.name=Rotten Apple item.apple.zap.name=Zap Apple item.apple.zap_cooked.name=Cooked Zap Apple +item.tomato.name=Tomato +item.tomato.rotten.name=Rotten Tomato +item.tomato.cloud.name=Cloudsdale Tomato + item.alfalfa_leaves.name=Alfalfa item.alfalfa_seeds.name=Grain diff --git a/src/main/resources/assets/unicopia/models/block/farmland/dry.json b/src/main/resources/assets/unicopia/models/block/farmland/dry.json new file mode 100644 index 00000000..bc3335a5 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/block/farmland/dry.json @@ -0,0 +1,8 @@ +{ + "parent": "block/farmland", + "textures": { + "particle": "unicopia:blocks/cloud_normal", + "dirt": "unicopia:blocks/cloud_normal", + "top": "unicopia:blocks/cloud_farmland_dry" + } +} diff --git a/src/main/resources/assets/unicopia/models/block/farmland/wet.json b/src/main/resources/assets/unicopia/models/block/farmland/wet.json new file mode 100644 index 00000000..025ed2f1 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/block/farmland/wet.json @@ -0,0 +1,8 @@ +{ + "parent": "block/farmland", + "textures": { + "particle": "unicopia:blocks/cloud_normal", + "dirt": "unicopia:blocks/cloud_normal", + "top": "unicopia:blocks/cloud_farmland_wet" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/cloudsdale_tomato.json b/src/main/resources/assets/unicopia/models/item/cloudsdale_tomato.json new file mode 100644 index 00000000..cfc42301 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/cloudsdale_tomato.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:items/tomato" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/rotten_cloudsdale_tomato.json b/src/main/resources/assets/unicopia/models/item/rotten_cloudsdale_tomato.json new file mode 100644 index 00000000..83747491 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/rotten_cloudsdale_tomato.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:items/rotten_tomato" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/rotten_tomato.json b/src/main/resources/assets/unicopia/models/item/rotten_tomato.json new file mode 100644 index 00000000..83747491 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/rotten_tomato.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:items/rotten_tomato" + } +} diff --git a/src/main/resources/assets/unicopia/models/item/tomato.json b/src/main/resources/assets/unicopia/models/item/tomato.json new file mode 100644 index 00000000..cfc42301 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/tomato.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:items/tomato" + } +} diff --git a/src/main/resources/assets/unicopia/textures/blocks/cloud_farmland_dry.png b/src/main/resources/assets/unicopia/textures/blocks/cloud_farmland_dry.png new file mode 100644 index 0000000000000000000000000000000000000000..b0ccfd3354d7f1c056750888f4abdf10682a9c52 GIT binary patch literal 3082 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 Y0>eR@P6FP53jhEB07*qoM6N<$f_0hcz5oCK literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/blocks/cloud_farmland_wet.png b/src/main/resources/assets/unicopia/textures/blocks/cloud_farmland_wet.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbad68065744056920c4a66ad0d3f9de13938f7 GIT binary patch literal 3076 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 SbA)UF0000wddsk literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/items/rotten_tomato.png b/src/main/resources/assets/unicopia/textures/items/rotten_tomato.png new file mode 100644 index 0000000000000000000000000000000000000000..07466582ee541054be6a6acee2f737447734d159 GIT binary patch literal 3184 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 JPDHLkV1fmG_#6NL literal 0 HcmV?d00001